文章目录
这是原型图:
构造函数,原型,原型链
- 首页我们来定义一个构造函数如下:
function fn() {}
console.dir(fn);
输出后发现,构造函数里面具有 prototype 这个属性,并且构造函数可以通过 prototype 这个属性找到构造函数 fn 的原型对象。fn 的原型对象里面有一个 constructor 的属性,这个属性可以指回构造函数本身。
- 然后我们把构造函数实例化变成一个实例对象
let f = new fn();
console.dir(f);
输出之后发现只有__proto__的属性,而且原型里面也有一个 constructor 的属性指向构造函数本身。由此得出实例对象的__proto__等于构造函数 fn原型对象 prototype
console.log(f.__proto__ == fn.prototype);
- 现在输出构造函数 fn
console.dir(fn);
由图可见构造函数的原型对象的__proto__指向为大 Object 的原型对象,并且他与大 Object 构造函数的原型一样,如下证实:
console.log(fn.prototype.__proto__ == Object.prototype);
打印结果为 true。
-
既然是大 Object 的原型对象,他就可以通过 constructor 指向大 Object 的构造函数,同时大 Object 也可以通过 prototype 指向大 Object 的原型对象。
-
然后我们输出构造函数 fn 的原型对象的** proto **原型输出如下:
console.dir(fn.prototype.__proto__);
- 可见里面已经没有__proto__这个属性了,所以输出如下最终结果为 null
console.dir(fn.prototype.__proto__.__proto__);
同理大 Object 的__proto__也为 null
js原型链查找规则
-
当访问一个对象的属性或者方法的时候,首先查找这个对象自身是否有这个属性。
function fn() {} let f = new fn(); f.name = '张三'; console.log(f.name);// log:张三
-
如果没有这个属性就查找他的原型对象prototype。
function fn() {} fn.prototype.name = '张三'; let f = new fn(); console.log(f.name);// log:张三
-
如果还没有这个属性,就会查找大Object的原型对象。
function fn() {} Object.prototype.name = '张三'; let f = new fn(); console.log(f.name);// log:张三
-
如果还没查找到,原型链的最后就会返回null。
function fn() {} let f = new fn(); console.log(f.name); //因为返回的结果是null,所以查找f下面的name为undefined //等同于下面的写法 let f2 = {}; console.log(f2.name);//f2已经声明了,但是没有赋值,返回undefined
-
如果原型prototype与对象自身都具有这个属性,则输出对象自身的属性(采取就近原则)。
function fn() {} Object.prototype.name = '李四'; let f = new fn(); f.name = '张三'; console.log(f.name);// log:张三
__ proto __的意义就是为对象查找机制提供一个路线。
原型链中的this指向:
1.在构造函数中,this指向对象实例,就是实例化后的对象。
2.原型对象函数里的this指向
一句话总结:谁掉用这个构造函数,this就指向谁。