長期更新文章 喜歡的start下 github.com/aototo/blog
建構函式已經是老生常談的事情了。這裡講一些比較基礎的東西。
先看下一個例子
function Book(name) {
if (!(this instanceof Book)) {
// the constructor was called without "new".
return new Book(name);
}
}
var myBook = Book(name);
var myBook1 = Book(name);
myBook.constructor === myBook1.constructor // true複製程式碼
首先判斷this是否為Book的例項,不是就返回新的例項。經常用於解決在建構函式前面忘記使用new
的情況,如果沒有使用在function前面使用new,那就按正常的函式執行。那為什麼這裡可以這麼使用?
我們先看下new
的原理
(1) 建立一個新的物件: var myBook = New Object()
(2) 設定物件的__proto__ 指向建構函式的prototype
myBook.__proto__ = Book.prototype複製程式碼
到了第二步驟我們就可以看到myBook可以訪問建構函式的prototype的constructor。
var myBook = New Object();
myBook.__proto__ = Book.prototype;
myBook instanceof Book // true複製程式碼
當執行第二步驟以後例子中的 if (!(this instanceof Book))
就不會被執行。所以this instanceof Book
可以判斷當前函式是否使用new。從而避免開發者忽略而造成程式錯誤的情況。
(3)第三步就是執行Book函式,並且讓this指向myBook物件複製程式碼
第四步就是判斷Book返回值的型別:
判斷條件
(1)如果是值型別就丟棄,返回instance。
(2)如果是引用型別,就返回這個引用型別的物件,替換掉instance。複製程式碼
例子:
function Book() {
return 2;
}
var myBook = new Book();
myBook instanceof Book // true複製程式碼
return 2屬於值型別,包括String、布林值、null、undefined等..如果是值型別,就丟棄返回instance。
function Book() {
var newObj = {}
return newObj;
}
var myBook = new Book();
myBook instanceof Book // false複製程式碼
如果是引用型別,就返回這個引用型別的物件
function Book() {
return new Number();
}
...複製程式碼
如果return的值是一個Number 物件,那麼例項物件的值就是Number 物件。
使用Object.create()建立的物件其proto 並不是指向建構函式。
原型鏈繼承需要注意的一點
例子:
function Car() {}
function Bmw() {}
Bmw.prototype = new Car();
Bmw.prototype.constructor = Bmw;
var bmw1 = new Bmw();複製程式碼
比較奇怪的是 Bmw.prototype.constructor = Bmw; 解釋下為什麼要這麼處理。
假設如果沒有這行
bmw1.constructor === Car //true複製程式碼
Bmw.prototype 實際上是 new Car() 的例項,結果導致Bmw prototype中的 constructor從丟失(ps: function建立後prototype已經有constructor值),bmw1
物件在原型鏈中查詢constructor的時候指向了建構函式Car
,這明顯是錯誤的。因此這裡修正了Bmw.prototype.constructor = Bmw
。同時還可以通過proto獲取Car的建構函式。
bmw1.__proto__.__proto__.constructor === Car複製程式碼