看了网上很多资料,以前对JS原型链可能了解的不够深,这次也是专门加深了理解。
一、proto和prototype的概念
开始先明确两个概念,proto和prototype。proto是对象的内部原型,是浏览器给它的一个属性,不是js赋予的属性。而prototype是构造器的原型,是js赋予的属性。这里举个例子:
1 | function fun(){} |
这里fun()是一个构造函数,也就是一个构造器。通过测试可以发现所有构造器/函数的proto都是指向Function.prototype,是一个空函数。也就是:1
fun.__proto__ === Function.prototype //function Empty(){}
这可以说明fun构造器来自Function原型,也就是Function.prototype。
而theme就是我们构造的一个对象,也就是fun()的一个实体对象。1
theme.__proto__ === fun.prototype //true
由于theme是一个对象而不是构造器,所以theme.prototype返回的是undefined。
我们还发现:1
Function.prototype === Object.__proto__ //true
说明所有的构造器都是对象,并且构造器都来自Function原型。普通对象没有prototype,只有proto属性。
二、JS构建对象和原型链
对象中包含一系列属性,这些属性是无序的,每个属性都有一个特定字符串的key和value。如:1
2
3var obj = {x:1,y:2}
obj.x; //1
obj.y; //2
作为key时,无论是数字还是对象,JS都会将它转换为字符串。
下面我们用原型链的方法创建一个对象:1
2
3
4
5
6
7
8
9
10
11
12function foo(){}
foo.prototype.z = 3;
var obj = new foo();
obj.x = 1;
obj.y = 2;
obj.x; //1
obj.y; //2
obj.z; //3
typeof obj.toString; //’function’
'z' in obj; //true
Obj.hasOwnPrototype(‘z’); //false
我们用typeof obj.toString来判断对象的类型,用’z’ in obj来判断obj中是否有z,用hasOwnPrototype来判断z是不是这个对象本身的一员。那我们可以发现obj中有z属性但是z不是对象本身的属性而是从原型链上继承的。
我们开始测试:1
2
3obj.__proto__ === foo.prototype //true
foo.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null //true
说明obj的proto指向foo构造器的prototype。,foo.prototype的proto指向了Object的prototype,最终Object.prototype.proto指向了null。这就是一条原型链,如下图。
为了能更升入地理解proto在原型链中发挥的作用,我们再举一个例子:
1 | var school = function(){}; |
我们可以看到student的proto指向classroom的prototype,所以student得proto指向school,所以student可以从原型链向上寻school中size的值。而classroom的prototype指向school并没有对它向上的原型链起效,所以我们可以得出一个结论:原型链形成的纽带是proto。
接下来谈谈原型链的作用。我认为原型链最重要的作用还是实现了JS中的继承,至于其他的节省内存等感觉倒是可有可无。