? ?? ?關(guān)于js中的this指向問題:有很多同學(xué)剛接觸js時,對this的指向問題很是迷惑,在有些不常見情況产禾,往往搞不清到底指向誰排作。對此,我們只需記住一點:this始終指向調(diào)用它的對象亚情。廢話少說妄痪,下面直接通過不同情況下的實例來說明其指向問題。
? ?? ?1楞件、對象中的方法中的this衫生,指向調(diào)用它的對象,即 b ,所以 this.a 的輸出結(jié)果是b對象中的a的值土浸; 如果b對象中沒有a罪针,則this.a的輸出結(jié)果是 undefined。
var o = {
a: 10,
b: {
a: 12,
fn: function(){
console.log(this.a); // 輸出結(jié)果是 12
console.log(this); // 輸出結(jié)果是 b 對象
}
}
}
//調(diào)用
o.b.fn();
var o = {
a: 10,
b: {
fn: function(){
console.log(this.a); // undefined
console.log(this); // b對象
}
}
}
//調(diào)用
o.b.fn();
2黄伊、改變調(diào)用方法泪酱,不直接調(diào)用:改用賦值后調(diào)用,此時this的指向為window还最,所以this.a的輸出結(jié)果為 undefined墓阀,因為全局中沒有全局變量a。
var o = {
a: 10,
b: {
a: 12,
fn: function(){
console.log(this.a); //undefined 若在對象o外定義a拓轻,則輸出的就是其在外定義的值(全局變量)
console.log(this); // window
}
}
}
var j = o.b.fn; //只是將b對象下的方法賦值給j斯撮,并沒有調(diào)用
j(); //調(diào)用,此時綁定的對象是window,并非b對象直接調(diào)用
3扶叉、在對象方法中調(diào)用時:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
console.log(this.x); // 1
console.log(this.y); // 1
}
};
point.moveTo(1, 1)//this 綁定到當(dāng)前對象吮成,即 point 對象
4、作為函數(shù)調(diào)用時
function someFun(x) {
this.x = x;
}
someFun(5); //函數(shù)被調(diào)用時辜梳,this綁定的是全局對象 window,相當(dāng)于直接聲明了一個全局變量x粱甫,并賦值為5
console.log(x); // x 已經(jīng)成為一個值為 5 的全局隱式變量
更復(fù)雜一點的情況:如下所示,point對象中的x作瞄、y沒有被改變茶宵,并結(jié)果中多了兩個新的全局變量x,y,值都為1宗挥。根本原因是point對象下的moveTo方法中的moveX與moveX方法在調(diào)用時都是全局調(diào)用乌庶,綁定的對象都是window。
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// 內(nèi)部函數(shù)
var moveX = function(x) {
this.x = x;
};
// 內(nèi)部函數(shù)
var moveY = function(y) {
this.y = y;
};
moveX(x); // 這里是全局調(diào)用
moveY(y);
};
};
point.moveTo(1, 1);
console.log(point.x); // 0
console.log(point.y); // 0
可以通過下面情況輸出結(jié)果說明:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = x;
console.log(this.x); // 1
console.log(this); // point對象
// 內(nèi)部函數(shù)
var moveX = function(x) {
this.x = x;
};
// 內(nèi)部函數(shù)
var moveY = function(y) {
this.y = y;
}
moveX(x); // 這里是全局調(diào)用
moveY(y);
}
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 0
console.log(x); // 1
console.log(y);// 1
像如上對象中函數(shù)方法所示契耿,本意是改變point對象中的x瞒大、y的值,而非新建全局變量搪桂。所以可以通過以下方法避免上述情況:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this; //內(nèi)部變量替換
// 內(nèi)部函數(shù)
var moveX = function(x) {
that.x = x;
// this.x = x;
};
// 內(nèi)部函數(shù)
var moveY = function(y) {
that.y = y;
// this.y = y;
}
moveX(x); //這里依然是全局調(diào)用透敌,但是在給變量賦值時盯滚,不再是this指向,而是that指向酗电,而that指向的對象是 point魄藕。
moveY(y);
}
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 1
console.log(x) // 報錯 x is not defined
console.log(y) //
另附將moveX、moveY由內(nèi)部函數(shù)改為非內(nèi)部函數(shù)后的一種情況示例:這種情況下moveX撵术、moveY方法的調(diào)用時綁定在moveTo對象上的背率,因為moveTo對象一開始是沒有x、y變量的嫩与,所以執(zhí)行 this.x = x寝姿、this.y = y之后,相當(dāng)于在moveTo對象中新建了兩個變量划滋。
var point = {
x : 0,
y : 0,
moveTo : {
// 內(nèi)部函數(shù)
moveX: function(x) {
console.log(this) // {moveX: ?, moveY: ?}
this.x = x;
},
// 內(nèi)部函數(shù)
moveY: function(y) {
this.y = y;
}
}
};
point.moveTo.moveX(1);
point.moveTo.moveY(1);
console.log(point.moveTo); // {moveX: ?, moveY: ?, x: 1, y: 1}
console.log(point.x); // 0
console.log(point.y); // 0
console.log(x) // x is not defined
console.log(y) //
5饵筑、作為構(gòu)造函數(shù)調(diào)用:
function Point(x, y){
console.log(this); // point對象
this.x = x;
this.y = y;
this.moveTo = function(x,y){
this.x = x;
this.y = y;
console.log(this.x);//1 10
console.log(this.y);//1 10
}
}
var p1 = new Point(0,0); //注意這種形式方法的調(diào)用及apply、call的使用
var p2 = {
x:0,
y:0
}
p1.moveTo(1,1);
p1.moveTo.apply(p2,[10,10]);
console.log(x);// x is not defined
console.log(y);//
6古毛、this在不同場景中的指向
? ?? ?①匿名函數(shù)中的this指向全局對象
var a = 10;
var foo = {
a: 20,
fn: (function(){
console.log(this); // window
console.log(this.a); // 10
})()
}
? ?? ?②setInterval和setTimeout定時器中的this指向全局對象
var a = 10;
var oTimer1 = setInterval(function(){
var a = 20;
console.log(this.a); // 10
clearInterval(oTimer1);
},100);
? ?? ?③eval中的this指向調(diào)用上下文中的this
(function(){
eval("console.log(this)"); // Window
})();
function Foo(){
this.bar = function(){
eval("console.log(this)"); // Foo
}
}
var foo = new Foo();
foo.bar();
? ?? ?④apply和call中的this指向參數(shù)中的對象
var a = 10;
var foo = {
a: 20,
fn: function(){
console.log(this.a);
}
};
var bar ={
a: 30
}
foo.fn.apply();//10(若參數(shù)為空翻翩,默認(rèn)指向全局對象)
foo.fn.apply(foo);//20
foo.fn.apply(bar);//30
附:eval都许、apply稻薇、call方法的說明:
eval() 函數(shù)可計算某個字符串,并執(zhí)行其中的的 JavaScript 代碼胶征。
call 塞椎、apply 這個兩個函數(shù)的第一個參數(shù)都是 this 的指向?qū)ο螅诙€參數(shù)的區(qū)別如下:
call的參數(shù)是直接放進去的睛低,第二第三第n個參數(shù)全都用逗號分隔案狠,直接放到后面 obj.myFun.call(db,'params1', ... ,'paramsn' );
apply的所有參數(shù)都必須放在一個數(shù)組里面?zhèn)鬟M去 obj.myFun.apply(db,['params1', ..., 'paramsn' ]);
以上钱雷。
參考鏈接:
1骂铁、https://www.jb51.net/article/62166.htm
2、https://www.jb51.net/article/72146.htm