ES5-callapplybind方法总结包括理解this的指向问题

36次阅读

共计 2562 个字符,预计需要花费 7 分钟才能阅读完成。

总结 call,apply,bind 方法的理解使用和区别。

call,apply,bind 这三个方法在 JavaScript 中是用来改变函数调用的 this 指向。那么改变函数 this 指向有什么用呢?我们先来看一段代码

var a= {
    name:'harden',
    fn:function () {console.log(this.name);
    }
}
var b = a.fn;
a.fn();//harden
b();//undefined

调用 a.fn 方法后得到了 harden,但在 b 方法中我想得到 harden,为什么却是 undefined 呢?原因是方法在执行的时候才能确定 this 到底指向谁,实际上 this 指向的是 最终 调用函数的对象。这里当 b 执行时,实际是 window 调用了 fn 函数,那么 fn 中的 this 就指向 window。
在开始讲 call,apply,bind 方法前,一起来总结一下 this 的指向问题。

理解 JavaScript 中的 this 指向问题。

总体来说 this 指向可以概括为一句话:this 指向在函数的定义时是不确定的,只有函数执行时才能确定 this 到底指向谁,实际上 this 的 最终 指向的是那个调用它的对象。但是这个说法在函数被很多对象包裹的时候并不成立,请看下面例子。
简单来说就是:谁(哪个对象)调用的这个函数,那么这个函数中的 this 就指向这个对象。

例一

 function a(){
        var name= "harden";
        console.log(this.name); //undefined
        console.log(this); //Window
    }
    a();

因为 this 最终指向调用他的对象,在上述代码中其实是 widow 触发的这个方法,那么 this 就指向 window,window 中并没有定义 a,那么就打印出 undefined。
例二:

var a = {
    name:'harden',
    fn:function() {console.log(this.name);//harden
        console.log(this);// 指向 a(可以自己跑一下)
    }
}
a.fn()

这里的 this 指向 a,因为这里的 fn 函数是通过 a.fn() 执行的,那么 this 自然指向 a。
说到这我就有疑问了,如果我用 window.a.fn()执行函数,this 不就指向 window 了吗?然后并不是这样的,请看下一个例子。补充一点:window 是 js 的全局对象。
例三:

var a = {
    name:'harden',
    b:{
        name:'james',
        fn:function() {console.log(this.name);//james
            console.log(this);// 指向 b
        }
    }
}
a.b.fn()

我们看到最终是 a 调用的方法,那为什么 this 会指向 b 呢?现在总结三句话,来完全理解 this 的指向问题:

情况一:如果一个函数中有 this,但是它没有被上一级的对象所调用,那么 this 指向的就是 window(除去严格模式外)。
情况二:如果一个函数中有 this,这个函数有被上一级的对象所调用,那么 this 指向的就是上一级的对象。
情况三:如果一个函数中有 this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this 指向的也只是它上一级的对象,例子 3 可以证明。

  • 构造函数中的 this:

     function Fn(){this.name = "harden";}
       var a = new Fn();
       console.log(a.name); //harden

这里的 a 可以点出 name,因为 new 关键字会改变 this 的指向。为什么 new 关键字会改变 this 呢,我自己有两种看法:
1. 在 new 的过程中会创建一个实例对象,通过 apply 等方法 通过 Fn.apply({}) 使 this 指向这个空对象,最后把 fn 方法中的材料加工完后返回给 a。

  • 当 this 遇到 return 的时候:

    function fn()  
       {  
           this.user = 'harden';  
           return {};}
       var a = new fn;  
       console.log(a.user); //undefined
       
       function fn()  
       {  
           this.user = 'harden';  
           return function(){};
       }
       var a = new fn;  
       console.log(a.user); //undefined
       
       function fn()  
       {  
           this.user = 'harden';  
           return 1;
       }
       var a = new fn;  
       console.log(a.user); //harden
       
       function fn()  
       {  
           this.user = 'harden';  
           return undefined;
       }
       var a = new fn;  
       console.log(a.user); //harden
    

总结一下:如果返回值是一个对象,那么 this 指向的就是那个返回的对象,如果返回值不是一个对象那么 this 还是指向函数的实例。还有一点就是返回 null,null 也是对象,但是因为他的特殊性,返回后 this 还是指向函数本身的实例。理解 JavaScript 中的指向问题
理解完 JavaScript 中的指向问题,那么回到正题:

call,apply,bind 方法总结

1.call

a = {name: 'harden'}
function b () {console.log(this.name);
}
b.call(a);//harden
b()//undefined

b.call(a)用字面意思来讲就是:把函数 b 添加到对象 a 的环境中,使函数中的 this 指向对象 a。
call 与 apply 不同的地方就是传参不同。
2.apply

a = {name: 'harden'}
function b (data1,data2) {console.log(data1,data2);
}
b.call(a,'a1','a2');//a1 a2
b.apply(a,['a1','a2']);//a1 a2

3.bind

a = {name: 'harden'}
    function b () {console.log(this.name);
    }
    b.bind(a);// 不会执行函数
    var aaa = b.bind(a);
    aaa()//harden

bind 不会立即调用函数,是把函数返回,bind 通常用它来指定回调函数的 this。
关于 call, apply, bind 方法的区别与内部实现

正文完
 0