# 原型链经典图
# prototype 和 __proto__
的关系
prototype
是显示原型。它是构造函数才有的,每一个函数在创建之后都会拥有一个名为 prototype 的属性,这个属性指向函数的原型对象,用于访问函数的原型对象,实现基于原型的继承和属性的共享。__proto__
是隐式原型。这是所有对象都有的,构造函数实例化对象的__proto__
指向与构造函数的prototype
指向相同,构成原型链。
原型链就是用来沿着对象的原型一级一级查找属性的。
在原型链中,当我们访问 obj 这个对象中的 x 属性时,如果在 obj 中找不到,那么就会沿着 __proto__
依次查找,__proto__
会一直找到 Object.prototype.__proto__ = null
原型链的终点。
JavaScript 中任意对象都有一个内置属性 [[prototype]]
,在 ES5 之前没有标准的方法可以访问这个内置属性,但是大多数浏览器都支持通过 __proto__
来访问。ES5 中出现了对于这个内置属性标准的 Get 方法 Object.getPropertyOf()
。用于访问对象实例的原型对象。
function Test() {}
const test = new Test();
test.__proto__ === Test.prototype; // true
2
3
即构造函数拥有 prototype
属性,对象实例拥有 __proto__
属性,它们都是用来访问原型对象的。
函数有点特别,它不仅是个函数,还是个对象。所以它也有 __proto__
属性。
为什么?
因为函数是内置构造函数 Function
的实例。
const test = new Function("function Test() {}");
test.__proto__ === Function.prototype; // true
2
所以函数能够通过 __proto__
访问它的原型对象。
function Test() {}
Test.prototype.__proto__ === Object.prototype; // true
2
Object
其实也是一个内置函数。
const obj = new Object();
obj.__proto__ === Object.prototype;
2
为了防止无休止的循环下去,所以 Object.prototype.__proto__
指向 null 终止。
因此,使用 Object.create(null)
创建的对象是没有 __proto__
属性的,也没有 prototype
属性。
# 相关文章
# 面试真题
function Foo() {
Foo.a = function() {
console.log(1);
};
this.a = function() {
console.log(2);
};
}
Foo.prototype.a = function() {
console.log(3);
};
Foo.a = function() {
console.log(4);
};
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
// 输出为:4、2、1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22