在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。

  1. js分为函数对象和普通对象,每个对象都有__proto__属性,但是只有函数对象才有prototype属性

  2. Object、Function都是js内置的函数, 类似的还有我们常用到的Array、RegExp、Date、Boolean、Number、String


  1. 属性__proto__是一个对象,它有两个属性,constructor和__proto__;

  2. 原型对象prototype有一个默认的constructor属性,用于记录实例是由哪个构造函数创建;


  1. Person.prototype.constructor == Person // 准则1:原型对象(即Person.prototype)的constructor指向构造函数本身

  2. person01.proto == Person.prototype // 准则2:实例(即person01)的__proto__和原型对象指向同一个地方

图示:

  • avatar

面试场景

面试官:谈谈你对 JS 原型和原型链的理解?

候选人:JS 原型是指为其它对象提供共享属性访问的对象。在创建对象时,每个对象都包含一个隐式引用指向它的原型对象或者 null。

原型也是对象,因此它也有自己的原型。这样构成一个原型链。

面试官:原型链有什么作用?

候选人:在访问一个对象的属性时,实际上是在查询原型链。这个对象是原型链的第一个元素,先检查它是否包含属性名,如果包含则返回属性值,否则检查原型链上的第二个元素,以此类推。

面试官:那如何实现原型继承呢?

候选人:有两种方式。一种是通过 Object.create 或者 Object.setPrototypeOf 显式继承另一个对象,将它设置为原型。

另一种是通过 constructor 构造函数,在使用 new 关键字实例化时,会自动继承 constructor 的 prototype 对象,作为实例的原型。

在 ES2015 中提供了 class 的风格,背后跟 constructor 工作方式一样,写起来更内聚一些。

面试官:ConstructorB 如何继承 ConstructorA ?

候选人:JS 里的继承,是对象跟对象之间的继承。constructor 的主要用途是初始化对象的属性。

因此,两个 Constructor 之间的继承,需要分开两个步骤。

第一步是,编写新的 constructor,将两个 constructor 通过 call/apply 的方式,合并它们的属性初始化。按照超类优先的顺序进行。

第二步是,取出超类和子类的原型对象,通过 Object.create/Object.setPrototypeOf 显式原型继承的方式,设置子类的原型为超类原型。

整个过程手动编写起来比较繁琐,因此建议通过 ES2015 提供的 class 和 extends 关键字去完成继承,它们内置了上述两个步骤。

面试官:看起来你挺了解原型,你能说一个原型里比较少人知道的特性吗?

候选人:在 ES3 时代,只有访问属性的 get 操作能触发对原型链的查找。在 ES5 时代,新增了 accessor property 访问器属性的概念。它可以定义属性的 getter/setter 操作。

具有访问器属性 setter 操作的对象,作为另一个对象的原型的时候,设置属性的 set 操作,也能触发对原型链的查找。

普通对象的 proto 属性,其实就是在原型链查找出来的,它定义在 Object.prototype 对象上。

理解Object和Function

JavaScript 中 Object 和 Function 的关系是微妙的,他们互为对方的一个实例。

Function instanceof Object 和 Object instanceof Function 都是 true

1。我们可以认为 Object 是一个特殊的“类”,而这里的“类”即:Function

于是便可以理解为: Object = Function () {} 或 Object = new Function(); 即:Object 是 Function 的一个实例,所以,Object 原型链中便包含 Function.prototype,得出: Function.prototype.isPrototypeOf(Object) 为 true

2。同时,js中,所有对象(不包括js语言外部对象)都可视为是 Object 的一个实例, Function 不例外,Function.prototype 亦不例外,于是有 Function = new Object(); Function.prototype = new Object(), 于是 Object.prototype.isPrototypeOf(Function) 和 Object.prototype.isPrototypeOf(Function.prototype) 都为 true 了

3。补充:Function 本身也是一个“类”,然而,所有“类”都是Funciton的实例,于是 Function instanceof Function; 为true。同时,所有对象都是 Object 类的实例,Object 本身也是一个对象,所有又有 Object instanceof Object 也为 true。另外,还可以认为 Funciton 类型是 Object 类型的一个“派生类”,class Function 继承了class Object ,是 class Object 的一个“子类”。

Object.toString方法深入理解