Fork me on GitHub

理解JS中的call、apply、bind方法

  • 在JavaScript中,callapplybind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向

  • callapplybind方法的共同点

    • callapplybind 三者都是用来改变函数的this对象的指向的;
    • callapplybind 三者第一个参数都是this要指向的对象,也就是想指定的上下文(函数的每次调用都会拥有一个特殊值,即本次调用的上下文(context),这就是this关键字的值);
    • callapplybind 三者都可以利用后续参数传参
  • bind方法与callapply两个方法的区别:

    • bind方法是返回对应函数,便于稍后调用
    • callapply则是立即调用
  • 可见,当我们希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind()方法。而 apply/call 则会立即执行函数。
call()
  • 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
  • 定义:调用一个对象的一个方法,以另一个对象替换当前对象。
  • 说明: call 方法可以用来代替另一个对象调用一个方法
  • call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
  • thisObj的取值有以下4种情况:
    (1) 不传,或者传null,undefined,函数中的this指向window对象;
    (2) 传递另一个函数的函数名,函数中的this指向这个函数的引用;
    (3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean;
    (4) 传递一个对象,函数中的this指向这个对象。
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function a(){   
    console.log(this); //输出函数a中的this对象
    }
    function b(){}
    var c={name:"call"}; //定义对象c

    a.call(); //window
    a.call(null); //window
    a.call(undefined); //window
    a.call(1); //Number
    a.call(''); //String
    a.call(true); //Boolean
    a.call(b); //function b(){}
    a.call(c); //Object
apply和call的区别
  • 对于callapply二者而言,作用完全一样,只是接受参数的方式不太一样
  • call需要把参数按顺序传递进去,而apply则是把参数放在数组里后将整个数组传入
  • 在JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话:
    • 当参数是明确知道数量时用call
    • 而不确定的时候用apply,然后把参数 push 进数组传递进去。
    • 当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
bind()
  • bind是在 ES5 中扩展的方法(IE6,7,8不支持)。bind方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind方法的第一个参数作为 this,传入 bind 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
  • bind方法的返回值是函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var name = '李四'
    var foo = {
    name: "张三",
    logName: function(age) {
    console.log(this.name, age);
    }
    }
    var fooNew = foo.logName;
    var fooNewBind = foo.logName.bind(foo);
    fooNew(10)//李四,10
    fooNewBind(11)//张三,11(因为bind改变了fooNewBind里面的this指向)
  • 在Javascript中,多次使用bind()是无效的。更深层次的原因, bind()的实现,相当于使用函数在内部包了一个 call/apply ,第二次bind()相当于再包住第一次bind(),故第二次以后的bind()是无法生效的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var bar = function(){   
    console.log(this.x);
    }
    var foo={
    x:3
    }
    bar(); // undefined

    bar.bind(foo)(); // 3
    /*或*/
    var func = bar.bind(foo);
    func(); // 3
  • 由于箭头函数没有自己的this,所以当然也就不能用call()apply()bind()这些方法去改变this的指向

  • 箭头函数的this总是指向词法作用域,也就是外层调用者。
------ 本文结束 ------