当构造函数内部拥有返回值时会发生什么

现象

咱们都知道,在 JavaScript 里面生成一个对象有不少种方法,其中一种即是使用构造函数。首先,定义一个构造器,在构造器内部定义对象的属性,再在构造器的原型上定义对象的方法,以下所示:javascript

const Person = function (name) {
  this.name = name;
}
Person.prototype.sayName = function () {
  console.log(this.name)
}
复制代码

因而,当咱们对 Person 调用 new 操做符,并传入一个 name 的时候,便会生成一个新的对象, 而且该对象会继承 Person 原型上所定义的属性或方法。html

然而,当咱们的构造器拥有一个返回值的时候,会发生什么呢?java

const Person = function (name) {
  this.name = name;
  return { name:  'Jason' }
}

Person.prototype.sayName = function () {
  console.log(this.name)
}

const person = new Person('Tony')

person.name
// Jason
person.sayName
// undefined
person instanceof Person
// false
复制代码

能够看到,当咱们在构造函数中返回一个对象时,对构造函数调用 new 操做符,最后获得的将会是咱们返回的对象,而当咱们返回一个非对象的值的时候,获得的则是在构造函数中初始化的 thisecmascript

注:这里的对象表示非原始值:async

The ECMAScript language types are Undefined, Null, Boolean, String, Symbol, Number, and Object.函数

那么,形成这种现象的缘由是什么呢?这个时候就须要了解当咱们对一个构造函数调用 new 操做符的时候,到底发生了什么。ui

概念

ECMAScript 规范中,定义了函数对象这一律念,一个函数对象内部包含了如下几个属性(简单摘抄,完整属性列表参见前面连接):this

  • FunctionKind ("normal", "classConstructor", "generator", "async")
  • ConstructorKind("base", "derived")

做为构造器的函数对象还含有内部方法[[Construct]]lua

流程

对构造函数调用 new

当咱们对一个函数调用 new 操做符的时候,会执行EvaluateNew(constructExpr, arguments)方法。spa

  1. 方法内部会对传入的参数进行一系列的校验,并经过 constructExpr 获取相应的 constructor
  2. 当解析后获得的 constructor 不是构造器(如箭头函数)的时候,会抛出一个 TypeError
  3. 执行语句 Return ? Construct(constructor, argList)
  4. 调用 constructorconstruct 方法 —— Return ? F.[[Construct]](argumentsList, newTarget)

Construct

  1. 先进行一系列的断言
  2. 判断 F.ConstructorKind 是否为 basebase 表示基类),若是是 base,则初始化函数内部的 thisObject.create(F.prototype)
  3. 判断 F.ConstructorKind 是否为 basebase 表示基类),若是是,则执行OrdinaryCallBindThis(F, calleeContext, thisArgument)
  4. 执行 OrdinaryCallEvaluateBody(F, argumentsList),获得结果 result
  5. 若是 result 的值为一个对象,则直接返回该对象
  6. 若是 F.ConstructorKindbase,则返回上面初始化的 this
  7. 若是 result 的值不是 undefined,则抛出一个TypeError
    注:这种场景,好比在继承后的 classconstructor 中返回了一个字符串
    class A {}
    class B extends A {
      constructor() {
        return ''
      }
    }
    // Uncaught TypeError: Derived constructors may only return object or undefined
    new B() 
    复制代码

总结

在实际的使用过程当中, 咱们每每不多会在构造函数中返回一个值,最多见的场景大概是 return this 以实现链式调用。在某次突发奇想,对此感到好奇而且尝试以后,一路刨根问底,才了解到简单的调用背后,包含了这么多复杂的步骤。

参考

相关文章
相关标签/搜索