14 個折磨人的 JavaScript 面試題
前端工程師有時候面試時會遇到一類面試官,他們問的問題對於語言本身非常較真兒,往往不是候選人可能期待的面向實際的問題(有些候選人強調能幹活就行,至於知不知道其中緣由是無關痛癢的)。這類題目,雖然沒有邏輯,但某種程度說,確實考察了候選人對於javascript
這門語言的理解。
突然想到這個話題是無聊在翻自己的Github,看看以前都寫過什麼醜貨。然後翻到了這篇解釋Javascript quiz的文章quiz-legend,反正沒事兒,就想搬過來供大家學習、理解、背誦、批判。
問題一
(function(){ return typeof arguments;//"object" })();
arguments
是一個Array-like物件,對應的就是傳入函式的引數列表。你可以在任何函式中直接使用該變數。
typeof
操作符只會返回string
型別的結果。參照如下列表可知對應不同資料,typeof
返回的值都是什麼:
型別 | 結果 |
---|---|
undefined |
'undefined' |
null |
'object' |
Boolean |
'boolean' |
Number |
'number' |
String |
'string' |
Symbol (new in ECMAScript 2015) | 'symbol' |
Host object (provided by the JS environment) | Implementation-dependent |
Function object (implements [[Call]] in ECMA-262 terms) | 'function' |
Any other object | 'object' |
由此我們推斷出,
typeof arguments
是object
問題二
var f = function g(){ return 23; }; typeof g();//報錯
這是一個名字是g
的function expression,然後又被賦值給了變數f
。
這裡的函式名g
和被其賦值的變數f
有如下差異:
- 函式名
g
不能變動,而變數f
可以被重新賦值 - 函式名
g
只能在函式體內部被使用,試圖在函式外部使用g
會報錯的
問題三
(function(x){ delete x; return x;//1 })(1);
delete
操作符可以從物件中刪除屬性,正確用法如下:
delete object.property delete object['property']
delete
操作符只能作用在物件的屬性上,對變數和函式名無效。也就是說delete x
是沒有意義的。
你最好也知道,
delete
是不會直接釋放記憶體的,她只是間接的中斷物件引用
問題四
var y = 1, x = y = typeof x; x;//"undefined"
我們試圖分解上述程式碼成下面兩步:
var y = 1; //step 1 var x = y = typeof x; //step 2
第一步應該沒有異議,我們直接看第二步
- 賦值表示式從右向左執行
y
被重新賦值為typeof x
的結果,也就是undefined
x
被賦值為右邊表示式(y = typeof x
)的結果,也就是undefined
問題五
(function f(f){ return typeof f();//"number" })(function(){ return 1; });
直接上註釋解釋:
(function f(f){ //這裡的f是傳入的引數function(){ return 1; } //執行的結果自然是1 return typeof f(); //所以根據問題一的表格我們知道,typeof 1結果是"number" })(function(){ return 1; });
問題六
var foo = { bar: function() { return this.baz; }, baz: 1 }; (function(){ return typeof arguments[0]();//"undefined" })(foo.bar);
這裡你可能會誤以為最終結果是number
。向函式中傳遞引數可以看作是一種賦值,所以arguments[0]
得到是是真正的bar
函式的值,而不是foo.bar
這個引用,那麼自然this
也就不會指向foo
,而是window
了。
問題七
var foo = { bar: function(){ return this.baz; }, baz: 1 } typeof (f = foo.bar)();//"undefined"
這和上一題是一樣的問題,(f = foo.bar)
返回的就是bar
的值,而不是其引用,那麼this
也就指的不是foo
了。
問題八
var f = (function f(){ return '1'; }, function g(){ return 2; })(); typeof f;//"number"
逗號操作符 對它的每個操作物件求值(從左至右),然後返回最後一個操作物件的值
所以(function f(){ return '1'; }, function g(){ return 2; })
的返回值就是函式g
,然後執行她,那麼結果是2
;最後再typeof 2
,根據問題一的表格,結果自然是number
問題九
var x = 1; if (function f(){}) { x += typeof f; } x;//"1undefined"
這個問題的關鍵點,我們在問題二中談到過,function expression
中的函式名f
是不能在函式體外部訪問的
問題十
var x = [typeof x, typeof y][1]; typeof typeof x;//"string"
- 因為沒有宣告過變數
y
,所以typeof y
返回"undefined"
- 將
typeof y
的結果賦值給x
,也就是說x
現在是"undefined"
- 然後
typeof x
當然是"string"
- 最後
typeof "string"
的結果自然還是"string"
問題十一
(function(foo){ return typeof foo.bar;//"undefined" })({ foo: { bar: 1 } });
這是個純粹的視覺詭計,上註釋
(function(foo){ //這裡的foo,是{ foo: { bar: 1 } },並沒有bar屬性哦。 //bar屬性是在foo.foo下面 //所以這裡結果是"undefined" return typeof foo.bar; })({ foo: { bar: 1 } });
問題十二
(function f(){ function f(){ return 1; } return f();//2 function f(){ return 2; } })();
通過function declaration
宣告的函式甚至可以在宣告之前使用,這種特性我們稱之為hoisting。於是上述程式碼其實是這樣被執行環境解釋的:
(function f(){ function f(){ return 1; } function f(){ return 2; } return f(); })();
問題十三
function f(){ return f; } new f() instanceof f;//false
當程式碼new f()
執行時,下面事情將會發生:
- 一個新物件被建立。它繼承自
f.prototype
- 建構函式
f
被執行。執行的時候,相應的傳參會被傳入,同時上下文(this
)會被指定為這個新例項。new f
等同於new f()
,只能用在不傳遞任何引數的情況。 - 如果建構函式返回了一個“物件”,那麼這個物件會取代整個
new
出來的結果。如果建構函式沒有返回物件,那麼new
出來的結果為步驟1建立的物件,
ps:一般情況下建構函式不返回任何值,不過使用者如果想覆蓋這個返回值,可以自己選擇返回一個普通物件來覆蓋。當然,返回陣列也會覆蓋,因為陣列也是物件。
於是,我們這裡的new f()
返回的仍然是函式f
本身,而並非他的例項
問題十四
with (function(x, undefined){}) length;//2
with
語句將某個物件新增的作用域鏈的頂部,如果在statement
中有某個未使用名稱空間的變數,跟作用域鏈中的某個屬性同名,則這個變數將指向這個屬性值。如果沒有同名的屬性,則將丟擲ReferenceError
異常。
OK,現在我們來看,由於function(x, undefined){}
是一個匿名函式表示式,是函式,就會有length
屬性,指的就是函式的引數個數。所以最終結果就是2
了
寫在最後
有人覺得這些題坑爹,也有人覺得開闊了眼界,見仁見智吧。但有一件事是真的,無論你是否堅定的實踐派,缺了理論基礎,也鐵定走不遠 - 你永遠不會見到哪個熟練的技術工人突然成了火箭專家。
看文件、讀標準、結合實踐,才是同志們的決勝之道。
相關文章
- 五個典型的JavaScript面試題JavaScript面試題
- 5個典型的JavaScript面試題JavaScript面試題
- 20個必會的JavaScript面試題JavaScript面試題
- 5個典型的JavaScript面試題(上)JavaScript面試題
- 140個Google面試問題Go面試
- 26個精選的JavaScript面試問題JavaScript面試
- 再來5個JavaScript面試題JavaScript面試題
- Promise這個折磨人的小妖精Promise
- 面試題-JavaScript交換兩個變數的方法面試題JavaScript變數
- 3個經常被問到的 JavaScript 面試題JavaScript面試題
- 每個前端開發者必會的 20 個 JavaScript 面試題前端JavaScript面試題
- 7個 Javascript 面試題及回答策略JavaScript面試題
- JavaScript面試題JavaScript面試題
- JavaScript 面試題JavaScript面試題
- 25 個最基本的 JavaScript 面試問題及答案JavaScript面試
- 25個最基本的JavaScript面試問題及答案JavaScript面試
- 5個經典的JavaScript面試基礎問題JavaScript面試
- 面試小冊:面試官經常問的十個棘手的 JavaScript 問題面試JavaScript
- JavaScript面試題整理JavaScript面試題
- JavaScript面試題目,JavaScript面試題
- 37個 JavaScript 基本面試問題和解答JavaScript面試
- IT面試題:附帶答案的14道Spring MVC面試題面試題SpringMVC
- 【Java面試】 Javascript常見面試題!JavaScript面試題
- 分享JavaScript面試題部分JavaScript面試題
- javascript經典面試題JavaScript面試題
- 讓我印象深刻的javascript面試題JavaScript面試題
- 最失敗的 JavaScript 面試問題JavaScript面試
- 讓我印象深刻的 JavaScript 面試題JavaScript面試題
- 前端面試題(4)JavaScript前端面試題JavaScript
- 前端面試題 之 JavaScript前端面試題JavaScript
- JavaScript中揹包問題(面試題)JavaScript面試題
- 前端程式設計師經常忽視的一個JavaScript面試題前端程式設計師JavaScript面試題
- Hive的一個面試題Hive面試題
- 14個Google地圖的JavaScript資源Go地圖JavaScript
- JavaScript的基礎知識點(面試題)JavaScript面試題
- 最近面試的題目(WEB、Service、SQL、JavaScript)面試WebSQLJavaScript
- 21個JavaScript 面試中常見演算法問題詳解JavaScript面試演算法
- JavaScript 面試必須知道的 10 個概念JavaScript面試