原型与原型链

当谈到继承时,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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

function DOG(name){
this.name = name;

}

DOG.prototype = { species : '犬科' };


var dogA = new DOG('大毛');

var dogB = new DOG('二毛');


alert(dogA.species); // 犬科

alert(dogB.species); // 犬科

现在,species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响到两个实例对象。

1
2
3
4
5
6
7

DOG.prototype.species = '猫科';


alert(dogA.species); // 猫科

alert(dogB.species); // 猫科

笔记

1.每个对象都具有一个名为__proto__的属性;

2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);

3.每个对象的__proto__属性指向自身构造函数的prototype;


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
30
31
32
33
34
35
36
37
38
39
function Fun(){}
// 我创造了一个函数Fn
// 这个函数由Function生成(Function作为构造函数)


var fn=new Fun()
// 我创建了一个函数fn
// 这个函数由Fn生成(Fn作为构造函数)


console.log(fn.__proto__ === Fun.prototype) //true
// fn的__proto__指向其构造函数Fun的prototype


console.log(Fun.__proto__ === Function.prototype) //true
// Fun的__proto__指向其构造函数Function的prototype


console.log(Function.__proto__ === Function.prototype) //true
// Function的__proto__指向其构造函数Function的prototype
// 构造函数自身是一个函数,他是被自身构造的


console.log(Function.prototype.__proto__ === Object.prototype) //true
// Function.prototype的__proto__指向其构造函数Object的prototype
// Function.prototype是一个对象,同样是一个方法,方法是函数,所以它必须有自己的构造函数也就是Object


console.log(Fun.prototype.__proto__ === Object.prototype) //true
// 与上条相同
// 此处可以知道一点,所有构造函数的的prototype方法的__都指向__Object.prototype(除了....Object.prototype自身)


console.log(Object.__proto__ === Function.prototype) //true
// Object作为一个构造函数(是一个函数对象!!函数对象!!),所以他的__proto__指向Function.prototype


console.log(Object.prototype.__proto__ === null) //true
// Object.prototype作为一切的源头,他的__proto__是null

下面是一个新的,额外的例子

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
30
var 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

感谢您的阅读。 🙏 关于转载请看这里