function
foo() ;
return
this;
}foo.getname = function () ;
foo.prototype.getname = function () ;
var getname = function () ;
function
getname()
//請寫出以下輸出結果:
foo.getname();
getname();
foo().getname();
getname();
new foo.getname();
new foo().getname();
newnew foo().getname();
先來理解下題目,首先建立了乙個foo()函式,然後在給foo函式增添乙個函式屬性getname,在foo原型上增添乙個getname函式屬性,然後再以函式表示式和函式宣告分別建立了乙個同名函式getname。
第一問:foo.getname()返回2。
第二問:首先需要知道函式表示式和函式宣告的區別。
函式宣告具有變數宣告提公升(即所有宣告變數或宣告函式都會被提公升到當前函式的頂部)例:
console.log('x'
inwindow);
console.log(typeof func);
var x = 0;
function
func(){}
js引擎會將其解析為:
var x;
function
func(){}
console.log('x'
inwindow); //true
console.log(typeof func); //function
x = 0;
如果能明白的話就能理解下面**的輸出:
console.log(x); //function(){}
var x = 1;
console.log(x); //1
function
x(){}
console.log(x); //1
所以js引擎在解析**時候就變成了:
//省略部分**
function
foo() ;
return
this;
}var getname;
function
getname()
getname = function () ;
getname(); //4
後面函式表示式的賦值將前面的getname值個覆蓋了,所以第二問輸出4。
第三問:首先執行foo()函式,並執行getname的賦值語句。
它會查詢當前作用域上是否存在這個變數,如果沒有就向它上層作用域繼續尋找,直到找到window全域性作用域,若還是沒有則在全域性作用域上建立getname變數,因為window域中存在著getname這個變數即(var getname = function () ;),所以將其替換為(getname = function () ;)
並返回window物件,所以foo().getname()的結果為1;
若**改為:
function
foo() ;
return
this;
}foo().getname(); //typeerror: foo().getname is not a function.
建立getname時候多加乙個var,即在當前作用域中新增乙個區域性變數getname,而在執行完畢後該區域性變數就會被**,並且該函式返回window全域性物件,故在訪問window中的getname會報錯,因為沒有建立window物件無此變數。
即(getname = function () ;)
故此時getname();輸出結果為1。
第五問 new foo.getname(); ,此處考察的是js的運算子優先順序問題。
根據圖中優先順序的描述:
優先順序圖
可以得知:可以得知點(.)的優先順序高於new操作,所以原式相當於是:
new (foo.getname)();
所以結果為2;
第六問 new foo().getname()
根據表的執行結果為:(new foo()).getname();
js返回值分為三類:
1、沒有返回值則建立乙個空物件,並把函式中與this繫結的屬性新增;
function
f()var obj = new f(); // obj: 建立乙個物件,並繫結函式中this所繫結的屬性
2、若有返回值則檢查返回值的型別,若返回值為非引用型別,比如基本型別:(string,number,boolean,null,undefined),則js引擎會忽略該返回值,並且建立乙個新物件,並把函式中與this繫結的屬性新增;
function
f()var obj = new f(); // obj: 建立乙個物件,並繫結函式中this所繫結的屬性
3、若返回值是引用型別,則實際返回值為這個引用型別。
function
f();}
var obj = new f(); //obj:
如果理解這些,再來看下面乙個例子:
var obj;
function
f1()
obj = new f1(); //obj: f1
function
f2()
obj = new f2(); //obj: f2
function
f3()
obj = new f3(); //obj: string
從例子中我們可以得出:無論 『a』還是string('a')建立的都是基本型別值,而new string('a')則建立乙個字串包裝物件。
原題中,返回的是this,而this在建構函式中本來就代表當前例項化物件。
之後呼叫例項化物件的getname函式,因為在foo建構函式中沒有為例項化物件新增任何屬性,遂到當前物件的原型物件(prototype)中尋找getname,故最終輸出3。
第七問:new new foo().getname(); 同樣是運算子優先順序問題。
執行結果為:new ((new foo()).getname)();
先初始化foo的例項化物件,然後將其原型上的getname函式作為建構函式再次new,故最終結果為3
記錄一些有意思的前端面試題
1 乘積函式 function mul array.prototype let argus slice.call arguments,0 let returnfn function returnfn.valueof function returnfn.tostring null return ret...
一些比較有意思的題目
example 輸入 698592 k 4 輸出 6592 solution 一種比較常見的思路是列舉全部k 4的數字,然後再取最小值,然而這樣複雜度會很高。本文的思路是不斷遞迴求得最小值,注意邊界,可以顯著降低複雜度。void find min core vector vec,int k,int ...
一些有意思的東西
近日,在敲 的時候,筆者發現了一些有意思的東西。在我們用迴圈的時候,常常因為一些條件,要提前結束迴圈,而在c語言中,可以打破迴圈的就是break和continue了 1.看這個 它只輸出了兩個6,由此我們可以看出break是打破整個迴圈 2.再看關於continue 可以看出,它輸出了9個6,因此c...