原文地址:https://blog.csdn.net/god_wen/article/details/78996302
这两天想看看 jquery的源代码。可是一开始就懵逼了。什么是js的原型链呢?于是在网上寻找答案,发现还挺多的。于是就来这里总结一番。
想弄清原型链其实就是弄清楚__proto__和prototype的关系。
任何对象都有一个__proto__属性
任何方法都有一个prototype属性,prototype也是一个对象 ,所以其中也有一个___proto__
我们先来看prototype属性
var fn=function(){
};
console.log(fn.prototype);
可以看见prototype中有两个属性constructor和__proto__。constructor指向函数自己。同时可以看见prototype中也有__proto__。因为prototype也是一个对象。
prototype是拿来干什么的呢。它的作用很像java中的静态属性/方法。其中的对象可以给所有实例使用,如
var fn =function (){
};
fn.prototype.name='wen';
fn.prototype.age='18';
var obj1=new fn();
var obj2=new fn();
console.log(obj1.name);
console.log(obj2.age);
输出
wen
18
那么__proto__是什么呢?像要弄清这点我们想要知道js中创建对象的一些细节。js创建对象我们有如下三种方法
1 通过构造函数创建对象
var obj=new Object();
- 2通过Object.create创建对象
var obj1={};
var obj2= Object.create(obj1);
3 通过花括号创建,如
var obj={};
- 其实上述三种方法都是通过构造函数创建的。而第三种其实调用的时Object()方法创建的。所以我们可以怎么认为
js中的对象都是new +构造函数创建的。而这个构造函数就是我们定义的函数。
而所有的对象中都有__proto__属性,这个属性就是一个指针,指向构造函数中的prototype属性。
我们可以做一个简单的验证
var obj1={};
console.log(obj1.__proto__===Object.prototype);
- //输出
true
- 通过上面的分析,我们知道js中声明的方法其实就是一个类,它的构造函数就是自己。我们可以向其中的prototype塞入各种对象。这些对象会被所有实例继承。而所有的实例都有一个proto指针指向着构造函数的prototype属性。
tips:
遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject的原型。从 ECMAScript 6 开始,[[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__。
————————————-分割线—————————————————-
下面是深入的分析。
非函数对象的创建
非函数对象只有__proto__,它指向构造函数的prototype属性。我们知道prototype的属性中也有__proto__。那么该__proto__指向谁呢。回忆下一我之前说的所有对象的__proto__指向创建它们的构造函数的prototype。那么谁创建的prototype的呢?。那当然是Object构造函数了。
所以函数中的prototype属性中的__proto__指向的是Object构造函数的prototype属性。但是问题又来了,这个prototype中也有__proto__,这不死循环了。很高兴的告诉你这个prototype中__proto__等于null的。所以不会死循环的,除非你把它改了。
如下图
图片是我之前存下来的,忘了出自哪里了。如果侵害了别人的别人的著作。希望告诉我,我会主动下架的。
我们来验证一下
var obj1={};
console.log(obj1.__proto__.__proto__===null);
//输出
true
- 好我们接着思考
函数对象的创建
函数对象有prototype和__proto__属性。prototype中的__proto__指向的是Object构造函数,这就不用多说了。我们来看__proto__。
函数对象的__proto__指向构造函数的prototype。而函数的构造函数是Function构造函数。接着
Function的prototype中的__proto__指向谁呢?前面已经说了指向Object构造函数。那么Function函数的__proto__指向谁呢。答案是指向自己,因为Function函数也是一个函数。来给大家上一张神图。
接着我们拿出点佐证出来。
var fn =function (){
};
//fn.prototype.__proto__->Object.prototype
//Object.prototype.__proto__===null?
console.log(fn.prototype.__proto__.__proto__===null);
//fn.__proto__->Function.prototype
//Function.prototype.__proto__->Object.prototype
//Object.prototype.__proto__===null
console.log(fn.__proto__.__proto__.__proto__===null);
从上图你可以看见其实Object构造函数的__proto__
也是指向Function构造函数的。
总结
通过上面的分析,我们可以发现js代码的设计是非常巧妙的。
总结一下,当你需要理清js中的__proto__和prototype的链接顺序,你只需记住。
1函数对象有__proto__和prototype属性
2非函数对象只有__proto__属性
3prototype中有__proto__属性。且是Object构造函数创建的
4函数对象__proto__指向它的创建者及Function构造函数
5Function构造函数__proto__指向它自己
6Object对象的prototype中的__proto__是null