谈谈对 js 原型链的理解

85 阅读2分钟

《用得上的前端知识》系列 - 你我都很忙,能用100字说清楚,绝不写万字长文

基本概念和关联

概念

  • Object.prototype:由 JS 引擎直接创建的对象;
  • Function.prototype:JS与引擎以 Object.prototype 为原型创建的函数;
  • prototype:指向构造函数的原型;“原型”可以理解为“原始模型”,构造函数以原型为模版创建实例;
  • proto :用于标记当前对象是基于哪个原型生成的;
  • 函数对象:所有typeof返回“function”的对象都是函数对象,这样的对象也称为构造器(constructor)。

关联

  • 函数 & 原型:(构造)函数以“原型”为模版创建实例。

原型链

关键点说明

  • js 引擎一开始就定义了很多数据类型,比如:Object、Array、Date、Function、Math、Error…;
  • 每个函数都有一个 prototype 属性,指向与之关联的原型对象;
  • 每个对象都有一个 proto 属性,指向它的构造函数的原型对象;
  • 对象通过构造函数的原型继承属性;
  • Object.prototype 是一个直接由 JS 引擎直接创建的对象,它的 proto 属性为 null;
  • Function.prototype 是由 JS 引擎直接创建的函数,它没有 prototype 属性(值为 undefined)。

原型链的起源分析

  • JS 引擎创建了一个对象 obj(它将作为原型链的顶端以及 Object 构造函数的原型);
  • JS 引擎以对象 obj 作为原型,创建函数对象 fn(它将作为 Function 构造函数的原型);
  • 以函数对象 fn 作为原型,创建内置函数 Object 和 Function;
  • 把函数对象 fn 设置为 Function 的原型,即:Function.prototype = fn;
  • 把对象 obj 设置为 Object 的原型,即:Object.prototype = obj;
  • 使用 Function 和 Object 创建其他内置函数及其原型。

示意图如下:

注:除了函数对象,还有很多内部对象,如:Object、Array、Date、RegExp、Math、Error。它们实际上表示一种类型;

需要注意的地方

//示例代码
function Person() {}
var person = new Person();
console.log(person.constructor === Person); // true
console.log(person.constructor === Person.prototype.constructor); //true
  • 不是所有函数都是 new Function() 产生的,比如 Function.prototype;
  • 所有实例都是对象,但是对象不一定都是实例,比如 Object.prototype(js引擎直接创建的);
  • 如上代码所示,person 中并没有 constructor,其值来源于构造函数的原型(即 Person.prototype.constructor);
  • 如上代码所示,proto 属性并不存在于 Person.prototype,而是存在于 Object.prototype,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。

特别说明

其实从平时的使用和面试这两个角度来看,只要记住本文的第一张图片中描述的关系链即可。

参考资料