当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 __proto__ )指向它的原型对象( prototype )。该原型对象也有一个自己的原型对象( __proto__ ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
举例来说,现在有一个叫做DOG的构造函数,表示狗对象的原型。1
2
3
4
5
6
function DOG(name){
this.name = name;
}
对这个构造函数使用new,就会生成一个狗对象的实例。1
2
3
4
var dogA = new DOG('大毛');
alert(dogA.name); // 大毛
用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。
考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。
这个属性包含一个对象(以下简称”prototype对象”),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。
1 |
|
现在,species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响到两个实例对象。
1 |
|
笔记
1.每个对象都具有一个名为__proto__的属性;
2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);
3.每个对象的__proto__属性指向自身构造函数的prototype;
1 | function Fun(){} |
下面是一个新的,额外的例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30var obj={}
// 创建了一个obj
console.log(obj.__proto__ === Object.prototype) //true
// obj作为一个直接以字面量创建的对象,所以obj__proto__直接指向了Object.prototype,而不需要经过Function了!!
// 下面是根据原型链延伸的内容
// 还有一个上文并未提到的constructor, constructor在原型链中,是作为对象prototypr的一个属性存在的,它指向构造函数(由于主要讲原型链,这个就没在意、);
console.log(obj.__proto__.__proto__ === null) //true
console.log(obj.__proto__.constructor === Object) //true
console.log(obj.__proto__.constructor.__proto__ === Function.prototype) //true
console.log(obj.__proto__.constructor.__proto__.__proto__ === Object.prototype) //true
console.log(obj.__proto__.constructor.__proto__.__proto__.__proto__ === null) //true
console.log(obj.__proto__.constructor.__proto__.__proto__.constructor.__proto__ === Function.prototype) //true
// 以上,有兴趣的可以一一验证 F12搞起.
节选自
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://www.cnblogs.com/az96/p/6014621.html