(function() { var a = b = 5; })(); console.log(b); //5
這個問題的陷阱就是,在當即執行函數表達式(IIFE
)中,有兩個賦值,可是其中變量a使用關鍵詞var來聲明。這就意味着a是這個函數的局部變量。與此相反,b被分配給了全局做用域(譯註:也就是全局變量)。javascript
這個問題另外一個陷阱就是,在函數中沒有使用」嚴格模式」 ('use strict'
)。若是 嚴格模式開啓,那麼代碼就會報錯 」 Uncaught ReferenceError: b is not defined
」 。請記住,若是這是預期的行爲,嚴格模式要求你顯式地引用全局做用域。因此,你須要像下面這麼寫:java
(function() { 'use strict'; var a = window.b = 5; })(); console.log(b);
答案:
5node
在 String 對象上定義一個 repeatify 函數。這個函數接受一個整數參數,來明確字符串須要重複幾回。這個函數要求字符串重複指定的次數。舉個例子:
console.log('hello'.repeatify(3));
應該打印出hellohellohello
.面試
答案:算法
String.prototype.repeatify = String.prototype.repeatify || function(times){ var str = ''; for(var i = 0;i < times;i++){ str += this; } return str; }
這個問題測試了開發人員對 javascript 中繼承及原型(prototype)屬性的知識。這也驗證了開發人員是否有能力擴展原生數據類型功能(雖然不該該這麼作)。閉包
在這裏,另外一個關鍵點是,看你怎樣避免重寫可能已經定義了的方法。這能夠經過在定義本身的方法以前,檢測方法是否已經存在。app
String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};
function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test();
答案:
undefined
2函數
這個結果的緣由是,變量和函數都被提高(hoisted) 到了函數體的頂部。所以,當打印變量a時,它雖存在於函數體(由於a已經被聲明),但仍然是undefined。換言之,上面的代碼等同於下面的代碼:學習
function test() { var a; function foo() { return 2; } console.log(a); console.log(foo()); a = 1; } test();
this
是怎麼工做的var fullname = 'John Doe'; var obj = { fullname: 'Colin Ihrig', prop: { fullname: 'Aurelio De Rosa', getFullname: function() { return this.fullname; } } }; console.log(obj.prop.getFullname()); var test = obj.prop.getFullname; console.log(test());
答案:
這段代碼打印結果是:Aurelio De Rosa
和 John Doe
。緣由是,JavaScript中關鍵字this所引用的是函數上下文,取決於函數是如何調用的,而不是怎麼被定義的
。測試
在第一個console.log()
,getFullname()
是做爲obj.prop
對象的函數被調用。所以,當前的上下文指代後者,而且函數返回這個對象的fullname
屬性。相反,當getFullname()
被賦值給test
變量時,當前的上下文是全局對象window
,這是由於test被隱式地做爲全局對象的屬性。基於這一點,函數返回window
的fullname
,在本例中即爲第一行代碼設置的。
修復前一個問題,讓最後一個console.log() 打印輸出Aurelio De Rosa.
答案:
這個問題能夠經過運用call()
或者apply()
方法強制轉換上下文環境。若是你不瞭解這兩個方法及它們的區別,我建議你看看這篇文章 function.call
和function.apply
之間有和區別。 下面的代碼中,我用了call()
,但apply()
也能產生一樣的結果:
console.log(test.call(obj.prop));
var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', function() { console.log('You clicked element #' + i); }); }
請問,若是用戶點擊第一個和第四個按鈕的時候,控制檯分別打印的結果是什麼?爲何?
答案:
概念:閉包(Closures)。對於每個JavaScript開發者來講,若是你想在網頁中編寫5行以上的代碼,那麼準確理解和恰當使用閉包是很是重要的。若是你想開始學習或者只是想簡單地溫習一下閉包,那麼我強烈建議你去閱讀 Colin Ihrig 這個教程:JavaScript Closures Demystified
也就是說,代碼打印兩次You clicked element
#NODES_LENGTH
,其中NODES_LENGTH
是nodes
的結點個數。緣由是在for循環完成後,變量i的值等於節點列表的長度。此外,由於i在代碼添加處理程序的做用域中,該變量屬於處理程序的閉包
。你會記得,閉包中的變量的值不是靜態的,所以i的值不是添加處理程序時的值(對於列表來講,第一個按鈕爲0,對於第二個按鈕爲1,依此類推)。在處理程序將被執行的時候,在控制檯上將打印變量i的當前值,等於節點列表的長度。
修復上題的問題,使得點擊第一個按鈕時輸出0,點擊第二個按鈕時輸出1,依此類推。
有多種辦法能夠解決這個問題,下面主要使用兩種方法解決這個問題。
第一個解決方案使用當即執行函數表達式(IIFE)再建立一個閉包,從而獲得所指望的i的值。實現此方法的代碼以下:
var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', (function(i) { return function() { console.log('You clicked element #' + i); } })(i)); }
另外一個解決方案不使用IIFE,而是將函數移到循環的外面。這種方法由下面的代碼實現:
function handlerWrapper(i) { return function() { console.log('You clicked element #' + i); } } var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', handlerWrapper(i)); }
寫一個isPrime()函數,當其爲質數時返回true,不然返回false。
答案:
我認爲這是面試中最多見的問題之一。然而,儘管這個問題常常出現而且也很簡單,可是從被面試人提供的答案中能很好地看出被面試人的數學和算法水平。
首先, 由於JavaScript不一樣於C或者Java,所以你不能信任傳遞來的數據類型。若是面試官沒有明確地告訴你,你應該詢問他是否須要作輸入檢查,仍是不進行檢查直接寫函數。嚴格上說,應該對函數的輸入進行檢查。
第二點要記住:負數不是質數。一樣的,1和0也不是,所以,首先測試這些數字。此外,2是質數中惟一的偶數。沒有必要用一個循環來驗證4,6,8。再則,若是一個數字不能被2整除,那麼它不能被4,6,8等整除。所以,你的循環必須跳過這些數字。若是你測試輸入偶數,你的算法將慢2倍(你測試雙倍數字)。能夠採起其餘一些更明智的優化手段,我這裏採用的是適用於大多數狀況的。例如,若是一個數字不能被5整除,它也不會被5的倍數整除。因此,沒有必要檢測10,15,20等等。若是你深刻了解這個問題的解決方案,我建議你去看相關的Wikipedia介紹。
最後一點,你不須要檢查比輸入數字的開方還要大的數字。我感受人們會遺漏掉這一點,而且也不會由於此而得到消極的反饋。可是,展現出這一方面的知識會給你額外加分。
如今你具有了這個問題的背景知識,下面是總結以上全部考慮的解決方案:
function isPrime(number) { // If your browser doesn't support the method Number.isInteger of ECMAScript 6, // you can implement your own pretty easily if (typeof number !== 'number' || !Number.isInteger(number)) { // Alternatively you can throw an error. return false; } if (number < 2) { return false; } if (number === 2) { return true; } else if (number % 2 === 0) { return false; } var squareRoot = Math.sqrt(number); for(var i = 3; i <= squareRoot; i += 2) { if (number % i === 0) { return false; } } return true; }