对于JavaScript原型链的理解

197 阅读3分钟

对于JavaScript原型链的理解

问题的提出:

在初学原型的时候,几句代码的执行结果让我很不解:

typeof Object;	// function
typeof Function; // function

typeof Object.__proto__;	// function
typeof Object.prototype;	// Object

typeof Function.__proto__;	// function
typeof Function.prototype;	// function

基础知识:

在搞清楚上述代码之前,需要明白几点JavaScript的基础知识:

  1. JavaScript中,一切皆是对象;
  2. 对象是由函数创建的;
  3. 一切函数都是Function的实例
  4. Object对象是一个函数,所有的对象都是Object对象的实例,即所有的对象都继承自Object的原型对象;

对于三个属性的理解:

清楚了上述的基础知识之后,我们现在来理解一下原型链中关键的三个属性:prototype__proto__constructor

首先给出函数创建对象时,三个属性的指向图:(红箭头标识指针的指向):

IMG_14872D15A8E6-1.jpeg

遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf()Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__

  • prototype:

    每个函数都有一个prototype属性,这个属性是个指针,指向一个对象。该对象(原型对象)的用途是包含可以由特定类型的所有实例共享的属性和方法。其中,“特定类型的所有实例”就是由该函数作为构造函数创建的所有实例对象。

  • __proto__

    即上图中的[[Prototype]],是每个对象都有的属性,用于指向该对象的原型,由__proto__可以构成一条原型链。

  • constructor

    在我的理解中,construtor对于不同的对象有不同的含义:

    1. 对于一般对象,即我们使用构造函数创造的对象,constructor表示该对象的构造函数,如:

      function Foo() {}
      let foo = new Foo();
      console.log(foo.constructor);	// Foo() {}
      
      let a = {};	// 相当于 let a = new Object();
      console.log(a.constructor);	// Object() { [native code] }
      
      let b = [];	// 相当于 let b = new Array();
      console.log(b.constructor);	// Array() { [native code] }
      
      function c() {}	// 相当于 let c = new Function();
      console.log(c.constructor);	// Function() { [native code] }
      
    2. 对于函数所对应的原型对象(f.prototype),constructor表示该原型对象对应的函数,如:

      function Foo() {}
      console.log(Foo.prototype.constructor);	// Foo() {}
      
      // 用`instanceof`检测某对象是否是某函数的实例
      console.log(Foo.prototype instanceof Foo);	// false
      console.log(Foo.prototype instanceof Object);	// true
      

    为什么构造函数的实例化对象和原型对象的constructor都指向该构造函数?

    因为constructor是原型对象的固有属性,在被创建之初就指向它的函数,调用实例化对象的constructor时,会在原型链上一直寻找constructor属性,直到在原型对象上找到。

总结:

3080079431-5b02b2e259a19_fix732.png

  • 在JavaScript中,只有Object.prototype没有原型(null);
  • 对于对象中的属性,js会沿着原型链向上查找,直到找到该属性或到达Object.prototype才停止;处在原型链下层的属性被找到后,js就停止寻找,使得处在原型链上层的同名属性无法被访问,这种情况被称为"属性遮蔽 (property shadowing)";
  • ObjectStringNumberBooleanArrayFunction这些构造函数的constructor都是Function

一切皆是对象

对象都是由函数创造的

资料参考