葉小釵 的博客最近都在討論面試題目
正好以前也看過一篇,就借花獻佛拿出來分享一下 http://perfectionkills.com/javascript-quiz/
附帶了自己的理解,答案有爭議的地方歡迎大家指出
題目一
(function(){
return typeof arguments;
})();
答案
"object"
arguments是對象,偽數組有兩件事要注意這里:
參數不是數組,它是一個數組一樣的物體,你可以使用方括號和整數索引的元素,但方法通常可在一個如推上不存在參數數組
Array.prototype.slice.call(arguments); 轉成數組
當然arguments即使是數組,返回的依然是"object",因為數組也是對象,附加:typeof 對類型的判斷
https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Operators/typeof
題目二
var f = function g(){ return 23; };
typeof g();
答案
會發生錯誤
因為function g(){ return 23; }是函數表達式,事實上只有事一個名字,不是一個函數聲明
函數實際上是綁定到變量f,不是g.
指定的標識符在函數表達式雖然有其用途:堆棧跟蹤是清晰而不是充斥着無名的函數,你可以有一個匿名函數遞歸調用本身不使用argument.callee
附非常詳細的帖子函數表達式
http://kangax.github.io/nfe/
題目三
(function(x){
delete x;
return x;
})(1);
答案
1
參數不可刪除
見我發過的帖子(js中的delete定義)
http://www.cnblogs.com/aaronjs/articles/3148934.html
國外的帖子(理解刪除)
http://perfectionkills.com/understanding-delete/
題目四
var y = 1, x = y = typeof x;
x;
答案
"undefined"
通過重寫代碼如下結果:
var a, b; 展開就是 var a; var b;.
A = B = C;相當於 B = C = B;
知道了這一點,我們重寫並得到:
var y = 1;
y = typeof x;
var x = y;
x;
當執行
y = typeof x時,x 還沒有被定義,所以y成為字符串"undefined",然后被分配到x
題目五
(function f(f){
return typeof f();
})(function(){ return 1; });
答案
"number"
為了便於理解我們繼續分解:
第一部分
var baz = function(){ return 1; };
第二部分
(function f(f){
return typeof f();
})(baz);
在這里,函數f接受一個參數是另一個函數,f函數內部執行這個實參函數並且返回類型
無論是從調用該函數返回,即使參數名稱f與函數名沖突,函數接受本身作為自己的參數,然后調用,此時就看誰更具有更高的優先級了,顯然,參數的優先級更高,所以實際執行的是return typeof 1
題目六
var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();
})(foo.bar);
答案 "undefined"
為什么是"undefined"?.
我們必須要知道this運算符是怎么工作的.
JS語言精粹總結的很精煉:
1 純粹的函數調用
2 作為對象方法的調用
3 作為構造函數調用
4 apply調用
我們看看題目是屬於那種環境?
在arguments[0]()中執行了一個方法,arguments[0]就是foo.bar方法
注意:這在foo.bar中的this是沒有綁定到foo
雖然 foo.bar 傳遞給了函數,但是真正執行的時候,函數 bar 的上下文環境是 arguments ,並不是 foo
arguemnts[0] 可以理解為 arguments.0(不過寫代碼就不要這樣了,語法會錯誤的),所以這樣看來,上下文環境是 arguemnts 就沒問題了,所以在執行baz的時候自然this就是window了,window 上沒有baz屬性,返回的就是undefined, typeof調用的話就轉換成"undefined"了
附上博文
http://www.cnblogs.com/aaronjs/archive/2011/09/02/2164009.html
MDC
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/this_Operator#Description
題目七
var foo = {
bar: function(){ return this.baz; },
baz: 1
}
typeof (f = foo.bar)();
答案 "undefined"
繼續改寫一下:
var foo = {
bar: function(){ return this.baz; },
baz: 1
}
f = foo.bar;
typeof f();
把foo.bar存儲給f然后調用,所以this在foo.bar引用的是全局對象,所以就沒有baz屬性了
換句話說
foo.bar執行的時候上下文是 foo,但是當 把 foo.bar 賦值給 f 的時候,f 的上下文環境是 window ,是沒有 baz 的,所以是 ”undefined"
題目八
var f = (function f(){ return "1"; }, function g(){ return 2; })();
typeof f;
答案 "number"
逗號操作符的使用可以很混淆,但這段說明它的行為:
var x = (1, 2, 3);
x;
x的值是3,這表明,當你有一系列的組合在一起,並由逗號分隔的表達式,它們從左到右進行計算,但只有最后一個表達式的結果保存。由於同樣的原因,這個問題可以改寫為減少混亂:
var f = (function g(){ return 2; })();
typeof f;
關於逗號表達式:
原文:
http://www.2ality.com/2012/09/expressions-vs-statements.html
譯文:
http://www.cnblogs.com/ziyunfei/archive/2012/09/16/2687589.html
題目九
var x = 1;
if (function f(){}) {
x += typeof f;
}
x;
答案 "1undefined"
這里有個難點
if 中的 function f(){} 要如何處理?
函數聲明的實際規則如下:
函數聲明只能出現在程序或函數體內。從句法上講,它們 不能出現在Block(塊)({ ... })中,例如不能出現在 if、while 或 for 語句中。因為 Block(塊) 中只能包含Statement語句, 而不能包含函數聲明這樣的源元素。另一方面,仔細看一看規則也會發現,唯一可能讓表達式出現在Block(塊)中情形,就是讓它作為表達式語句的一部分。但是,規范明確規定了表達式語句不能以關鍵字function開頭。而這實際上就是說,函數表達式同樣也不能出現在Statement語句或Block(塊)中(因為Block(塊)就是由Statement語句構成的)。
假設代碼我們不妨變一下:
var x = 1;
if (function(){}) {
x += typeof f;
}
x;
var x = 1;
x += typeof f;
x;
f在這了沒有被定義,所以typeof f 是字符串"undefined" ,字符與數字相加結果也是一個字符串,
所以最后的x就是"1undefined"了
題目十
(function f(){
function f(){ return 1; }
return f();
function f(){ return 2; }
})();
答案 2
如果是一直看下來的話,這個題目應該是比較簡單
簡單的來說在執行return之前,函數聲明會在任何表達式被解析和求值之前先被解析和求值,
即使你的聲明在代碼的最后一行,它也會在同作用域內第一個表達式之前被解析/求值,
參考如下例子,函數fn是在alert之后聲明的,但是在alert執行的時候,fn已經有定義了
alert(fn());
function fn() {
return 'Hello world!';
}
所以題目中函數提升了兩次,第二次把第一次覆蓋了,
所以 return 后面的 f 是 return 語句的下一條語句聲明的函數 f 。
注意自執行函數 (function f (){})(); 中的 f 並沒有函數提升效果,它是表達式
題目十一
function f(){ return f; }
new f() instanceof f;
答案 false
怎樣去理解?
new f()
首先這個操作會創建一個新對象並調用構造函數函數這一新的對象作為它的當前上下文對象
簡單的說
new f();
依稀記得高級程序設計里面是這么說的:
1 創建空對象。
2 將類的prototype中的屬性和方法復制到實例中。
3 將第一步創建的空對象做為類的參數調用類的構造函數
默認如果沒有覆蓋這個空對象的話,返回this
var a = new Object;
a instanceof Object 為 true
我們在看 f() 返回了 return f;
那么也就是說這個新的對象是是自身,構造函數本身在 new 的過程中會返回一個表示該對象的實例。
但是函數的返回值覆蓋了這個實例,這個new 就形同虛設
果f的形式為 function f(){return this}或function f(){}就不一樣
var a = new f();
a instanceof f // false
值得注意的是 instanceof 檢測的是原型
又附上我博客的
JS 對象機制深剖——new 運算符
http://www.cnblogs.com/aaronjs/archive/2012/07/04/2575570.html
題目十二
var x = [typeof x, typeof y][1];
typeof typeof x;
答案
這題目比較簡單,注意下返回類型即可
x = [,][1];
即 x = typeof y = 'undefind'.
typeof 返回的是string類型就可以了
typeof typeof必然就是'string'了.
View Code
題目十三
function(foo){
return typeof foo.bar;
})({ foo: { bar: 1 } });
答案 "undefined"
又是一個惡心的題目,純文字游戲,大家看仔細看
先分解一下
var baz = { foo: { bar: 1 } };
(function(foo){
return typeof foo.bar;
})(baz);
去掉函數關聯
var baz = { foo: { bar: 1 } };
var foo = baz;
typeof foo.bar;
最后,通過替代我們除去中間變量foo
var baz = { foo: { bar: 1 } };
typeof baz.bar;
所以現在就很清晰了,屬性中沒有定義baz;它被定義為baz.foo上了,所以結果是:”undefined"
題目十四
with (function(x, undefined){}) length;
答案 2
with用得很少,with 語句就是用於暫修改作用域鏈的或者通常用來縮短特定情形下必須寫的代碼量
使用with語句的JavaScript代碼很難優化,因此它的運算速度比不使用with語句的等價代碼要慢得多。
而且,在with語句中的函數定義和變量初始化可能會產生令人驚訝的、相抵觸的行為,因此我們避免使用with語句
with的用法是這樣的:
with(object) {},在大括號里面,可以引用object的屬性而不用使用object.attr這種形式。
這道題里面,with接受了一個對象,只不過這個對象是函數,函數有length屬性,
代表形參的個數,所以上面返回的值是2
mozilla with
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:with