javascript中让你捉摸不定的this

this到底指向谁,估计很多人在使用javascript的过程中都遇到过,这个关键字如果没搞懂,在一些高级功能中都会困难重重,搜了下相关文章,介绍的都挺多的,也有很深入的,比如汤姆大叔的《深入理解javascript系列》文章。看到很多文章中提到一句话:"this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁实际上this的最终指向的是那个调用它的对象"。

《javascript设计模式与实践》中是这样说的:javascript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境

除去不常用的with和eval,实际应用中,this的指向大致分为下面4种情况:

1、作为对象的方法调用。

2、作为普通函数调用。

3、构造器函数调用。

4、call和apply调用。

情况1:作为对象的方法调用

当函数作为对象的方法调用时,this指向该对象。这是最常见的,比如:

var obj={
  a:1,
  fun:function(){
    console.log(this.a);//输出:1
  }
};
obj.fun();

情况2:作为普通函数调用

当函数不作为对象的属性调用时,即作为普通函数调用,this总是指向全局对象。

var a=1;
function fun(){
  var a=2;
  console.log(this.a);//输出:1
 console.log(a);//输出:2 } fun();

再看一种情况:

var name="张三";
var obj={
  name:"李四",
  getName:function(){
    console.log(this.name);
  }
}
obj.getName();//输出:李四
var getName=obj.getName;
getName();//输出:张三

 直接调用obj.getName(),这里的this是作为对象的方法调用,所以它指向obj,this.name就是李四;

obj.getName赋值给getName后,getName就变成了普通函数,所以指向的是全局的window.name,结果是张三;

举个在实际开发过程中遇到的会让人困惑的例子:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <button id="btn">点我</button>
  <script type="text/javascript">
    var id="window";
    document.getElementById("btn").onclick=function(){
      alert(this.id);//输出:btn
      var callback=function(){
        alert(this.id);//输出:window
      }
      callback();
    }
  </script>
</body>
</html>

  点击按钮的时候this指向的是按钮,但是callback是作为普通函数调用的,里面的this指向的是全局对象window,所以结果是window。

此时我们可以临时用一个变量保存对当前对象的引用:

var id="window";
    document.getElementById("btn").onclick=function(){
      var self=this;
      var callback=function(){
        alert(self.id);//输出:btn
      }
      callback();
   }

情况3:构造器中调用

function myClass(){
  this.name="张三";
}
var child=new myClass();
console.log(child.name);//输出:张三

大部分的javascript函数都可以当做构造函数来使用,构造器函数外表跟普通函数一模一样,区别在于调用的方式。当使用new运算符调用函数时,该函数总会返回一个对象,就是我们常说的实例对象。通常情况下,通过new运算符后,构造器函数中的this就指向的实例对象。

注意:如果构造器函数显式的返回了一个object类型的休息,那么运算结果最终会返回这个对象,而不是上面所期望的。例如:

function myClass(){
  this.name="张三";
  return {
    name:"李四"
  }
}
var child=new myClass();
console.log(child.name);//输出:"李四"
console.log(child);//输出:[object Object] {name: "李四"}

  

 这个例子与上面的例子差别就在于构造器函数最后返回了一个对象。如果构造器函数不显式的返回任何数据,或者返回一个非对象类型的数据,就不会出现这种情况,例如:

function myClass(){
  this.name="张三";
  return "李四"
}
var child=new myClass();
console.log(child.name);//输出:张三
console.log(child);//输出:[object Object] {name: "张三"}

情况4:call和apply

call和apply能够动态的修改传入函数的this:

var obj1={
  name:"张三",
  getName:function(){
    console.log(this.name);
  }
};
var obj2={
  name:"李四"
};
obj1.getName();//输出:"张三"
obj1.getName.call(obj2);//输出:"李四"
obj1.getName.apply(obj2);//输出:"李四"

  

call和apply的作用这里就不详细说了。

 

posted @ 2016-03-31 17:03  沉默术士  阅读(648)  评论(0编辑  收藏  举报