JS之原型和原型链
__proto__
是每个对象都有的一个属性,而prototype
是函数才会有的属性。constructor
属性本质上只有prototype
属性才有
先上图
prototype属性
上面说了,prototype
是函数独有的属性。
对应上面的图,就是
function Foo()
指向Foo.prototype
function Object()
指向Object.prototype
function 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
,所以才需要那句修正的代码,来保证了原型链的正确。
若有不当之处,欢迎指出