感谢阮一峰老师:http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html
涉及到的知识点:变量提升
定义:
- 哪个对象调用函数,函数里面的this指向哪个对象。
- this默认指向window(全局)。
- 函数里面也有一个this。
- this在函数执行时才能确定指向谁。
- 闭包中的内函数this默认指向window。
- DOM元素中的事件(onclick、onmousedown等等) this指向这个DOM元素对象。
情景1:
var x = 0;
function test() {
this.x = 2;
alert(window.x)
}
test()
解释:
这里实际上是window调用了test()方法,所以this指的就是window。实际上,上面的代码可以转变为:
var x = 0;
var test = function() { //转换函数
this.x = 2;
alert(window.x)
}
test()
由于test函数在声明时没有在某函数内部声明,所以test函数在用var定义时,属于window对象,再转变一下:
window.x = 0;//因为var定义时,作用域就是window
window.test = function() {
this.x = 2;
alert(window.x)
}
window.test()
这样就清晰了:哪个对象调用函数,函数里面的this指向哪个对象。明显这里是window调用了test方法。
这里有一个知识点需要声明下:在ES5中,若变量没有用var去声明时,默认属于window对象,即以下两个定义是等价:
x = 0; <===> window.x = 0;
test1 = function(){
console.log('1')
}
window.test1 = function(){
console.log('1')
}
情景2:
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m();
以上代码输出什么?
首先:代码我们先转换一下(一步步来)
第一步,修改函数的表现形式:
var test = function() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m(); // 1
第二步,将obj定义的变量提升:
var obj = {};
obj.x = 1;
var test = function() {
console.log(this.x);
}
obj.m = test;
obj.m(); // 1
第三步,obj.m 等价于test函数的右边的function,把test定义去掉,function函数给obj.m:
var obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m(); // 1
调用,显然,调用函数的是obj ,所以this就表示obj,而obj定义了x为1 ,所以输出结果为 1。
情景3:
function test() {
this.x = 1;
}
var obj = new test();
console.log(obj.x) // 1
运行结果为1。为了表明这时this不属于window(全局)对象,我们对代码做一些改变:
var x = 2;
function test() {
this.x = 1;
}
var obj = new test();
console.log(x) // 2
这里我建议一步步来,先进行转换:
window.x = 2;
var test=function() {
this.x = 1;
}
var obj = new test();
console.log(x) // 2
再转:
window.x = 2;
window.test = function() {
this.x = 1;
}
window.obj = new test();
console.log(window.x) // 2 表明全局变量x的值根本没变。
test();//当执行test方法时,实际上是执行了:window.test();执行此函数时,x的值已经改变
console.log(window.x) // 1 这里的x的值,被this.x这一行所改变
所以:哪个对象调用函数,函数里面的this指向哪个对象。
情景4:apply 调用
apply定义:应用某一对象的一个方法,用另一个对象替换当前对象。 //说实话这样不太能理解
看以下代码:
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply() // 0
首页进行变量提升、代码转换,以上代码等价于:
window.x = 0;
window.obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m.apply() // 0
apply()
的参数为空时,默认调用window(全局)对象。
好,继续转换:
window.x = 0;
window.obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m.apply(window) // 0
上面的代码输出为0,我们可以这样理解:
第一步:首先我们不要apply,有了上面的基础我们知道,输出的是1。
window.x = 0;
window.obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m() // 1
第二步:我们加上apply,但是定义说了,如果apply没有参数,默认参数是window(全局)对象,好,我们加上。
这里可见区别在哪,就是多了一个apply,这5个字母,就把函数内的this指给了window(原本是指向obj,因为是obj调用了m函数)。
window.x = 0;
window.obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m.apply(window) // 实际上和obj.m.apply()等价
第三步:这次我们把apply的参数改一下,把m函数内的this指向obj本身,应该怎么做?没错,就是把obj放进去替换window(全局)对象:
window.x = 0;
window.obj = {};
obj.x = 1;
obj.m = function() {
console.log(this.x);
}
obj.m.apply(obj) // 输出1
情景5: 匿名函数
定义:在函数表达式中,创建一个函数并将它赋值给一个变量,若此时function关键字后没有标识符,那么创建的函数可称为匿名函数:
var a=function(){ return 1 };
1. 无论在何种情况下,匿名函数中的this永远指向的是window。
2.前提是不要放到window.onload,window.ready 函数下,否则this的指向就会发生变化。