JavaScript原型之路

2018-06-16 20:25 更新

簡介

最近我在學(xué)習(xí)Frontend Masters 上的高級JavaScript系列教程,Kyle 帶來了他的“OLOO”(對象鏈接其他對象)概念。這讓我想起了Keith Peters 幾年前發(fā)表的一篇博文,關(guān)于學(xué)習(xí)沒有“new”的世界,其中解釋了使用原型繼承代替構(gòu)造函數(shù)。兩者都是純粹的原型編碼。

標(biāo)準(zhǔn)方法(The Standard Way)

一直以來,我們學(xué)習(xí)的在 JavaScript 里創(chuàng)建對象的方法都是創(chuàng)建一個(gè)構(gòu)造函數(shù),然后為函數(shù)的原型對象添加方法。

function Animal(name) {
  this.name = name;
}
Animal.prototype.getName = function() {
  return this.name;
};

對于子類的解決方案是,創(chuàng)建一個(gè)新的構(gòu)造函數(shù),并且設(shè)置其原型為其父類的原型。調(diào)用父類的構(gòu)造函數(shù),并將this設(shè)置為其上下文對象。

function Dog(name) {
  Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.speak = function() {
  return "woof";
};

var dog = new Dog("Scamp");
console.log(dog.getName() + ' says ' + dog.speak());

原型方法(The Prototypal Way)

如果你接觸過任何原型語言,你會(huì)覺得上面的例子看起來很奇怪。我嘗試過 IO 語言——一門基于原型的語言。在原型語言中,可以通過克隆對象并添加屬性和方法的方式創(chuàng)建一個(gè)原型。然后你能克隆剛才創(chuàng)建的原型,從而創(chuàng)建一個(gè)可以使用的實(shí)例,或者克隆它來創(chuàng)建另一個(gè)原型。上面的例子在 IO 里,看起來像下面這樣:

Animal := Object clone
Animal getName := method(name)

Dog := Animal clone
Dog speak := method("woof")

dog := Dog clone
dog name := "Scamp"
writeln(dog getName(), " says ", dog speak())

好消息(The Good News)

在JavaScript中,也可以使用這種編碼方式!Object.create 函數(shù)和 IO 里的 clone 類似。下面是在JavaScript中,純原型的實(shí)現(xiàn)。除了語法不同之外,和 IO 版本一樣。

Animal = Object.create(Object);
Animal.getName = function() {
  return this.name;
};

Dog = Object.create(Animal);
Dog.speak = function() {
  return "woof";
};

var dog = Object.create(Dog);
dog.name = "Scamp";
console.log(dog.getName() + ' says ' + dog.speak());

壞消息(The Bad News)

當(dāng)使用構(gòu)造函數(shù)時(shí),JavaScript 引擎會(huì)進(jìn)行優(yōu)化。在 JSPerf 上測試兩個(gè)不同的操作,顯示基于原型的實(shí)現(xiàn)比使用構(gòu)造函數(shù)的方式最多慢90多倍。

另外,如果你使用類似 Angular 的框架,當(dāng)創(chuàng)建控制器和服務(wù)時(shí),必須使用構(gòu)造函數(shù)。

引入類(Enter Classes)

ES6帶來了新的 class 語法。但其只是標(biāo)準(zhǔn)構(gòu)造函數(shù)方法的語法糖。新的語法看起來更像 Java 或 c#,但其幕后仍然是創(chuàng)建原型對象。這會(huì)讓來自基于類語言的人感到迷惑,因?yàn)楫?dāng)創(chuàng)建原型時(shí),他們希望類和他們的語言有相同的屬性。

class Animal {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name);
  }
  speak() {
    return "woof";
  }
}

var dog = new Dog("Scamp");
console.log(dog.getName() + ' says ' + dog.speak());

結(jié)論(Conclusion)

如果讓我選擇,我會(huì)用純原型的風(fēng)格。這更具有表現(xiàn)力,動(dòng)態(tài)和有趣。由于虛擬機(jī)會(huì)對構(gòu)造函數(shù)方法進(jìn)行優(yōu)化,所有框架都會(huì)選擇構(gòu)造函數(shù)方法,在產(chǎn)品代碼中,我會(huì)繼續(xù)使用構(gòu)造函數(shù)。一旦 ES6 變得流行,我希望使用新的類語法代替古老的構(gòu)造函數(shù)方法。

英文:http://jurberg.github.io/blog/2014/07/12/javascript-prototype/

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號