今天看到一道面試題,如下,問: 例項化 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
到底做了什麼工作吧~
就拿下面這個 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 就能訪問到建構函式原型上的屬性 - 將建構函式
cons
的this
指向obj
,這樣obj
能訪問建構函式裡的屬性 - 判斷返回的值是不是一個物件,如果是物件即返回它(當然這裡要處理
return null
的特例,因為歷史遺留問題typeof null === 'object'
);如果不是物件就返回obj
(注意:這裡的obj
已經不是一個空物件)
如果你耐心看到了這裡,那麼十分感謝。如文章有錯誤,望給予指正~