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免费指导。快来与我一起学习吧 !