JS中this的指向
【成都小課堂】
1.背景介紹
2.知識剖析
3.常見問題
4.解決方案
5.編碼實戰
6.擴展思考
7.參考文獻
8.更多討論
1.背景介紹
this是Javascript語言的一個關鍵字。它代表函數運行時,自動生成的一個內部對象。
this是動態綁定的,它可以是全局對象、當前對象或者任意對象(這取決于函數的調用方式)。這就導致了this具備了多重含義,可以使得javascript更靈活的使用。但是,帶來了靈活性的同時也會給我們初學者帶來不少困惑。
2.知識剖析
全局環境中的this
function test() {
console.log(this);
}
test();
總結:在全局作用域中它的this執行當前的全局對象(瀏覽器端是Window,node中是global)
嚴格模式‘use strict’下的this
'use strict';
function test() {
console.log(this);
};
test();
// undefined
原因:this并不會指向全局,而是undefined,這樣的做法是為了消除js中一些不嚴謹的行為。
在javascritp中,不一定只有對象方法的上下文中才有this, 全局函數調用和其他的幾種不同的上下文中也有this指代。 它可以是全局對象、當前對象或者任意對象,這完全取決于函數的調用方式。JavaScript中函數的調用有以下幾種方式:作為對象方法調用,作為函數調用,作為構造函數調用,和使用apply或call調用。
1.作為對象方法調用:this被自然綁定到該對象,也就是說this就指這個上級對象
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};
point.moveTo(1, 1)//this綁定到當前對象,即point對象
2.作為函數調用:this被綁定到全局對象
function makeNoSense(x) {
this.x = x;
}
makeNoSense(5);
x;// x已經成為一個值為5的全局變量
3.作為構造函數調用:this綁定到新創建的對象上,也就是說this就指這個新對象
function Point(x, y){
this.x = x;
this.y = y;
}
注:構造函數不使用new調用,則和普通函數一樣。一般地,構造函數首字母大寫
4.使用apply或call調用:在JavaScript中函數也是對象,對象則有方法,apply和call就是函數對象的方法。
function Point(x, y){
this.x = x;
this.y = y;
this.moveTo = function(x, y){
this.x = x;
this.y = y;
}
}
var p1 = new Point(0, 0);
var p2 = {x: 0, y: 0};
p1.moveTo(1, 1);
p1.moveTo.apply(p2, [10, 10]);
3、常見問題
問題一
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
setTimeout(this.foo, 1000);
}
}
obj.foo2();
現象:兩次打印的this不一樣
問題二
'use strict';
function foo() {
console.log(this);
}
setTimeout(foo, 1);
// window
現象:加了嚴格模式,foo調用也沒有指定this,應該是出來undefined,但是這里仍然出現了全局對象
4、解決方案
問題一起因是因為 setTimeout() 將 this.foo 作為了自身的參數,這時候 this.foo 是作為一個fun參數去獲取全局的變量了。
可以這么這么解決:利用閉包的特性來處理
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
var _this = this;
setTimeout(function() {
console.log(this); ?// Window
console.log(_this); ?// Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
可以看到直接用this仍然是Window;因為foo2中的this是指向obj,我們可以先用一個變量_this來儲存,然后在回調函數中使用_this,就可以指向當前的這個對象了
問題二
setTimeout方法在調用傳入函數的時候,如果這個函數沒有指定了的this,那么它會做一個隱式的操作—-自動地注入全局上下文,等同于調用foo.apply(window)而非foo();
5、編碼實戰
對于內部函數,即聲明在另外一個函數體內的函數,這種綁定到全局對象的方式會產生另外一個問題。我們仍然以前面提到的point對象為例,這次我們希望在moveTo方法內定義兩個函數,分別將x,y坐標進行平移。結果可能出乎大家意料,不僅point對象沒有移動,反而多出兩個全局變量x,y
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
//內部函數
var moveX = function(x) {
this.x = x;//this綁定到了哪里?
};
//內部函數
var moveY = function(y) {
this.y = y;//this綁定到了哪里?
};
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>0
point.y; //==>0
x; //==>1
y; //==>1
這屬于JavaScript的設計缺陷,正確的設計方式是內部函數的this應該綁定到其外層函數對應的對象上,為了規避這一設計缺陷,聰明的JavaScript程序員想出了變量替代的方法,約定俗成,該變量一般被命名為that。
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this;
//內部函數
var moveX = function(x) {
that.x = x;
};
//內部函數
var moveY = function(y) {
that.y = y;
}
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>1
point.y; //==>1
6.擴展思考
問題:如何理解this?
當一個函數被調用時,擁有它的object會作為this傳入。在全局下,就是window or global,其他時候就是相應的object。 也可以看到,call和apply就是利用這一點實現更改this值的
7.參考文獻
8、更多討論
this含義為何如此豐富?
理解this的指向有何意義?
小課堂視頻:
------------------------------------------------------------------------------------------------------------------------
技能樹.IT修真院
“我們相信人人都可以成為一個工程師,現在開始,找個師兄,帶你入門,掌控自己學習的節奏,學習的路上不再迷茫”。
這里是技能樹.IT修真院,成千上萬的師兄在這里找到了自己的學習路線,學習透明化,成長可見化,師兄1對1免費指導。快來與我一起學習吧 !