JavaScript是个有点神奇的语言,不过它的一些独有的特性往往让我们初学者感到费解。This是Javascript语言的一个关键词。不过它到底是指什么呢?很多人都会认为this指的是当前对象。当然,这样理解是没错的,但是在有些情况下仍然会有些问题。在此,我搜集了一些资料,重新学习并整理一下,希望能借此来更好的理解this在JS中的工作方式和使用方法。
-
var test = function(){
-
alert(this);
-
}
-
test();
-
new test();
运行以上代码,你会发现test()和new test()的运行结果是不一样的,test()指向的是Windows对象而new test()才是指向test对象,为什么会有两种不同的运行结果?其实这里就涉及到一个变量作用域的问题,而变量作用域同时又牵涉到闭包(Closure)这个JS特性了,正因为闭包的存在,理解变量作用域就显得非常重要。
关于变量作用域
接着先来介绍一下所谓的变量作用域,概念非常简单,每个变量都有自己的作用域,即变量在这么一个区域中可以被识别,而出了此区域就没有任何作用了。作用域就两种:全局作用域和局部作用域。
全局变量在JavaScript中处处都有定义,它贯穿在一个全局对象中,因此可以在任何地方使用。而局部变量则只在一个函数中有定义。其中要注意到的一点就是:JavaScript无块级作用域,这有别于C++和Java。因此任何变量在定义它的整个函数体中都能被识别。
-
var a=123;
-
function fun1(){
-
alert(a);
-
}
-
-
fun1(); // 123
很简单,函数内部可以直接读取全局变量;
-
function fun2(){
-
var a=123;
-
}
-
-
alert(a); // error
在函数外部当然无法读取函数内的局部变量。
-
var s="oo";
-
-
function fun3(){
-
alert(s); // undefined
-
-
var s ="xx";
-
-
alert(s); // xx 因为javascript无块级作用域,s在此被初始化,整个函数中都有定义
-
}
-
-
fun3();
以上代码其实就相当于
-
function fun3(){
-
var s;
-
alert(s);
-
-
s = "xx";
-
alert(s);
-
}
-
-
fun3();
另外大家要注意的一点就是,在函数内部声明变量的时候,如果不用var命令,这样其实就相当声明了一个全局变量。
关于闭包
了解过变量作用域之后,对于理解闭包就有很大的帮助了。当我们需要得到函数内的局部变量的时候,就需要在函数的内部再定义一个函数。
-
function fun1(){
-
var a = 123;
-
function fun2(){
-
alert(a); //123
-
}
-
}
fun2可以访问fun1所有的局部变量,因此我们只要把fun2作为返回值,就可以在fun1外部读取到它的内部变量了。
-
function fun1(){
-
var a = 123;
-
function fun2(){
-
alert(a); //123
-
}
-
-
return fun2;
-
}
-
-
var result = fun2();
-
result();
因此,有了闭包将联系函数内外联系起来,我们就可以从函数外读取到函数内部的变量了,另外由于JavaScript作用域的机制,闭包只能读取到包含函数中任何变量的最后一个值。
这里引用一个例子:
-
function createFunctions(){
-
var result = new Array();
-
-
for (var i=0; i < 10; i++){
-
result[i] = function(){
-
return i;
-
};
-
}
-
-
return result;
-
}
-
-
var funcs = createFunctions();
-
-
for(var i=0; i < funcs.length; i++){
-
alert(funcs[i]()); //每次都显示10
-
}
因为每个函数作用域中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i,当createFunctions()函数返回后,变量i的值是10,因此每个函数都引用着保存变量i的同一个变量对象,所以每个函数内部i的值都是10。我们要稍微改写一下函数,让它符合我们的预期要求。
-
function createFunctions(){
-
var result = new Array();
-
-
for (var i=0; i < 10; i++){
-
result[i] = function(num){
-
return num;
-
}(i);
-
}
-
-
return result;
-
}
-
-
var funcs = createFunctions();
-
-
for(var i=0; i < funcs.length; i++){
-
alert(funcs[i]); //每次都显示10
-
}
这里,我们通过定义一个匿名函数,并立即执行该匿名函数的结果赋给数组,这里的匿名函数只有一个参数num,也就是最终要返回的值。在调用每个匿名函数时,我们传入了变量i,通过变量i的将当前值赋给参数num,这样就获得我们所要的结果。
清楚了作用域和闭包之后,对于this就能很快理解了。先来看下面这段代码:
-
function test1{
-
this.x = 123;
-
alert(this.x);
-
}
-
-
test1(); //123
当前的this就是全局对象,稍作变化,效果一样。
-
var x = 1;
-
function test(){
-
this.x = 0;
-
}
-
alert(x); //1
-
-
test();
-
alert(x); //0
再看如下代码:
-
var oo = new Object;
-
-
oo.x = 1;
-
-
function test2(){
-
-
alert(this.x);
-
-
}
-
-
oo.fun = test2;
-
-
oo.fun(); // 1
这里的this就指当前调用该方法的对象。
对于开头这段代码来说,test()函数是在全局作用域下的(在这里其实就是window对象),所以this的值是当前的window对象。而通过 new test()其实是作为构造函数来调用的,就是通过这个函数来生成一个新的对象,所以这里的this就指的是这个新对象。
-
var xx = 2;
-
-
function test3(){
-
-
this.xx = 1;
-
-
}
-
-
var oo = new test3();
-
alert(oo.xx); //1
-
alert(xx); //2
以上例子可证明this并不是全局对象,因为xx的值并没有改变。最后在网上看到两段例子,对于理解this和闭包有很大的帮助,在此引用过来。
代码一
-
var name = "The Window";
-
-
var object = {
-
name : "My Object",
-
-
getNameFunc : function(){
-
return function(){
-
return this.name;
-
};
-
-
}
-
-
};
-
-
alert(object.getNameFunc()());
代码二
-
var name = "The Window";
-
-
var object = {
-
name : "My Object",
-
-
getNameFunc : function(){
-
var that = this;
-
return function(){
-
return that.name;
-
};
-
-
}
-
-
};
-
-
alert(object.getNameFunc()());
由于本人水平有限,此文也算是我最近学习过程中的一个小结吧,若有不当之处,还望大家指正。

Post a comment