在JavaScript 中,prototype constructor __proto__三者之间的关系困扰了很多人,
接下来就理理他们之间剪不断理还乱的关系
简单理解,某个对象的constructor属性返回该对象构造函数,其__proto__属性是个对象,值和其构造函数的prototype属性值一致, prototype理解是原型
prototype 是“原型”, js的所有函数都有一个prototype属性 ,其属性值是个对象 ,prototype对象中包含构造函数定义的属性和方法,通过该构造函数创建的实例对象都有构造函数提供的属性和方法
var Cat = function(){
this.like = '爱吃鱼',
this.hobby = '爱睡觉'
}
var lucky = new Cat();
console.log(lucky);
var xiaohei = new Cat();
console.log(xiaohei);
lucky 和 xiaohei 都是通过Cat 构造函数创建的,他们都继承里Cat 的属性 hobby ,like(可以理解为他们都继承了猫的特性,爱吃鱼,也爱睡觉,当然继承的对象属性是可以修改的)
prorotype的主要作用简单来说就是“便于方法或者属性的重用”,可以利用prototype添加扩展属性和方法,
Cat.ptototype.show = function(){
console.log(this.hobby);
}
Cat.prototype.color = 'orangle'
var c = new Cat();
a.show(); //爱睡觉
console.log(c.__proto__ === Cat.prototype); // true 对象c的__proto__值取自构造函数Cat的prototype值 console.log(c.constructor === Cat); // true 对象c的构造函数是Cat console.log(Cat.prototype.constructor === Cat); // true
我们通过c.show()调用了show方法,但是show方法并不显示在对象本身属性里(可通过hasOwnProperty验证),为何能用?又是__proto__!所有的实例对象都有个__proto__属性,我们看到它的值跟Cat.prototype一致,也就是说实例c继承了Cat类的属性方法。本身的属性里找不到show方法,自动去__proto__中寻找。
我们的 c.constructor返回的是c的构造函数,也就是Cat,其实实例对象c本身并没有constructor属性,但是c中的__proto__拥有constructor属性,没错,c本身没有,就会从它的__proto__属性中寻找constructor方法,如果还没有,就继续从__proto__属性的__proto__属性中寻找... 这样就构成了一个原型链。
其实new方式的核心实现要分为三个步骤
var c = {}; //1
c.__proto__ = Cat.prototype; //2
Cat.call(c); //3
return c; //4
第2步: 将新生成的对象的__prop__属性赋值为构造函数的prototype属性,使得通过构造函数创建的所有对象可以共享相同的原型。这意味着同一个构造函数创建的所有 对象都继承自一个相同的对象,因此它们都是同一个类的对象。
小贴士:在JavaScript标准中,并没有__prop__这个属性,不过它现在已经是一些主流的 JavaScript执行环境默认的一个标准属性,用于指向构造函数的原型。该属性是 默认不可见的,而且在各执行环境中实现的细节不尽相同,例如IE浏览器中不存在该属性。我们只要知道JavaScript对象内部存在指向构造函数原型的指针就可 以了,这个指针是在调用new表达式的时候自动赋值的,并且我们不应该去修改 它。
第3步:将构造函数的作用域赋给新对象,因此Cat函数中的this指向新对象c,然后再调用show函数。于是我们就给c对象赋值了成员变量like,hobby。
第4步:返回新对象obj。
最后总结
javascript中每个对象除了本身的属性外,还有一个__proto__属性,继承了父对象的方法和属性(形成原型链);而每个函数有个prototype属性,该属性值是个对象,该对象函数自定义的一些属性方法外,还有两个属性,constructor(其值一般为函数本身)和__proto__(其值继承自父对象)。