web前端开发,一起交流最cool的技术让前端飞Web前端之路

javascript 中的this、apply、call

2018-04-05  本文已影响45人  Searchen

前言:
this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

Part 1 作为对象的方法调用
当函数作为对象的方法被调用时,this 指向该对象,如obj.b(),this指向obj

var obj = {
 name:  "Sear",
 getName: function(){
   alert ( this === obj ); // 输出:true 
    return this.name ; 
  } };
 obj.getName();// 输出: Sear

我们说当函数作为对象的方法被调用时,this 指向该对象,那么,下面这种情况:

var obj = {
    myName: "Sear",
    getName: function () {
        return this.myName;
    }
};
obj.getName(); //输出Sear
var newObject = obj.getName;
 console.log(newObject()) // 输出undefine

诶?怎么是undefine呢?是这样的
当用另外一个变量 newObjec来引用 obj.getName,并且调用 getName2 时,将就是下面Part2我们要提到的规律,此时是普通函数调用方式,this 是指向全局 window 的,所以程序的执行结果是 undefined。

Part 2 作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的 this 默认的,指向全局变量window。在浏览器的 JavaScript 里,这个全局对象是 window 对象

    window.name = "Hello"
    var obj = {
       name :"world",
       getName : function (){
       console.log(this === obj) //输出false
      console.log(this.name)     //输出 Hello
       return this.name
 }
}
var get = obj.getName
get()   //输出Hello 

有时候我们会遇到一些困扰,比如在 div 节点的事件函数内部,有一个局部的 callback 方法, callback 被作为普通函数调用时,callback 内部的 this 指向了 window,但我们往往是想让它指向 该 div 节点,见如下代码:参考《javascript设计模式与开发实践》中的一个例子就很好理解了

 <html>
 <body>
         <div id="div1">我是一个 div</div> </body>
 <script>
   window.id = 'window';
   document.getElementById( 'div1' ).onclick = function(){ alert ( this.id ); // 输出:'div1'
  var callback = function(){
  alert ( this.id );
     callback();
 };
</script>
</html>

此时有一种简单的解决方案,可以用一个变量保存 div 节点的引用:

 document.getElementById( 'div1' ).onclick = function(){ var that = this; // 保存 div 的引    
 用
                                                                                                                                 
var callback = function(){
         alert ( that.id ); // 输出:'div1' }
         callback(); 
 };

这种转换this的指向在小程序中也经常出现

Part 3 new 调用时指的是被构造的对象

 var obj = function (){
   this.name = 'Sear'
 }
var newObj = new obj()
newObj.name    // 输出Sear

但用 new 调用构造器时,还要注意一个问题,如果构造器显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的 this:

 var MyClass = function(){
 this.name = 'hello';
 return { 
   // 显式地返回一个对象
   name: 'world'
          }
  };
   var obj = new MyClass();
  obj.name   // 输出:world

如果构造器显式地不是返回了一个 object 类型的对象,那么不会造成上面的问题

 var MyClass = function(){
     this.name = 'hello'
    return 'world'; // 返回 string 类型
 };
var obj = new MyClass();
obj.name; // 输出:hello

Part 4 call、apply调用,指向我们指定的对象,即会改变this的指向

window.name = "Hello"
var obj = function () {
    return this.name
}
var obj1 = {
    name: 'world'
}
var obj2 = {
    name: 'Sear'
}
obj(); //输出 Hello
obj.call(obj1);//输出 world 
obj.apply(obj2); //输出Sear

参考书籍:
《javascript设计模式及开发实践》
链接: https://pan.baidu.com/s/1Twpu1hM2YaPsNEqgiXsAZQ 密码: i8jf
仅限知识分享,请勿商业使用,谢谢

上一篇下一篇

猜你喜欢

热点阅读