call,apply,bind的区别及使用

javascript一切都来源于对象,函数也不例外。所以函数也有属性和方法。每一个函数都包括length和prototype以及函数对象上的属性和方法。好比call()、apply()、bind(),这三个方法都是用来改变调用的函数内部this的指向在非函数后是不能使用的,都是在函数后去调用这些方法从而改变this的指向。简单的来讲,就是将函数内的this对象改成本身须要的this对象。javascript

1. call()

调用一个对象的一个方法,并以另外一个对象去替换当前的上下对象。call方法能够一个方法中的上下文对象从初始化的上下文替换成由thisObj指定的新对象。若是没有设置thisObj,会被全局的global替代。java

语法: Function.call(thisObj,[params1[,params2[,paramsN]]])
参数解析: thisObj: 当前须要被指定的this的那个新对象              
     params1,...,paramsN: 传递被调用的函数的参数值

例子:
    ```
    function Person(name,sex){
        this.name = name;
        this.sex = sex;
    }

    function Student(name,grade,sex){
        Person.call(this,name,sex)
        this.grade = grade
    }

    let stu = new Student('cherry','女','99')

    stu.name; // cherry
    stu.sex; // 女
    stu.grade; // 99
    ```
解析:student自己只有grade属性,但在student中call person时,
将person中的this指向了student对象。因此后面的this.name,this.sex
都是将属性建立到student上了。

2. apply()

将方法中的上下文对象从初始化上下文替换成由thisObj指向的新对象。数组

语法: Function.apply(thisObj,[params1,...,paramsN])
参数解析: thisObj: 当前须要被指定的this的那个新对象
        [params1,...,paramsN]: **数组类型的参数**,若是此函数非
        数组或非类数组会致使报错。

1.使用shift()获取数组第一个值app

/*
* 这里假设arguments是类数组对象,想获取第一个的值
*/
const context = Array.prototype.shift.apply(arguments)

2.使用slice()将类数组转为数组函数

/*
* 一样假设arguments是类数组对象
*/
const arr = Array.prototype.slice(arguments)

2.1 call()与apply()的异同点

它们的功能是同样的,都是改变当前方法的this指向。只是传参的形式不同,第一个参数都是当前要指定的this的值。第二个参数不一样,call()是一个值,一个值的排列传递。apply()是将参数放在一个数组中进行传递this

2.2 call()与apply()的选取问题

主要看传递给函数参数的形式,若是参数的形式是数组或类数组则选择apply(),若是是须要一个个的指明顺序或者说传递给函数参数自身都是一个单独的变量可选用call()。好比上面call()中的例子,若是Student中函数的顺序与Person中须要的顺序相同,可直接使用apply()方法(Person.apply(this,agruments))prototype

2.3 apply()巧妙用法

调用apply()方法时,第一个参数是对象(this), 第二个参数是一个数组集合。那么代表经过apply()的转化能够将一个数组对象[params1,...,paramsN]转成参数列表(params1,...,paramsN)code

1.Math.max()获取最大值
数组是没法直接使用Math.max方法的,而且接收的参数形式是参数列表(num1,num2,...,numN)对象

// Math.max的正常使用
Math.max(1,3,6) // 6 
Math.max.apply(null,[1,3,6])   // 等价于Math.max(1,3,6) 输出6

这里的thisObj设置为null,是由于并无对象去调用这个方法,只是得到一个结果而已,因此直接设置为null便可。ip

2.使用push()合并两个数组
咱们都知道push没法合并两个数组,可是它支持push(params1,...,paramsN)

let arr = [1,3,4];
 /*
 * 1. 这里的this是a数组,则是a数组调用push方法,参数是[5,6]
 * 2. 经过apply方法,[5,6]转化成(5,6)并做为函数参数传递给push
 * 则等价于 a.push(5,6)
 */
 Array.prototype.push.apply(a,[5,6]) // [1,3,4,5,6]

3. bind()

定义:第一个参数是当前要绑定的this对象,从第二个参数开始的参数会在调用原函数时将参数传递给原函数。主要做用改变当前函数的this指向,并将this的值传递给bind绑定的函数的值,同时返回一个新的函数实例,因此不会在bind的时候运行这个绑定函数。
语法:Function.bind(thisObj,args)
参数解析:thisObj: 当前须要被指定的this的那个新对象
args: 传递给原函数的参数

const name = "cherry";
cosnt obj = { name: "qq"};

function getName(){
    console.log(this.name)
}

/*
* 没有强制指定this的值,而且前面也没有调用改函数的对象
* 这时this指向全局window
*/ 
getName()  // cherry

/*
* bind以后this指向obj对象
*/
var newFn = getName.bind(obj)
newFn() // qq

这个方法会返回一个新函数,称为绑定函数。当调用这个绑定的函数时,第一个参数是改变这个绑定函数的this指向,从第二个参数以及后面的参数时在绑定函数运行时将做为函数参数按顺序传递给原参数

4. 总结

这三个函数都是改变当前函数的this指向,call和apply都是当即调用这个函数并返回结果。不一样的使用call时的所需的函数参数时一个个顺序传递的,apply则是使用数组列表传递的。针对于bind是建立一个新函数,再调用这个新函数才会真正运行绑定函数。

相关文章
相关标签/搜索