js this详解
This的定义:
它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象,
这说明this关键字只与函数的执行环境有关,而与声明环境没有关系。下面通过例子来讲解。
例子1:
function a(){ var user = "哈哈哈"; console.log(this.user); //undefined console.log(this); //Window } a();
既然this的最终指向的是那个调用它的对象,a()的执行就相当于window.a(),所以this指向window.
例子2:
var o = { user:"哈哈哈", fn:function(){ console.log(this.user); //哈哈哈 } } o.fn();
这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁。
例子3:
var o = { a:’哈哈哈’, b:{ a:’呵呵呵’, fn:function(){ console.log(this.a); //呵呵呵 } } } o.b.fn();
如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象(不管有没有this要的东西,没有就输出undefined)。
例子4:
var o = { a:’哈哈哈’, b:{ a:’呵呵呵’, fn:function(){ console.log(this.a); //undefined console.log(this); //window } } } var j = o.b.fn; j();
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn。
例子5:
var id = 'windowId'; document.getElementById('myDiv').onclick = function() { console.log(this.id); //输出myDiv function fn(){ console.log(this.id); //输出windowId }; fn(); //普通函数调用 };
这里补充下:不管函数处于什么样的执行环境,只要是当普通函数调用,this就指向windows.
例子6:
var a=function(){ console.log(this)//window } var o={ name:'小白菜', b:function(fn){ console.log(this);//{name:'小白菜',b:f(fn)} fn() a(); } } o.b(function(){ console.log(this)//window })
这个例子是我之前的面试题目,也是因为它而让我想写这篇文章。我想大家看到这里大概明白b函数里面的this,就是指向它的执行环境o。迷糊的估计是fn()和a()的输出。其实简单理解就像例5我所说的,不管处于什么样的环境下,只要当普通函数调用就指向window。硬要说个理由,就像开头所说的:this的最终指向的是那个调用它的对象。本例子fn()=window.fn()。
补充1:
1、 function fn() { this.name = '哈哈哈'; return {}; } var a = new fn(); console.log(a.name ); //undefined 2、 function fn() { this.name = '哈哈哈'; return function(){}; } var a = new fn(); console.log(a.name ); //undefined 3、 function fn() { this.name = '哈哈哈'; return 1; } var a = new fn(); console.log(a.name ); //哈哈哈 4、 function fn() { this.name = '哈哈哈'; return undefined; } var a = new fn(); console.log(a.name ); //哈哈哈 5、 function fn() { this.name = '哈哈哈'; return null; }var a = new fn; console.log(a.name ); //哈哈哈
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
补充2:
this一般指向的是当前被调用者,但也可以通过其它方式来改变它的指向,为什么要改变向上下文呢?主要是为了实现一种情况,当一个对象没有某个方法的时候,而且另外一个对象却有这个方法,这个时候就可以通过改变上下文来使用自己没有的方法了。
如下面的例子:
var obj1 = { name: '111' } var obj2 = { name: '222' } window.name = 'window'; var getName= function(a,b) { alert(this.name); alert(a); alert(b); } getName();//window,undefined,undefined; getName.call(obj1,'a','b');//111,a,b getName.apply(obj2,['a','b']);//222,a,b
obj1没有showName()方法,obj2有,这个时候可以这个样子使用,var temp=obj1.prototype.call(obj2);这样就可以用obj2的方法了。
那什么时候用call什么时候用apply?
当参数个数是固定不变的时候可以用call,当参数个数不确定可以用apply,把要传递的参数push到一个数组里面然后传递给函数,不清楚call和apply可以猛戳百度。
如想了解this的作用可阅读《this的作用》这篇文章。