英文原文:http://devign.me/javascript-this-keyword/
什么是this
Javascript的this关键字是很容易理解混乱的。javascript的this关键字的定义是——调用这个函数的那个对象。this用于任何一个函数的作用域或者全局域,在每一个作用域接收一个不同的值。位于一个函数内部的this,它的值依赖于调用这个函数的对象,也就是说调用对象的不同,this的值也不同。
作用域是什么呢?每个函数有它自己的空间定义变量和属性,当访问一个变量时,必须通过定义这个变量的空间。在javascript中,当没有定义一个函数时,则任何事情都发生在全局域。
var o={};//声明一个对象
o.name = "moon";
o.method = function(){
alert(this.name);
};
o.method();
我们定义了一个对象o,和一个方法用来显示this.name,但是this来自哪里呢?
通过调用函数o.method(),我们得到值"moon",其发生的过程是这样的:
1. 创建了一个string类型的变量,其值为"moon", 并且将这个name的属性赋予o;
2. 创建一个方法,并且将此方法赋予给了o;
3. 调用这个方法,o就是调用这个方法的对象;
4. 方法调用时,this实际就是o的一个参考,得到o.name就是moon;
函数其实也是一个普通意义上的变量,它包含了一个表达式,这些表达式在函数被调用时执行。将method方法赋予o的属性,并不使得this就与o连接。对象并不知道这个函数内的内容,this实际赋值是在这个函数被真正调用的时候,这时this被赋值为调用这个函数的对象,即o。
我们将之修改的更复杂点:
var o={};
o.name = "moon";
o.method = function(){
alert(this.name);
};
var x={};
x.name = "sun";
x.method = o.method;
x.method();
上面定义了一个新的对象x,并且给它name的属性赋值为sun;将o的method的方法赋予x的method的属性。程序运行的结果是没有得到“moon",我们得到的值是sun,因为x是抵调用函数method的对象,所以this的值是x,而不是o.
我们可以说每一个javascript的函数都都有一个隐藏的参数叫this,可以更深地理解为每次调用函数的时候,都有一个this参数传递给这个函数,这个this就是调用这个函数的对象。
function f(){alert(this.name);}; 变成 function f(this){alert(this.name);};
var o={}; o.name = "moon" o.method = function(this) { alert(this.name); }; o.method(o); var x={}; x.name = "sun"; x.method = o.method; x.method(x);
改变this的值
javascript提供了两个函数可以方便地改变this的值,这两个函数时call和apply. 这两个函数很相似,他们都是一个函数方法(在Function.prototype定义),他们都有一个参数定义this的对象,同时也包含了函数调用的参数。两者不同的地方时参数传递的方式,call就是普通的参数传递,有几个参数就传递几个参数,apply只传递一个包含这些参数的数组;
将上面的代码该成call的调用:
var o={}; o.name = "moon"; o.method = function() { alert(this.name); }; var x={}; x.name = "sun"; o.method.call(x);
上面这段代码背后是什么呢,相当于
x.temporarymethod = o.method; x.temporarymethod();
this的值是x,它的输出是sun;
this和new 操作符
一个javascript函数不仅仅是一组稍后使用的状态,它其实也是一个类。没一个函数都可以看做是一个类。我们可以创建一个类的实例:
function Foo(name) { this.name = name; }
这个函数像所有的函数一样也是一个类,因此可以创建它的一个实例
var instance = new Fool("bar"); alert(instance.name);//bar
当调用new Foo("bar")时,后面实际发生了什么呢?
var instance={}; Foo.call(instance,name);
调用构造函数将执行表达式
this.name = name;
编译器创建了一个新的,空的对象,并且用call激活了类的构造函数。这样this就是新创建的对象的引用,构造函数执行表达式,返回新的对象。this和prototype
prototype是类的一个属性,不论给他赋予什么值,这个值对类的所有实例都是有效的。当访问一个对象属性,会首先检查对象是不是已经存在这个属性,如果不存在,这个值就会被赋予给这个对象所属的类(这个对象最基础的类);
javascript有一些预定义好的类:Object, Function, String, Number, Array, Date, Math, Error, RegExp
我们可以用我们自己的方法扩展这个任何的类,然后这个类的每个实例都包含了我们的扩展。
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g,""); } var s = " x "; alert("<"+s+">"); alert("<"+s.trim()+">");
上面给string类扩展了一个trim的方法,其功能是删除字符串从头到位的空白。我们可以从任何字符串方法这个方法,this将包含string的值,因为string变量就是调用这个函数的对象。this和DOM
<div id="div" οnclick="alert(this.innerHTML);">div</div>
DOM能够理解这段代码为:
div.οnclick=function () { alert(this.innerHTML); };
onclick定义为一个属性,它的值是一个函数。浏览器会应用一个监听器给鼠标点击动作。一旦click收到,它会检查他的位置是否是在div,然后检查div是否有onclick属性,然后调用这个方法:
div.onclick(event);
因此this就是div的引用。