Javascript編程“陷阱”總結
關於this關鍵字
首先看一段代碼:
var obj = {
id: "xyz",
printId: function() {
console.log('The id is '+ this.id + ' '+ this.toString());
}
};
obj.printId(); //The id is xyz [object Object]
var callback=obj.printId;
callback(); //The id is undefined [object global]
setTimeout(obj.printId,1000); //The id is undefined [object Object]
這樣就出現問題了,隻有obj.printId()返回了我們想要的結果,第二種調用隻是個賦值,但this卻指向global,第三種調用,this指向Object,但是顯然不是我們定義的obj,因此它獲取不到id屬性。原因就在於,在javascript中,this關鍵字的指向是在函數調用的時候定義的。callback()在調用的時候,屬於全局頂層的函數,已經不是我們定義的obj中的一個函數,所以this指向global,至於setTimeout的回調函數調用方式之所以指向一個Object,這應該和setTimeout這個api的實現方式有關
那我們有沒有辦法用callback和setTimeout方式顯示出正常結果呢?你可以這樣寫:
obj.printId(); //The id is xyz [object Object]
var callback=function() { obj.printId(); };
callback(); //The id is xyz [object Object]
setTimeout(function() {obj.printId(); },1000); //The id is xyz [object Object]
關於變量作用域
第一個,最簡單的例子:
for(var i = 0; i < 5; i++) {
console.log(i); //0 1 2 3 4
}
第二個,加個異步函數,也很簡單:
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); //5 5 5 5 5
}, 100);
}
第三個,我們製作一個方法數組:
var data = [];
for (var i = 0; i < 5; i++) {
data[i] = function foo() {
console.log(i);
};
}
data[0](); data[1](); data[2](); data[3](); data[4](); //5 5 5 5 5
第一個,如我們所想,輸出0,1,2,3,4;可是第二個第三個都是5,5,5,5,5.
原因分析:我們在for循環中定義的變量i,在for循環結束後還沒有走出它的作用域,也就是說for循環之後,i依然可以訪問,值等於最後一次循環後的值,就是5了。第二段代碼中,setTimeout的回調函數執行時,for循環已經完成,此時i就是5。同理,第三段代碼,在datai執行時,i已經是5了。當然,我們有辦法讓它顯示正確結果,但要增加一個變量,像這樣:
for(var i = 0; i < 5; i++) {
(function() {
var j = i;
setTimeout( function() { console.log(j); }, 500*i); //0 1 2 3 4
})();
}
bonus:在object外麵增加method的方法
var obj1 = { id: "Foo"};
var obj2 = { id: "Bar"};
function f1(a, b) {
console.log(this, a, b);
}
f1.call(obj1, 'A', 'B'); //Object{id:"Foo"} "A" "B"
f1.apply(obj2, [ 'A', 'B' ]); //Object{id:"Bar"} "A" "B"
最後更新:2017-06-23 23:35:15