__proto__是每个对象都有的一个属性,而prototype是函数才会有的属性。constructor属性本质上只有prototype属性才有
先上图
prototype属性
上面说了,prototype是函数独有的属性。
对应上面的图,就是
function Foo()指向Foo.prototypefunction Object()指向Object.prototypefunction Function()指向Function.prototype
各自对应的prototype就是用来放各自的原型属性和原型方法的,可以用来共享这些属性和方法
Foo.prototype.name = 'zk'
像这样就是原型属性,也可以根据同样的方法来创建原型方法。
我们一般使用的Object.prototype.toString.call()来判断类型,就是使用的Object中的原型方法来判断的。
__proto__属性
__proto__是对象具有的属性,指从一个对象指向此对象的原型对象(类似指向Java中的父类)。
在prototype中的属性和方法(也就是原型属性、原型方法),此构造函数的实例都可以访问和调用。那么这里的原型属性和原型方法是怎么和构造函数的实例联系起来的?就是通过__proto__属性。
现在可以知道,万物继承自Object.protptype
比如:在调用f1.toString()的时候,首先在f1本身找,没有找到再通过f1.__proto__找到Foo.prototype,如果还是没有找到,就通过Foo.prototype.__proto__找到Object.prototype,一直重复操作,直到找到为止;若最后还是没有,就返回undefined
constructor属性
constructor属性是prototype属性才会有的属性
构造函数.prototype.constructor === 该构造函数
总的看来,constructor似乎没起到什么作用,不一定
那constructor的作用是什么?
function Person(area){
this.type = 'person';
this.area = area;
}
Person.prototype.sayArea = function(){
console.log(this.area);
}
let Father = function(age){
this.age = age;
}
Father.prototype = new Person('Beijin');
console.log(Person.prototype.constructor); // function person()
console.log(Father.prototype.constructor); // function person()
Father.prototype.constructor = Father; // 修正
console.log(Father.prototype.constructor); // function father()
如果没有上面修正的那句代码
let temp = new Father(25)
console.log(temp.constructor) // function Person() {}
由Father构建出来的对象temp的构造函数指向是Person,而不是你new它的时候用的构造函数Father。这就导致了原型链的错乱。
在Father.prototype = new Person('Beijin');中,Father的原型指向了一个新对象,这个新对象的constructor指向的是Person,所以才需要那句修正的代码,来保证了原型链的正确。
若有不当之处,欢迎指出