最近我在學習Frontend Masters 上的高級JavaScript系列教程,Kyle 帶來了他的「OLOO」(對象連接其餘對象)概念。這讓我想起了Keith Peters 幾年前發表的一篇博文,關於學習沒有「new」的世界,其中解釋了使用原型繼承代替構造函數。二者都是純粹的原型編碼。javascript
一直以來,咱們學習的在 JavaScript 裏建立對象的方法都是建立一個構造函數,而後爲函數的原型對象添加方法。html
function Animal(name) { this.name = name; } Animal.prototype.getName = function() { return this.name; };
對於子類的解決方案是,建立一個新的構造函數,而且設置其原型爲其父類的原型。調用父類的構造函數,並將this設置爲其上下文對象。html5
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 語言——一門基於原型的語言。在原型語言中,能夠經過克隆對象並添加屬性和方法的方式建立一個原型。而後你能克隆剛纔建立的原型,從而建立一個可使用的實例,或者克隆它來建立另外一個原型。上面的例子在 IO 裏,看起來像下面這樣:java
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 函數和 IO 裏的 clone 相似。下面是在JavaScript中,純原型的實現。除了語法不一樣以外,和 IO 版本同樣。git
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());
當使用構造函數時,JavaScript 引擎會進行優化。在 JSPerf 上測試兩個不一樣的操做,顯示基於原型的實現比使用構造函數的方式最多慢90多倍。angularjs
另外,若是你使用相似 Angular 的框架,當建立控制器和服務時,必須使用構造函數。github
ES6帶來了新的 class 語法。但其只是標準構造函數方法的語法糖。新的語法看起來更像 Java 或 c#,但其幕後仍然是建立原型對象。這會讓來自基於類語言的人感到迷惑,由於當建立原型時,他們但願類和他們的語言有相同的屬性。c#
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());
若是讓我選擇,我會用純原型的風格。這更具備表現力,動態和有趣。因爲虛擬機會對構造函數方法進行優化,全部框架都會選擇構造函數方法,在產品代碼中,我會繼續使用構造函數。一旦 ES6 變得流行,我但願使用新的類語法代替古老的構造函數方法。框架
原文:http://yanhaijing.com/javascript/2014/07/18/javascript-prototypefrontend
英文:http://jurberg.github.io/blog/2014/07/12/javascript-prototype/