一道面試題引發的思考:理解 new 運算子

蛋黃派派發表於2018-12-20

今天看到一道面試題,如下,問: 例項化 Person 過程中,Person返回什麼(或者 p 等於什麼)?

function Person(name) {
    this.name = name
    return name;
}
let p = new Person('Tom');
複製程式碼

說實話,第一反應我以為值為 'Tom',等到我把程式碼丟到控制檯一輸出,才明白我錯了。天吶,new運算子給無視掉了嗎??? 撇開 new 的存在,我們修改下程式碼

function Person(name) {
    this.name = name
    return name;
}
let p = Person('Tom');
console.log(p);
複製程式碼

很顯然,輸出的結果是 'Tom', 但是有 new 存在呢?接下去,我們來捋一捋。 首先,我先去 MDN上搜尋了 new 的定義

new 運算子建立一個使用者定義的物件型別的例項或具有建構函式的內建物件的例項。

emmmm,相當晦澀難懂。

那我們試著寫幾個栗子看看結果吧

function Person1(name) {
  this.name = name;
  // 沒有返回值
}

function Person2(name) {
  this.name = name;
  return name;
  // 返回非物件
}

function Person3(name) {
  this.name = name;
  return { a: 1 };
  // 返回物件
}

function Person4(name) {
  this.name = name;
  return null;
  // 返回null
}

var p1 = new Person1("aa");
var p2 = new Person2("bb");
var p3 = new Person3("cc");
var p4 = new Person4("dd");

console.log(p1); // Person1 {name: "aa"}
console.log(p2); // Person2 {name: "bb"}
console.log(p3); // {a: 1}
console.log(p4); // Person4 {name: "dd"}
複製程式碼

根據上面幾個栗子,我們能得出結論:當使用 new 來建立物件||呼叫建構函式時,如果函式沒有返回值|| 返回值是非物件,那麼返回的就是建構函式例項後的物件(注意:return null,返回的也是建構函式例項後的物件而非null);如果函式return物件,那麼返回這個物件

我們接著看 MDN 文件的解釋,畢竟光光看這幾個demo沒有說服力。

一道面試題引發的思考:理解 new 運算子

一起來理解下 new 到底做了什麼工作吧~ 就拿下面這個 demo分析

function Person(name) {
  this.name = name;
  return {a: 1}
}
var p = new Person('fe')
複製程式碼

當呼叫 new Person(...)時,會進行以下幾步:

  • 首先是 繼承自 Person.prototype的新物件會被建立
  • 使用引數 'fe' 呼叫建構函式 Person, 並將 this 繫結到新建立的物件
  • Person 返回的物件就是 new 表示式的結果 =》 Person 返回的物件是 {a: 1} 所以new 表示式的結果為 {a:1} ; 如果 Person 沒有返回值(一般建構函式都不返回值)那麼使用步驟1建立的物件,即==》 繼承自 Person.prototype 的新物件

貌似照著文件能夠些許理解了,倘若模擬實現 new運算子更能深入理解 new 以下是 new 的模擬實現,程式碼來源 : JavaScript深入之new的模擬實現

function objectFactory() {
  var obj = new Object(),
  cons = [].shift.call(arguments)
  obj.__proto__ = cons.prototype
  var ret = cons.apply(obj, arguments)
  return typeof ret === 'object' ? ret|| obj : obj
}
function Person(name) {
  this.name = name;
  return {a: 1}
}
var p = objectFactory(Person, 'fe')
複製程式碼

當然了,學習別人的程式碼不能僅僅只是照搬過來,起碼得理解這個程式碼吧。 使用

  • 首先是建立一個物件
  • cons 是呼叫 objectFactory 方法的第一個引數,即建構函式; 因為 shift 會改變原陣列,所以改變後的 argument 即為呼叫建構函式的引數 (這裡補充說明下: arguments 是一個對應於傳遞給函式的引數的類陣列物件。)
  • obj 的原型指向建構函式, 這樣 obj 就能訪問到建構函式原型上的屬性
  • 將建構函式 consthis 指向 obj,這樣 obj 能訪問建構函式裡的屬性
  • 判斷返回的值是不是一個物件,如果是物件即返回它(當然這裡要處理 return null 的特例,因為歷史遺留問題 typeof null === 'object');如果不是物件就返回 obj (注意:這裡的 obj 已經不是一個空物件)

如果你耐心看到了這裡,那麼十分感謝。如文章有錯誤,望給予指正~

相關文章