原文:https://github.com/yangshun/front-end-interview-handbook/blob/master/questions/javascript-questions.mdjavascript
最近將持續翻譯JavaScript面試題,但願對各位有所幫助。 html
(文章中斜體字部分爲譯者添加)java
目錄:
Part 1(事件委託/this關鍵字/原型鏈/AMD與CommonJS/自執行函數)node
Part 2 (null與undefined/閉包/foreach與map/匿名函數/代碼組織)git
Part 3 (宿主對象與原生對象/函數調用方式/call與apply/bind/document.write)github
事件委託是一種向父級元素增長事件監聽器,而不用向子級元素一個個添加的技術方案。監聽器將在會DOM事件冒泡到父級元素時被觸發。事件委託有如下優點:面試
參考文檔:express
https://davidwalsh.name/event-delegate瀏覽器
https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation閉包
關於this其實沒有一個統一的解釋,它算是JavaScript中最讓人困惑的一個概念了。一種通俗的解釋就是,this的取值依賴於函數被誰調用。我在網上看過不少關於this的解釋,其中Arnav Aggrawal 的解釋應該是最爲清楚的,如下是他的觀點:
關於this更深一層的介紹,請參考:article on Medium
引用文檔:
https://codeburst.io/the-simple-rules-to-this-in-javascript-35d97f31bde3
https://stackoverflow.com/a/3127440/1751946
這是一個在面試中常常被問到的問題。JavaScript中的全部對象一個叫prototype的屬性,這個屬性指向於另外一個對象。當須要訪問一個對象上的某個屬性時,若是在自身對象上沒有找到該屬性的話,JS引擎會在對象的prototype上進行查找,找不到的話會繼續在prototype的prototype對象,依次類推直至在某個prototype上找到該屬性,或者到達原型鏈盡頭時中止。JS的這種行爲和傳統的繼承概念很像,但原型鏈的內容遠不止於此,更多內容請查看:delegation than inheritance
引用文檔:
https://www.quora.com/What-is-prototypal-inheritance/answer/Kyle-Simpson
https://davidwalsh.name/javascript-objects
這兩個均可以實現模塊系統,模塊系統在ES2015沒有發佈以前並無被原生JavaScript所支持。CommonJS是同步的,AMD(Asynchronous Module Definition)是相對異步的。CommonJS的設計初衷是應用在服務端,而AMD主要用在客戶瀏覽器端,由於它能夠支持異步加載模塊。
另外在語法層面,我也發現AMD相對比較輕量化,而CommonJS更接近別的開發語言中導入模塊的寫法。大多數時候,AMD仍是比較冗餘的,由於它會導入全部的JavaScript代碼到你的入口文件中,這樣反而使咱們不能從異步加載中受益。(好比我只須要lodash/map,但AMD會把整個lodash加載進來) CommonJS的語法更爲接近Nodejs模塊的編寫方式,在服務端和客戶端開發時,使用方式區別並不大。
值得慶幸的是ES2015的到來,它能夠同時支持同步與異步模塊加載,使得咱們有了一個統一的解決方案。但目前ES2015的模塊系統尚未被徹底支持,因此咱們須要使用一些轉換器將ES6編譯爲ES5。
引用文檔:
https://auth0.com/blog/javascript-module-systems-showdown/
https://stackoverflow.com/questions/16521471/relation-between-commonjs-amd-and-requirejs
IIFE的意思是自執行函數表達式。JavaScript引擎將會把上面的代碼看着是function foo(){}和(),也就是說前面是一個函數聲明,後面的()是嘗試去執行這個函數,可是因爲沒有執行的函數名,因此這裏會拋出異常:Uncaught SyntaxError: Unexpected token )。
有兩個經過增長括號的方法去修復上面的問題:(function foo(){}()) 以及 (function foo(){}())。這種函數並不會暴露在全局做用域中,你甚至還能夠把函數名也去掉,只保留函數體自己。(即匿名函數:(function (){}()) )
引用文檔:
http://lucybain.com/blog/2014/immediately-invoked-function-expression/