JavaScript原型之路

2018-06-16 20:25 更新

簡介

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

標準方法(The Standard Way)

一直以來,我們學習的在 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());

原型方法(The Prototypal Way)

如果你接觸過任何原型語言,你會覺得上面的例子看起來很奇怪。我嘗試過 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())

好消息(The Good News)

在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());

壞消息(The Bad News)

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

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

引入類(Enter Classes)

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());

結(jié)論(Conclusion)

如果讓我選擇,我會用純原型的風格。這更具有表現(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/

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號