這段時間一直在研究設計模式,在看工廠模式的時候,看到一段代碼
VehicleFactory.prototype.createVehicle = function ( options ) { if( options.vehicleType === "car" ){ this.vehicleClass = Car; }else{ this.vehicleClass = Truck; } return new this.vehicleClass( options ); };
對這段代碼最后的返回new this.vehicleClass( options )有些迷惑,到底是先執行了后面的方法還是先new了一個新對象出來呢?
直到今天v2ex出現一道JS面試題, v2ex鏈接 前面幾問都沒問題,到后面涉及到new的時候感覺有些混亂。
function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //請寫出以下輸出結果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
找了原文,看了下評論,找到了關鍵的地方,下面的1與2是原文的評論。
1.其實博主沒講明白,這里確實是(new Foo()).getName(),但是跟括號優先級高於成員訪問沒關系,實際上這里成員訪問的優先級是最高的,因此先執行了 .getName,但是在進行左側取值的時候, new Foo() 可以理解為兩種運算:new 帶參數(即 new Foo())和函數調用(即 先 Foo() 取值之后再 new),而 new 帶參數的優先級是高於函數調用的,因此先執行了 new Foo(),或得 Foo 類的實例對象,再進行了成員訪問 .getName。
2.第五問和第六問關於優先級的解釋也不恰當,new Foo()中的括號並不是括號運算符,而是函數調用的一部分
new Foo.getName(); 和 new Foo().getName(); 的區別在於
new Foo 結合屬於 new 無參數列表的情況(17級)
new Foo() 結合屬於 new 有參數列表的情況(18級)
成員訪問運算符(.)優先級為 18 級,和 new Foo() 同級
對於同級運算符,按照從左到右的順序依次計算
所以先執行 new Foo() 返回一個 Foo 的對象 ,對 Foo 對象調用 getName 時查找引用鏈,得到 Foo.prototype.getName
new Foo 結合被判定為無參數列表的new,優先級低於成員訪問,
所以先執行成員訪問得到 Foo 的屬性 getName, 然后 Foo.getName 和 new 結合,執行帶參數列表的 new 運算
需要注意的是帶參數列表的 new ...(...) 看起來像是 new 后面跟了一個函數調用,但在判斷運算符優先級時 new 運算是一個整體,不能把它分開
javascript 中設定帶參數列表 new 的優先級高於函數調用,那么在滿足帶參數列表的 new 運算符時,就不存在函數調用了
雖然帶參數列表的 new 運算也會執行函數調用,但是在判斷運算時不把 new 和 ...(...) 分開。
v2ex那位樓主對這個問題的解析也很不錯,可以看一下。現在對開頭的工廠模式那個new有了正確理解了吧。