JavaScript原型之路

简介

最近我在学习Frontend Masters 上的高级JavaScript系列教程,Kyle 带来了他的“OLOO”(对象连接其余对象)概念。这让我想起了Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。二者都是纯粹的原型编码。javascript

标准方法(The Standard Way)

一直以来,咱们学习的在 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());

 

原型方法(The Prototypal Way)

若是你接触过任何原型语言,你会以为上面的例子看起来很奇怪。我尝试过 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())

 

好消息(The Good News)

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

 

 

坏消息(The Bad News)

当使用构造函数时,JavaScript 引擎会进行优化。在 JSPerf 上测试两个不一样的操做,显示基于原型的实现比使用构造函数的方式最多慢90多倍。angularjs

Perf Graph

另外,若是你使用相似 Angular 的框架,当建立控制器和服务时,必须使用构造函数。github

引入类(Enter Classes)

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

 

结论(Conclusion)

若是让我选择,我会用纯原型的风格。这更具备表现力,动态和有趣。因为虚拟机会对构造函数方法进行优化,全部框架都会选择构造函数方法,在产品代码中,我会继续使用构造函数。一旦 ES6 变得流行,我但愿使用新的类语法代替古老的构造函数方法。框架

原文:http://yanhaijing.com/javascript/2014/07/18/javascript-prototypefrontend

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

相关文章
相关标签/搜索