最近我在學習Frontend Masters 上的高級JavaScript系列教程,Kyle 帶來了他的“OLOO”(對象鏈接其他對象)概念。這讓我想起了Keith Peters 幾年前發(fā)表的一篇博文,關(guān)于學習沒有“new”的世界,其中解釋了使用原型繼承代替構(gòu)造函數(shù)。兩者都是純粹的原型編碼。
一直以來,我們學習的在 JavaScript 里創(chuàng)建對象的方法都是創(chuàng)建一個構(gòu)造函數(shù),然后為函數(shù)的原型對象添加方法。
function Animal(name) {
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
};
對于子類的解決方案是,創(chuàng)建一個新的構(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());
如果你接觸過任何原型語言,你會覺得上面的例子看起來很奇怪。我嘗試過 IO 語言——一門基于原型的語言。在原型語言中,可以通過克隆對象并添加屬性和方法的方式創(chuàng)建一個原型。然后你能克隆剛才創(chuàng)建的原型,從而創(chuàng)建一個可以使用的實例,或者克隆它來創(chuàng)建另一個原型。上面的例子在 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())
在JavaScript中,也可以使用這種編碼方式!Object.create 函數(shù)和 IO 里的 clone 類似。下面是在JavaScript中,純原型的實現(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());
當使用構(gòu)造函數(shù)時,JavaScript 引擎會進行優(yōu)化。在 JSPerf 上測試兩個不同的操作,顯示基于原型的實現(xiàn)比使用構(gòu)造函數(shù)的方式最多慢90多倍。
另外,如果你使用類似 Angular 的框架,當創(chuàng)建控制器和服務(wù)時,必須使用構(gòu)造函數(shù)。
ES6帶來了新的 class 語法。但其只是標準構(gòu)造函數(shù)方法的語法糖。新的語法看起來更像 Java 或 c#,但其幕后仍然是創(chuàng)建原型對象。這會讓來自基于類語言的人感到迷惑,因為當創(chuàng)建原型時,他們希望類和他們的語言有相同的屬性。
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());
如果讓我選擇,我會用純原型的風格。這更具有表現(xiàn)力,動態(tài)和有趣。由于虛擬機會對構(gòu)造函數(shù)方法進行優(yōu)化,所有框架都會選擇構(gòu)造函數(shù)方法,在產(chǎn)品代碼中,我會繼續(xù)使用構(gòu)造函數(shù)。一旦 ES6 變得流行,我希望使用新的類語法代替古老的構(gòu)造函數(shù)方法。
英文:http://jurberg.github.io/blog/2014/07/12/javascript-prototype/
更多建議: