Skip to main content

原型

原型

每个函数都有一个默认的原型对象 - prototype ,通过 prototype 我们可以扩展 js 的内置对象。一个函数和它创建的实例共享这个函数的原型属性和方法。实例对象的 constructor 会指向构造函数

原型链

每个实例对象都会有一个隐式原型属性 __proto__,通过 __proto__ 指针指向创建该对象的构造函数的原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 Object.prototype,而 Object.prototype.__proto__ === null

可以看到:

  • 对象都能通过 __proto__ 属性找到 Object.prototypeObject.create(null) 创造出的对象例外,因为没有 __proto__ 属性。
  • 函数都能通过 __proto__ 属性找到 Function.prototype
  • Object 本身是个构造函数,是 Function 的实例

根据规范不建议直接使用 __proto__,推荐使用 Object.getPrototypeOf()

instanceOf 的原理

比如 A instanceOf B,会先沿着 A 的原型链一直向上找,如果能找到一个 __proto__ 等于 B 的 prototype,则返回 true;如果找到终点还没找到则返回 false

function _instanceOf(A, B) {
if (!A || !B) {
return false;
}
let O = B.prototype;
A = A.__proto__;
while (true) {
if (A === null) {
return false;
} else if (O === A) {
return true;
} else {
A = A.__proto__;
}
}
}

ObjectFunction 的鸡和蛋的问题

Object instanceof Function; // true
Function instanceof Object; // true
  • Object 本身是个构造函数,是 Function 的实例,即 Object.__proto__ === Function.prototype
  • Function.__proto__ 指向了 Function.prototypeFunction.prototype 继承自 Object.prototype,Function.prototype.__proto__ === Object.prototype

js 引擎查找对象属性/方法

先通过作用域链查找对象本身的属性或方法,之后沿着__proto__构成的原型链向上查找原型对象中的属性和方法,直到找到一个名字匹配的属性/方法或到达原型链的末端,如果找不到就会返回 undefined

为了判断一个对象是否包含自定义属性而不是原型链上的属性, 需要使用继承自 Object.prototype 的 hasOwnProperty 方法

面试题

// Object.prototype 是原型链的顶端
console.log(Object.prototype.__proto__ === null); // true

// Function可以理解为制造一切函数的机器,且自身也是由自己制造的,所以
console.log(Function.__proto__ === Function.prototype); // true

// Object从「对象」角度来讲,是由构造函数 Function 生产的
console.log(Object.__proto__ === Function.prototype); // true

// Function虽然由自身生产,但生产“机器”总要一个模板吧,这个模板对象(Function.prototype.__proto__)就是 Object.prototype
console.log(Function.prototype.__proto__ === Object.prototype); // true

// Object作为一个机器可以看做是有由Function制造出来的
// 而Function作为一个对象可以看做是由Object制造出来的。
console.log(Object instanceof Function); // true
console.log(Function instanceof Object); // true

// String 作为「对象」,是有构造函数 Function 生产的
console.log(String.__proto__ === Function.prototype); // true
// String.prototype 是个对象,是有 Object 生产的
console.log(String.prototype.__proto__ === Object.prototype); // true

function Person() {}
// 自定义构造函数作为「对象」,也是 Function 生产的
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
// Person 和 Object 一样,都是构造函数,都是有 Function 生产出来的对象
console.log(Person.__proto__ === Object.__proto__);

function Student() {
Person.call(this);
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor === Student;
console.log(Student.__proto__ === Function.prototype); // true
console.log(Student.prototype.__proto__ === Person.prototype); // true

参考