問題1: 範圍(Scope) 思考以下代碼: 控制台會列印出什麼? 答案 上述代碼會列印出5。 (1)在立即執行函數表達式(IIFE)中,有兩個命名,但是其中變數是通過關鍵詞var來聲明的。這就意味著a是這個函數的局部變數。與此相反,b是在全局作用域下的。 (2)在函數中他沒有使用_“嚴格模式”_ ...
問題1: 範圍(Scope)
思考以下代碼:
(function() { var a = b = 5; })(); console.log(b);
控制台會列印出什麼?
答案
上述代碼會列印出5
。
(1)在立即執行函數表達式(IIFE)中,有兩個命名,但是其中變數是通過關鍵詞var
來聲明的。這就意味著a
是這個函數的局部變數。與此相反,b
是在全局作用域下的。
(2)在函數中他沒有使用_“嚴格模式”_ ('use strict';
)。如果 嚴格模式開啟,那麼代碼就會報出未捕獲引用錯誤(Uncaught ReferenceError):b沒有定義。
// 嚴格模式寫法 (function() { 'use strict'; var a = window.b = 5; })(); console.log(b);
問題2: 創建 “原生(native)” 方法
在String
對象上定義一個repeatify
函數。這個函數接受一個整數參數,來明確字元串需要重覆幾次。這個函數要求字元串重覆指定的次數。舉個例子:
console.log('hello'.repeattify(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
這個屬性。這也驗證了開發人員是否有能力擴展原生數據類型的功能(雖然不應該這麼做)。
這個問題的另一個重點是驗證你是否意識到並知道如何避免覆蓋已經存在的函數。這可以通過在自定義函數之前判斷該函數是否存在來做到。
String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};
當你需要為舊瀏覽器實現向後相容的函數時,這一技巧十分有用。
問題3: 變數提升(Hoisting)
執行以下代碼會有什麼結果?為什麼?
function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test();
答案
這段代碼的執行結果是undefined
和 2
。
這個結果的原因是,變數和函數都被提升了(hoisted)。因此,在a
被列印的時候,它已經在函數作用域中存在(即它已經被聲明瞭),但是它的值依然是 undefined
。換言之,上述代碼和以下代碼是等價的。
function test() { var a; function foo() { return 2; } console.log(a); console.log(foo()); a = 1; } test();
問題4: this
在javascript中是如何工作的
以下代碼的結果是什麼?請解釋你的答案。
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
關鍵詞所引用對象,是依賴於函數是如何被調用的,而不是依賴於函數如何b被定義的。
在第一個console.log()
調用中, getFullname()
是作為obj.prop
的函數被調用的。因此,這裡的上下文環境指向後者並且函數返回this
對象的 fullname
屬性。相反,當 getFullname()
被賦為test
變數的值時,那個語境指向全局對象(window
)。這是因為,test
被隱式設置為全局對象的屬性。因此,函數調用返回window
的fullname
屬性值,在此段代碼中,這個值是通過第一行賦值語句設置的。
問題5: call()
和 apply()
修複上一個問題,讓最後一個console.log()
列印出 Aurelio De Rosa
。
答案
要解決這個問題,可以通過為函數call()
或者apply()
強制函數調用的上下文環境。在以下代碼中,我會用call()
,但是在這裡,用apply()
也可以獲得相同的結果:
console.log(test.call(obj.prop));