Q:
-
// (1)这里this指代什么?
-
function a(){
-
// (2)这里this指代什么?
-
var c = 2;
-
function b(){
-
// (3)这里呢?this又指代什么?
-
return c;
-
}
-
return b;
-
}
-
a()(); //调用a()函数会返回一个b函数,a()()表示当返回b函数之后立即执行。
面试官:嗯?是吗?你不好好想想吗?
我的内心:啊啊啊,哪里有洞。。。我是有多菜。
是,你没有看错,我确实是这么回答的,很可笑啊,我一直都觉得这真的是耻辱啊,我想我一辈子都不会忘记。不过,这个面试官很nice,给我道出了正确答案,还告诉我为什么。这场面试下来,我所有的自信心都被摧毁得破碎不堪,但它却是我最有收获的一次面试,也成为我前端路上的一次转折点。
正确的应该是:这三处均指的是window对象。
This,何意?这,这里,这个。在JavaScript中,它是关键字,既不是变量,也不是属性名,所以它是不允许被赋值的。那它是什么关键字呢?在JavaScript中,它指的是函数调用的上下文(context)。
根据ECMAScript3和非严格的ECMAScript5对函数调用的规定,this的值是全局对象。在严格模式下,则是undefined。和变量不同,关键字没有作用域的限制,嵌套函数(闭包)不会从调用它的函数中继承this。若想访问外部函数的this值,需要将它的值保存在一个变量里,这个变量和内部函数都同在一个作用域内。可看下面代码:
-
var o = {
-
m: function(){
-
var self = this;
-
console.log( this === o); // true, this就是这个对象o
-
f();
-
-
// 定义一个嵌套函数f()
-
function f(){
-
console.log( this === o); // false,this的值是全局对象或者undefined
-
console.log(self === o); // true, self值外部函数的this值
-
}
-
}
-
};
-
o.m();
this是在运行时基于函数的执行环境绑定的。在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过,随着函数使用场合不同,this的值可能发生变化。我们知道,在JavaScript中,调用函数有4种方式:
- 普通的函数调用
- 作为对象的方法调用
- 作为构造函数调用
- 通过它们的call()和apply()间接调用
那么就从它的调用方式简单分析一下,如有错误,烦请批评指正:
(1)作为函数
这是最通常的函数用法,属于全局性调用,因此this等于全局对象。
-
function f(){
-
window.x = 1;
-
console.log( this.x);
-
}
-
f(); // 1
对代码做些改变再看,
-
var x = 1;
-
function f(){
-
console.log( this.x);
-
}
-
f(); // 1
-
console.log( window.x); // 1
window.x与this.x值相等。再变一下,
-
var x = 1;
-
function f(){
-
this.x = -1;
-
console.log( this.x);
-
}
-
f(); // -1
-
console.log(x); // -1
在f()中给this.x赋值为-1,结果x的值跟着改变为-1,所以this等于全局对象。
(2)作为方法
当函数作为某个对象的方法调用时,这时this的值就是这个对象。
-
function f(){
-
console.log( this.x);
-
}
-
var o = {
-
x: -1,
-
m: f
-
};
-
o.m(); // -1
-
o.x = 1;
-
o.m(); // 1
对象的属性值改变,f()里面this.x跟着改变。可以在f()里面打印一下this,看看结果呢!
(3)作为构造函数
作为构造函数调用时,使用new关键字初始化一个实例对象,这时this等于这个实例对象。
-
function f(){
-
this.name = "zrn";
-
}
-
var o = new f();
-
console.log(o.name); // "zrn"
运行结果为”zrn”,表示这并非全局对象。变一下代码,
-
var name = "window";
-
function f(){
-
this.name = "zrn";
-
}
-
var o = new f();
-
console.log(o.name); // "zrn"
-
console.log(name); // "window"
name的值互不干涉。
(4)通过call()或者apply()调用
call()和apply()的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this的值。第一个参数(context)是函数运行的作用域,第二个参数是参数数组(argArr),不过使用call()时,要将这些参数逐个列举出来。如果未传递context,则context是全局对象(啊,说的有点多了)。
-
var name = "window";
-
function f(){
-
console.log( this.name);
-
}
-
var o = { name: "zrn"};
-
f.call(); // "window", this指的是window
-
f.apply(o); // "zrn", this指的是对象o
ps: call()和apply()方法是很强大的方法,期待更深入的学习它们。