1. 90前端首页
  2. 前端开发
  3. JavaScript

call,apply,bind的区别及使用

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

1. call()

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

语法: 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()获取数组第一个值

/*
* 这里假设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()是将参数放在一个数组中进行传递

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

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

2.3 apply()巧妙用法

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

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即可。

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是创建一个新函数,再调用这个新函数才会真正运行绑定函数。

本文来自网络整理,转载请注明原出处:https://segmentfault.com/a/1190000021713009

展开阅读全文

发表评论

登录后才能评论