JS基础之原型和原型链

85 阅读3分钟

原型和原型链经典图.png

1.原型和原型链的定义

原型:JS中除了null之外的JS对象都有一个与之关联的对象,这个对象就是它的原型,并且可以从这个对象继承属性和方法。

tips:上面为什么要强调除了null之外的JS对象?首先 null 不是一个JS对象,但是 typeof null 是等于 "object",这是JS的历史遗留问题。我们在谈论JS对象时,经常会特别指出“除了null之外”的对象,以防止混淆。这是因为尽管 typeof null 返回 "object",但在JS中,null实际上代表的是非对象的空值。下面内容中就不强调null了,默认所有JS对象就是除null之外的JS对象

原型链:JS在查找对象属性时,首先会在对象本身上查找,如果没有找到,就会去对象的原型上查找,接下来是原型的原型,依此类推,这样构成的一条链路我们称为原型链。

2.对象的原型

const obj = {}
console.log(obj.__proto__); // Object.prototype
console.log(obj.__proto__ === Object.prototype); // true
console.log(obj.prototype); // undefined

上面的代码我们通过字面量的方式创建了一个对象 obj ,而 __proto__obj 的原型,而 obj.__proto__ === Object.prototype也就是说所有对象的原型最终都会指向 Object.prototype,而Object.prototype本身也是一个对象,那么它的原型是什么呢,我们知道原型链的终点是null,而 Object.prototype的原型正是指向原型链的终点 null,即:Object.prototype.__proto__ === null。还有一点对象是没有 prototype 属性的。

重点:JS中所有对象的原型最终都会指向 Object.prototype,而 Object.prototype 的原型等于 null

3.函数的原型

function fn() { }
console.log(fn.__proto__ === Function.prototype); // true
console.log(fn.prototype);

当函数被当作对象时,也可以说当函数不被用作构造函数时,它的原型是 __proto__,而不做构造使用的函数的原型最终都是指向 Function.prototype的,而 Function.prototype 是个对象,所以它的原型还是指向 Object.prototype,也就是 Function.prototype.__proto__ === Object.prototype

tips:Function__proto__ 也等于 Function.prototype。因为当 Function 不被当作构造函数使用时,那么它的原型 __proto__ 也是指向 Function.prototype 的。

而当函数被用作构造函数时,它的原型就是 prototype,创建的实例都是从构造函数的 prototype 上去继承属性和方法的。

也可以说,函数都是由 Function 原生构造函数创建的,所以函数的 __proto__ 属性指向 Function 的prototype 属性。

4.解析上面那张图

function Foo() { }
const f1 = new Foo()
console.log(f1.__proto__ === Foo.prototype); // true
console.log(Foo.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null

const o1 = new Object()
console.log(o1.__proto__ === Object.prototype); // true
console.log(Object.prototype.constructor === Object); // true
console.log(Object.__proto__ === Function.prototype); // true 
console.log(Function.prototype.constructor === Function); // true

这个代码基本上可以描述上面那张图的内容。

    1. f1.__proto__ === Foo.prototype Foo是当构造函数使用的,它的原型是prototype,所以实例的原型等于它,没问题,这里看不懂的可以去看下 new 构造函数内部做了什么事情。
    1. Foo.prototype.__proto__ === Object.prototype Foo.prototype 是个对象,它的原型指向所有对象原型的终点 Object.prototype
    1. Object.prototype.__proto__ 指向原型链的终点 null
    1. o1.__proto__ === Object.prototype 这个跟第2条是一样的。
    1. Object.prototype.constructor === Object 构造函数原型中的 constructor 属性指回构造函数。
    1. Object.__proto__ === Function.prototype 函数不做构造函数使用时它原型的终点是 Function.prototype
    1. Function.prototype.constructor === Function 跟第5条一样。

参考资料