# 原型链经典图

jstest

# prototype 和 __proto__ 的关系

  1. prototype显示原型。它是构造函数才有的,每一个函数在创建之后都会拥有一个名为 prototype 的属性,这个属性指向函数的原型对象,用于访问函数的原型对象,实现基于原型的继承和属性的共享。

  2. __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
1
2
3

即构造函数拥有 prototype 属性,对象实例拥有 __proto__ 属性,它们都是用来访问原型对象的。

函数有点特别,它不仅是个函数,还是个对象。所以它也有 __proto__ 属性。

为什么?

因为函数是内置构造函数 Function 的实例。

const test = new Function("function Test() {}");
test.__proto__ === Function.prototype; // true
1
2

所以函数能够通过 __proto__ 访问它的原型对象。

function Test() {}
Test.prototype.__proto__ === Object.prototype; // true
1
2

Object 其实也是一个内置函数。

const obj = new Object();
obj.__proto__ === Object.prototype;
1
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
上次更新时间: 2024年01月05日 15:06:06