【Javascript】ES5原型链中prototype、__proto__和 [[Prototype]]

以下面这段代码为例,分析ES5原型链中的一些问题

var A = function(name) {
  this.name=name
};
A.prototype.n = 1;
var b = new A("tom");
A.prototype = {
  n: 2,
  m: 3
}//把A的原型对象用一个object覆盖(即function Object()的实例对象)

// b.__proto__ = A.prototype//修改b的原型
// A.prototype.constructor=A
console.log(b.__proto__.constructor==A);   //true
console.log(A.prototype); //{n:2,m:3}
console.log(b.n); //1
console.log(b.m); //undefined
console.log(b.__proto__) //A{n:1,constructor:f}  此时f是A,但A的prototype已经改变
console.log(b.__proto__.__proto__.__proto__);   //null 
//[[Prototype]]和__proto__不一样
//JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过 __proto__ 来访问
//其实[[prototype]]和__proto__意义相同,均表示对象的内部属性,其值指向对象原型。前者在一些书籍、规范中表示一个对象的原型属性,后者则是在浏览器实现中指向对象原型。
console.log(b);  // A {name: 'tom'}

var c = new A("jack");

// console.log(b.n);//1

console.log(c.__proto__.constructor==Object) //true
console.log(c.n);//2
console.log(c.m);//3
console.log(c.__proto__)
console.log(c.__proto__.__proto__.__proto__); //null
console.log(c);   //A {name: 'jack'}
A.prototype.constructor=A
console.log(c.__proto__.constructor==A) //true
  1. A.prototype = { n: 2, m: 3}A的原型对象用一个普通函数替代,以至于其中的constructor属性丢失,即构造器丢失
  2. 由于b是在重置原型对象之前实例化的,所以b中的构造器并没有丢失,并且b的原型对象还是被覆盖之前的原型对象{n:1,constructor:f}
  3. 而c是在重置原型对象之后实例化的,所以c中的原型函数为一个普通对象{n:2,m:3}(相当于由function Object()实例化之后的对象),该原型函数没有构造器constructor(即构造器丢失),所以会顺着原型链向上查找constructor,找到Object.prototypeconstructor,该构造器指向Object
  4. b.__proto__.__proto__.__proto__=null
    查找路径为:A.prototype->Object.prototype->null
  5. c.__proto__.__proto__.__proto__=null
    查找路径为:new Object(普通对象)->Object.prototype->null
  6. A.prototype.constructor=A 将重置后的A的原型对象重新指回A本身,所以c.__proto__.constructor==Atrue
  7. 若是b.__proto__ = A.prototype,则相当于bc有一样的原型对象了

prototype、__proto__和 [[Prototype]]

  1. __proto__是每个对象都具有的属性,prototype是函数独有的属性
  2. JS中一个构造函数默认带一个prototype属性
  3. prototype指向构造函数的原型对象
  4. 实例中的__proto__属性,也指向构造函数的原型对象(实例化之前的原型对象)
  5. b.__proto__=A.prototype(实例化之前的,若是实例化b之后,又重置了A的prototype,则该等式不成立)
  6. JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过 __proto__ 来访问。其实[[prototype]]__proto__意义相同,均表示对象的内部属性,其值指向对象原型。前者在一些书籍、规范中表示一个对象的原型属性,后者则是在浏览器实现中指向对象原型。但在chrome中打印出实例对象,会发现不管实例还是构造函数都有[[prototype]]属性,可见[[prototype]]并不是等同于__proto__

版权声明:本文为qq_44870156原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。