this对象真的是有时让我们头疼,我们真是分不清它到底指向哪个作用域,它有时的指向真的是不可思议,它本应该这样指向却那样指向。
虽然有这么句话,this是调用执行当前代码的对象的所有者,也就是谁调用它,它就指向谁,那问题来,如果我们分不清谁调用的它,那怎么办呢?
理论部分:
0X00:
js中的圣经红宝书和犀牛书对这部分说的很少,但是很精辟;要真正的深刻理解书上说的,那么你对this就一点也不难,但是像我这种菜鸟怎么可能理解呢???
红宝书:
this引用的是函数据以执行的环境对象,this对象是在运行时基于函数执行环境绑定的,在全局中,this等于window,当函数被作为木个对象的方法调用时,this等于那个对象,不过,由于匿名函数的执行环境具有全局性,因此,this对象通常指向window,还有就是每个函数在调用的时候都会自动获取两个特殊变量:this和arguments,放在活动对象中,内部在要使用这两个变量时,只是会在本函数的活动对象中搜索,永远不会沿着作用域链访问外面的活动对象。
犀牛书:
this对象没有作用域的限制,嵌套的函数不会从调用它的函数中继承this,如果嵌套函数作为方法调用,其this值指向调用它的对象,如果嵌套函数作为函数调用,其this值不是全局对象(非严格模式)就是undefined(严格模式);很多人误以为调用嵌套函数时this会指向调用外层函数的上下文。
这就是解释的。当你真正理解了this后看这些话,你感觉他们说的this判断就是这么回事很有感觉,但是对于我来说,读过这些话没太有感觉,不理解。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
声明:以下我说的都是在我们判断this对象指向时可以这么想,其他时候你可别这样想呀!有小部分是不太适合的,那样说的话;
我说的都是自己的理解,如果你感觉我说的不对,欢迎指正!
我说的这些例子中有很多是类似的,只是为了让我们加深理解!
0X01:
this往大了说无非就是全局中的和函数(方法)中的,只是这函数(方法)中的太过于复杂;
其实可以大致划分为五类:
- 全局下中【this】
- 函数中调用【foo(foo2(this))】(这里是指在函数中执行的函数即函数嵌套函数)
- 方法调用【obj.foo(this)】(这是是指对象调用函数时)
- 构造函数中【new Foo(this)】
- apply和call中【foo.apply(obj)】
有时候也不好说是在五种的哪一种;只是大致这样吧; 参考:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this
实战部分:
0x00:在全局中的情况
全局中:
0x01:
var a = 1; console.log(this);//window console.log(this.a);//1
这就是全局中的this它是指向window对象的,这种情况很简单
0x01:函数调用中的
如果一个函数的调用者是一个函数,那么那个被调用的函数中的this是指向window的
我们就是在对象的方法里调用函数,有时让我们分不清,其实在this眼里,所有的函数都是跟普通函数差不多;
在javascript语言精粹上说,在此模式中this被绑定到全局对象,这是语言设计上的一个错误。
001:setTimeout和setInterval中的this
这个是要单独拿出来的,他们其实都是来自window的方法,这两个函数不管是在哪里调用,;其执行上下文环境是window对象下的环境;
var num = 1; var obj = { num:2, show:function() { console.log(this.num); }, showNum:function() { setTimeout(this.show,1000); } }; obj.showNum();//1
参数中的this是传递引用的过来的,是和showNum中的this是一样的,其实这个this不是重点,在这里,show方法里面的this才是重点
我的理解是当程序执行到setTimeout的时候通过this.show获取对obj对象中show函数引用,show函数里面的this应该指向谁呢?(你不要误认为这个方法定义在obj中就和obj有关系(确实有关系,但是在this对象看来:函数定义在哪里都一样,在它看来你们都是一个个孤立的函数,就看你是在哪里调用的),你就记住这句话:在this对象看来:函数不管定义在哪里,都是一样的,没有区别,不管你是在对象中还是函数中,还是全局中的,都是一样的,我就是看你在哪里调用了,this是和javascript中执行环境有关,而非声明环境有关),
,不要认为show函数是obj的,就和obj有关系,这里就是想当于setTimeout(function(){console.log(this.num)},1000);其实这就是函数中嵌套函数,所以里面的this指向window;如果你感觉setTimeout有特别不和其他函数一样,你就看下面的,一样的,只不过这个是普通函数:
var num = 2; var obj = { num:1, foo2:function() { function foo3(a) { console.log(this);//window console.log(a);//1 } foo3(this.num);//this =>obj } } obj.foo2();
在调用foo3时他参数this就是obj,跟setTimeout中的是一样的;它里面的this也是window,这就是foo3是函数调用的,
002:
var x = 2; var obj = { x:1, a:function () { var x = 3; var b = function () { console.log(this.x); }; b(); } } obj.a();//2
这个和上面那个例子差不多,就是函数中嵌套函数的情况,一定是指向window了
003,简单的:
function foo() { function bar() { alert(this); } bar(); } foo();//window
0x02:方法中的调用
一定指向调用它的那个对象
001:
var num = 1; function foo() { console.log(this.num); } foo();//1
这其实就是window对象下的foo()方法的调用 ==》window.foo();只是在全局下可以省去罢了;
002:
var obj = { num:1, foo:function() { console.log(this.num); } } obj.foo();//1
003:
var obj1 = { num:1, showNum1:function() { console.log(this.num); } }; var obj2 = { num:2, showNum2:obj1.showNum1 } obj2.showNum2();//2
其实obj2等价与这样:
var obj2 = { num:2, showNum2:function(){ console.log(this.num); } }
只不过这个函数我是引用的obj1中的showNum2函数罢了,这样看你就知道了,再次说明了我说setTimeout时所说的,只不过我们showNum2:obj1.showNum1这样用就给我们一种感觉,它就是跟obj1有关系,其实在this看来没有关系,this就是个有奶便是娘的东西,它不管哪个娘生的它,谁是它亲娘(在哪个地方声明(定义)的它),只要给的奶喝,它就认谁为娘(谁执行调用的它);你一定要抛开声明地方不同,对你的影响;
004:
var x= 2; var obj = { x:1, fn:function() { alert(this.x); } }; // obj.fn(); var test = obj.fn; test();//2
也是那种情况,
等价与
var test = function(){ alert(this.x); } test();//2
005:
function foo() { alert(this.bar); } var x = {bar: 10}; var y = {bar: 20}; x.test = foo; y.test = foo; x.test(); // 10 y.test(); // 20
006:
var x = 10; var obj = { foo:function() { alert(this.x); }, x:20 }; with(obj) { foo();//20 }
调用foo时就是相当于obj.foo();
007:
var x = 3; var foo = { x:2, baz:{ x:1, bar:function() { return this.x; } } } var go = foo.baz.bar; console.log(go());//3 console.log(foo.baz.bar());//1
这就是变量go引用了函数function(){return this.x};这个就是foo.baz调用了bar()函数所以this指向调用者foo.baz这个对象
008:
function Foo() {} Foo.prototype.method = function() {console.log(this)}; function Bar() {} Bar.prototype = Foo.prototype; var obj = new Bar(); obj.method();//Bar
0x03:构造函数中
function Person() { console.log(this); this.x = 1; } var people = new Person(); console.log(people.x);//10
上面没有显式的创建对象;直接将属性赋值给this对象;没有return语句;
其实在你使用new操作符,调用构造函数其实经历了以下四个过程:
- 自动创建一个对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码
- 把这个新对象返回出去(隐式的return)
其实就是这样差不多:
function person() { var o = {}; o.x = 1; return o; } var people = person(); console.log(people.x);
这个this是有用处的,它可以使每个new实例化的对象都有属于自己的属性,而不全都是从原型中继承而来的。
0x04:apply和call方法中
他们都是在特定作用域中调用函数,实际上等于设置了函数体内的this对象的值,第一个参数在ES3或非严格模式中,传入的的null和undefined都会被全局对象代替,其他的原始值则会被相应的包装对象所代替,在严格模式下,第一个实参是null或undefined时,里面的this就是null或者是undefined,
001:
function f() { console.log(this.x + " " + this.y); } var obj = { x:1, y:2 } f.call(obj);//1 2
这里的this就是obj
002:
function show() { console.log(this); function test() { console.log(this); } test(); } show.call({x:1});//{X:1},window
这里就是首先由于call方法所以改变了作用域,show()函数的this指向了{x:1},test()属于函数调用函数的情况所以是window对象;
上面说的都是javascript语言中this;
现在说说DOM对象中的this
001.
一种是DOM0级事件绑定中的this,
obj.onclick = function () { console.log(this);//obj }
上面说了这么多你,你在看这里为什么这个this是obj你知道了吗?因为当你触发事件的时候,是obj对象就会检测它的onclick属性有没有绑定函数,如果绑定了就调用。
002.
DOM2级中的
先来个这样的:
<script type="text/javascript"> var x = 2; var obj = { x:1, fn:function(f) { f(); } } obj.fn(function(){console.log(this.x);});//2 </script>
它是会显示2的,也就是说这个this是window,和上面我罗嗦了半天的函数调用的情况,函数中调用函数
但是你看这里:
var x = 2; var test = document.getElementById("test"); test.x = 1; test.addEventListener(‘click‘,function() { console.log(this.x);//1 console.log(this);//test对象 });
这是怎么回事???要是按照上面的来应该是window对象呀,这就是addEventListener方法的特别之处,它不是不同的函数呀,简单说这个函数的作用就是把第二个参数的的函数,绑定在调用它的那个对象(这里是test)下的,有跟addEventListener的第一个参数的名字相同的属性名下。就类似这样:
test = { //这里是很多的属性名 //..... //...... click:function(){ console.log(this); } }
这个函数大体就是这个作用;
而IE的attachEvent就跟上面说的就差不多了,它的this是window;
不写了就写这么多吧。总结就是,this是和执行环境有关,不是和声明函数有关,在你用this的时候要小心点,实在不确定是什么,你就alert一下,不就知道了
下面这些是我的参考,我的很多很多例子就是从他们那里的,要不然那么多情况我怎么一时半会也想不出出来呀,他们写的这些都是精化呀,如果你感觉我写的把你搞晕了的话,还没有明白的话,我建议你看看这些,我相信在你看明白这些后你就对this有自己的理解和认识;
javascript秘密花园:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this
大叔的:http://www.cnblogs.com/TomXu/archive/2012/01/17/2310479.html
大额_skylar:http://www.cnblogs.com/skylar/p/4042663.html
http://www.cnblogs.com/justany/archive/2012/11/01/the_keyword_this_in_javascript.html
http://www.cnblogs.com/KevinYang/archive/2009/07/14/1522915.html
http://www.cnblogs.com/rush/archive/2012/07/31/2617429.html
javascript高级程序设计
javascript权威指南