寫這篇博客的原由是因為昨日的凡科筆試遇到了類似的題目。
現在就來看看這道題目,首先正如注釋寫的那樣,因為存在函數提升所以第一個getval()的輸出就是5,接着調用f.getval這個函數輸出2,
f().getval()這一步的理解是比較重要的:
第一步:先執行f函數內的代碼;因為f函數里的getval沒有用var等聲明,所以getval變為了全局的函數而不是f函數的私有成員,接着返回this=》即window對象;
第二步:這時f().getval()變成了window.getval();所以輸出為1
第二個getval的調用:參照上面故也輸出1;
new f.getval():因為成員訪問'.'的優先級比new高,所以先執行f.getval,在來執行new,可看成=》new (f.getval) (),new返回f.getval的實例,輸出2;
new f().getval():這里主要猶豫的時先執行f()還是new,因為此時new是帶參數的,所以先new,=》(new f()).getval,即調用的是f()上的getval,因為在f()里沒找到自己的getval,所以去原型上找,輸出為3
new new f().getval(): 由上面就可以知道帶參數的new會優先執行故:
第一步:new( new f().getval)()
第二步:new( ( new f() ).getval)()
先計算new f()
, 在獲取getval,在對獲取內容進行new ()計算,再進行調用;
也就是new( ( new f() ).getval)() =》new(f.prototype.getval)(),故輸出為3.
參考文章:https://www.jianshu.com/p/412ccd8c386e
補充:
靜態方法和實例方法:
function f(){ getval = function(){ console.log(1) } return this; } //這是f的靜態方法 f.getval = function(){ console.log(2) } //這是f的實例方法 f.prototype.getval = function(){ console.log(3) }
當我們希望某個方法只有構造函數自身可以使用,實例無法繼承使用,此方法就應該使用靜態方法。
函數f無法直接調用實例方法,實例也無法直接調用靜態方法。
變量提升:
var getval = function(){ console.log(4) }; function getval(){ console.log(5) } //相當於 function getval(){ console.log(5) } var getval ; getval = function(){ console.log(4) };
函數和變量都存在提升,但是函數提升優先級高於變量提升,且不會被同名變量聲明時覆蓋,但是會被變量賦值后覆蓋