當構造函數內部擁有返回值時會發生什麼

現象

咱們都知道,在 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 以實現鏈式調用。在某次突發奇想,對此感到好奇而且嘗試以後,一路刨根問底,才瞭解到簡單的調用背後,包含了這麼多複雜的步驟。

參考

相關文章
相關標籤/搜索