【翻译】javascript-prototype

原文地址:http://dailyjs.com/2012/05/20/js101-prototype/

在花费了很多年研究面向对象编程之后,想在javascript使用是令人失望的。主要是从根源上缺少一个class这样的关键词。然而,javascript的设计不会成为阻碍 – 精通它基于原型的继承,将会加深你对该语言的理解。

首先我们需要弄清楚面向对象与面向类编程的区别。Javascript提供了我们需要的工具来完成大多数语言的类可以做的事情 – 我们只需要学习如何正确使用它。

我们简单的看一下prototype属性,看它如何深化我们对javascript的了解。

prototype属性(The prototype Property)

prototype属性是一个内部属性,它被用于实现继承。我们这里的“继承”是一种特定的继承形式。因为状态和方法都由对象承载,所以我们可以说结构、行为和状态都是继承的。这与基于类的语言形成对比,其状态由实例承载,而方法由类承载。

构造函数就是一个具有属性的方法,该属性被称作prototype:

1
2
3
4
function Animal() {
}
console.log(Animal.protype);

{}标识Animal具有一个prototype属性,但是没有用户定义它。我们可以随意添加值和方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Animal() {
}
Animal.prototype.type = 'Unknown';
Animal.prototype.weight = 0;
Animal.prototype.weightUnits = 'kg';
Animal.prototype.toString = function() {
return this.type + ', ' + this.weight + this.weightUnits;
};
var molly = new Animal();
molly.type = 'Dog';
molly.weight = 28;
console.log(molly.toString()); // Dog, 28kg

这将会输出”Dog, 28kg”。我们可以使用对象字面量将这些赋值分组:

1
2
3
4
5
6
7
8
9
10
11
12
function Animal() {
}
Animal.prototype = {
type: 'Unknown',
weight: 0,
weightUnits: 'kg',
toString: function() {
return this.type + ', ' + this.weight + this.weightUnits;
}
};

这样就和你熟悉的类的方式差异不是很大。

动态原型(Dynamic Prototypes)

通过指定值可以给对象动态的添加属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var molly = new Animal()
, harley = new Animal();
molly.type = 'Dog';
molly.weight = 28;
harley.type = 'Dog';
harley.weight = 38;
harley.name = 'Harley';
console.log(molly);
console.log(harley);
// { type: 'Dog', weight: 28 }
// { type: 'Dog', weight: 38, name: 'Harley' }

在这里添加name属性只影响了实例。然而,构造函数的属性可以被改变,并且将影响用这个原型创建的对象。

1
2
3
4
Animal.prototype.weightUnits = 'oz';
console.log(molly.toString())
// Now displays 'Dog, 28oz'

这就是为什么人们只会扩展自己的库而不去改变内置原型,或者说只有这么做才是安全的。我们完全有可能改变对象,例如使用String的内置方法做一些不安全的事情:

1
2
3
4
5
String.prototype.match = function() {
return true;
};
console.log('alex'.match(/1234/));

输出为true,所以现在我成功的破坏了很多程序都在依赖的基础方法。
改变内置原型也不一定全部是坏的;我们使用它有用的东西,如修补支持更旧版本的ECMAScript在旧版的浏览器。

如果我们替换prototype属性会发生什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var molly = new Animal()
, harley;
molly.type = 'Dog';
molly.weight = 28;
Animal.prototype = {
toString: function() {
return '...';
}
};
harley = new Animal;
harley.type = 'Dog';
harley.weight = 38;
console.log(molly.toString());
console.log(harley.toString());
// Dog, 28kg
// ...

尽管事实上改变原型会影响所有实例,但是完全替换构造函数的原型不会影响旧实例。为什么?实例具有对原型的引用,而不是离散拷贝。想象它就是这样:使用new关键字创建的每个实例都链接到原始原型。

杨芳<br>前端一枚<br>背包客,热爱旅行,喜欢摄影<br>轻微洁癖,强迫症,电话恐惧症患者!