上文 原型链,今天我们来说说终极原型链

# 终极原型链

只要对 js 深入了解一些,你肯定听说过一句话就是函数本质上也是一个对象,当函数被当作做对象去使用时函数就被称为函数对象,当函数被 () 调用是一个函数。既然函数也是对象,那它肯定也有一个原型。本文讲解将一直以下面代码为例

function Person(name, age) { // 创建一个 Person 构造函数
    this.name = name;
    this.age = age;
}
const obj = new Person("asuhe", 18); //new 一个 Person 实例
console.log(obj);

所有的函数对象都会有一个原型(ES6 箭头函数除外),且会有一个 prototype 属性指向该原型。当用一个函数对象当作构造函数使用 new 创建一个实例对象时,该构造函数所有实例对象的隐式原型即 __proto__ 都会指向构造函数的原型对象。在上述代码中我们可以得到一个最基本的原型链结构

原型链(1)

函数对象的原型本质上也是一个对象,只要是对象那么必定会有一个构造函数。** 实际上除函数对象和自身指定构造函数的对象外,所有的对象都是由 Object 这个构造函数 new 出来的。** 也就是说函数对象的原型是由 Object 构造出来的。根据原型链查找规则,我们可以用如下代码证明

let res = {};
console.log(res);
console.log(res.__proto__ === Person.prototype.__proto__); //true 说明普通对象都是由 Object 作为构造函数 new 出来的

原型链(1)

Object 作为构造函数那么它必然也有一个原型并且由 prototype 属性指向。上面我们说过除函数对象和自己指定构造的对象外,所有的对象都是由 Object 作为构造函数 new 出来的。所以我们可以画出更加完善一点的原型链

原型链(2)

Object 的原型的隐式原型 __proto__ 应该指向其构造函数的原型 prototype ,而 Object 的原型是由它自身 new 出来的。这样它原型链就形成了一个环:Object.prototypeObject.prototype(prototype of Object).__proto__Object.prototypeObject.prototype。为了阻止原型链在这个环里无限循环查找下去,所以在底层 (prototype of Object).__proto__ 被设置成了 null 。我们可以用代码证明上述的原型链

console.log(Person.prototye.__proto__ === Object.prototype); //true 说明函数对象的原型是由 Object new 出来的
console.log(Object.prototype.__proto__); //null 说明 Object 的原型的隐式原型值为 null

输出

# 函数对象的原型链

到目前为止,我们基本搞定了普通对象的原型链结构。但是还有一个问题我们没有搞定就是,既然函数也是一个对象那么它肯定也有自己的隐式原型 __proto__ 指向它的构造函数的原型。在 js 的底层所有的函数都是由 Function 作为构造函数 new 出来的,也就是说任何一个函数都是 Function 的实例

** 当我们使用 function 关键字时本质上就是 Fuction 作为构造函数 new 了一个对象。在 js 的底层最终都是调用 Function 函数去创建一个函数的。** 我们可以使用如下代码证明

// 证明所有的函数对象都是由 Function 构造的
console.log(Person.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Person.__proto__ === Object.__proto__); // true
// 箭头函数没有 prototype
const arrFn = ()=> console.log('ash');
console.log(arrFn.prototype); //undefined 说明箭头函数没有原型
console.log(arrFn.__proto__ === Function.prototype); //true 说明箭头函数同样是 Function new 出来的

输出

Function 函数本身也是一个函数对象,但是 Function 它是由自己 new 出来的。所以它的 __proto__prototype 都指向同一个原型。

console.log(Function.prototype === Function.__proto__); //true 说明 Function 自己 new 出的自己
console.log(Function.prototype.__proto__ === Object.prototype); //true 说明 Function 的原型还是 Object new 出来的

有了以上基础我们就可以继续完善一下原型链

原型链(3)

上面这个图就是我们常说的终极原型链了

# 自测题

// 思考下列输出并说明原因
console.log(Object instanceof Object)
console.log(String instanceof Function)
console.log(Function instanceof Object)
console.log(Object instanceof Function)
console.log(String instanceof Object)