ES5 call,apply,bind方法总结(包括理解this的指向问题)

周阳
• 阅读 3315

总结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方法的区别与内部实现

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Dax Dax
3年前
JavaScript中call()、apply()、bind()的用法
call()apply()bind()都是用来更改this的指向的其中bind()返回的是一个函数,必须执行才行传参差异:call、bind、apply这三个函数的第一个参数都是this的指向对象,第二个参数差别就来了:call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面obj.myFun.call(db,'
巴拉米 巴拉米
4年前
bind、call、apply 区别?如何实现一个bind?
一、作用call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢?下面举个例子var name"lucy";const obj{    name:"martin",    say:function (){        co
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
LinMeng LinMeng
4年前
call、apply、bind三者为改变this指向的方法。
共同点:第一个参数都为改变this的指针。若第一参数为null/undefined,this默认指向window差异点如下:1.call(无数个参数)第一个参数:改变this指向第二个参数:实参使用之后会自动执行该函数functionfn(a,b,c){console.log(this,abc);//this指
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
JS 中的this指向问题和call、apply、bind的区别
this的指向问题一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window。functiona(){console.log(this);//输出函数a中的this对象}functionb(){};varc{name:"call"}
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(