总结
(1) 原型有显式原型和隐式原型,函数有显式原型prototype,对象有隐式原型[[prototype]]和__proto__。
(2) 对象的隐式原型指向函数的显示原型,这种链式结构成为原型链。
(3) 原型链的最后一层是Object的原型,再后面就是null了。
(4) 原型链的主要作用是用来实现继承,因为对象可以通过隐式原型[[prototype]]访问原型链上的属性。
(5) __proto__是浏览器在ES5时实现的属性,ES标准是[[prototype]],所以他们两个是相等的。
(6) 但是[[prototype]]无法直接访问,MDN推荐使用Object.getPrototypeOf(obj)访问,这种访问 === 我们常用的 obj.__proto__
注意:通过浏览器尝试查看原型链时,会点开很多层__proto__和[[prototype]],记住这两个是相等的,不要将它们分开计算原型链的链层。
遵循 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf() 和 Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__。但它不应该与构造函数 func 的 prototype 属性相混淆。被构造函数创建的实例对象的[[Prototype]] 指向 func 的 prototype 属性。** Object.prototype ** 属性表示 Object 的原型对象。——MDN
实例
function Person() {
//修改全局函数 1
getName = function () {
console.log(1);
}
return this;
}
Person.getName = function () {
console.log(2);
}
Person.prototype.getName = function () {
console.log(3);
}
function getName() {
console.log(5)
}
Person.getName();//2
//Person.getName == Person.prototype.constructor.getName;
//由于是放在构造函数中,只能这样访问
getName();//5
//调用全局函数
Person().getName();//1
//返回this this为window 并根据window调用getName();
getName();//1
//被Person函数体修改
new Person().getName();//3
//该对象从函数原型上找到getName