call、apply和bind的介绍

介绍了Call、Apply和Bind这三个函数的用法和区别。

call、apply和bind的介绍

By img Microanswer Create at:Nov 17, 2021, 11:39:28 AM 

Tags: call apply bind javascript

介绍了Call、Apply和Bind这三个函数的用法和区别。


重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。

javascript 允许我们以各种姿势去执行一个函数,这些所有的姿势中就包含了如标题所写的这三个姿势。下面直接介绍一下它们对应的用法。本文我们先定义一个函数,以这个函数为测试对象来介绍这三个姿势的不同之处。

一、定义函数

我们先简单的定义出来一个用于测试的函数,本文的重点不是如何定义函数,因此这里直接写一个简单的函数就好了,那么我们不妨实现一个:截取字符串中指定位置的子字符串。

/**
 * 截取 str 从 startIndex 到 endIndex 之间的字符串并返回。
 * @param str {string} 待截取字符串。
 * @param startIndex {number} 开始位置。
 * @param endIndex {number} 结束位置。
 */
function mySubstring(str, startIndex, endIndex) {
    var result = "";
    for (var index = 0; index < str.length; index++) {
        if (startIndex <= index && index <= endIndex) {
            result += str.charAt(index);
        }
    }
    this.result = result; // 在 this 上将结果也添加上。
    return result;
}

现在函数定义好了,这个函数也是很简单的,传入要截取的字符串以及位置信息,就可以返回截取结果了,中途有一行代码是将result也放在了this上面,此代码主要是为了后面讲解的时候会用到。接下来就分别对各个姿势进行介绍。

二、函数正常执行

直接在函数后面使用()括号,并传入对应参数,就可以正常执行了。但凡学过javascript都必然知道这种姿势。

var str = mySubstring("I'm Jack.", 2, 6);
// str 得到 "m Jac"

上述代码可以看到,函数后面通过括号直接执行,这也是最为常规的代码了。

三、使用call执行函数

使用call执行函数可以修改函数内this的指向,上面的函数中正好有this.result = result;这句代码,既然call可以修改this的指向,那么如果我们将其指向到我们希望的一个对象上,当执行完成这个函数后,这个对象上就应该会有一个 result 属性,并且有值的。看下面的代码:

// 创建一个自己的对象。
var myObj = {tag: "这是我自己的对象"};

// 使用call去执行上面的函数,并且传入我们自己的对象,从而实现上述函数里的this指向我们自己的对象。
var str = mySubstring.call(myObj, "I'm Jack.", 2, 6);
// str 得到 "m Jac"。

console.log(myObj);
// 同时 myObj 则为:{tag: "这是我自己的对象", result: "m Jac"};

看到没有,使用call去执行我们的函数时,第一个参数不是我们自己的函数定义的第一个了, 而是一个用于设定你希望函数内部this指向的一个东西,而后面的参数就和正常情况一样,原来的函数参数怎么定义的后面就怎么传递就好了。这看起来好像没有卵用,诚然,大多数情况下我们并不会去这样子使用。但如果你要写稍微工具化或者框架级别的系统时,你可能就会常常遇到各种奇葩的功能需求,而恰好这样的写法可以满足你的需求!

四、使用apply执行函数

applycall的作用几乎一模一样的,作用也是修改原函数内部的this指向,唯一的不同之处,就是参数的传递方式有所差异。请阅读下面的代码:

// 创建一个自己的对象。
var myObj = {tag: "这是我自己的对象"};

// 使用apply去执行上面的函数,并且传入我们自己的对象,从而实现上述函数里的this指向我们自己的对象。
var str = mySubstring.apply(myObj, ["I'm Jack.", 2, 6]);
// str 得到 "m Jac"。

console.log(myObj);
// 同时 myObj 则为:{tag: "这是我自己的对象", result: "m Jac"};

很简单对吧,它与 call 的差别就只是第一个参数后面不同,他们的第一个参数,都是用于指定this指向的,而后面的参数则有所不同了。apply是需要你把所有的参数放在一个数组里面,然后直接放在后面;而call则是你直接把你的参数挨着向后面继续写就可以了。

五、使用bind

bind与上面两个方法的作用类似,也可以修改原函数内的this指向,而bind的一个很大的区别在于,它不会执行函数本身,而是会产生一个新的函数,这个新的函数功能和原来的函数功能一模一样,但就是内部的this指向不一样。比方说下面的代码:

// 创建一个自己的对象。
var myObj = {tag: "这是我自己的对象"};

// 使用bind去处理上面的函数,并且传入我们自己的对象,从而实现上述函数里的this指向我们自己的对象。
var newFun = mySubstring.bind(myObj);
// newFun 是一个新的函数,不再是原来函数的执行结果了,这时候你可以 newFun() 执行这个新的函数。

// 执行这个新的函数,得到我们的结果
var str = newFun("I'm Jack.", 2, 6);
// str 得到 "m Jac"。

console.log(myObj);
// 同时 myObj 则为:{tag: "这是我自己的对象", result: "m Jac"};

要注意,上面的代码第5行可以看到,我们在使用bind函数的时候,只是传入了要修改的this指向,没有传入原本函数定义的那些参数,而是在下面执行新的函数时,传入了具体的参数。

实际上,你可以直接在bind的时候指定参数,指定了多少个,产生的新的函数,就只能传递剩下的参数,比如说:

// 创建一个自己的对象。
var myObj = {tag: "这是我自己的对象"};

// 使用bind去处理上面的函数,并且传入我们自己的对象,并且新函数数第一个参数设为 "I'm Jack."。
var newFun = mySubstring.bind(myObj, "I'm Jack.");

// 执行这个新的函数的时候,我们就只需要传递剩下的两个参数。
var str = newFun(2, 6);
// str 得到 "m Jac"。

console.log(myObj); // 同时 myObj 则为:{tag: "这是我自己的对象", result: "m Jac"};

// 如果我们直接指定两个参数,则新函数执行时只需要传最后一个了。
var newFun2 = mySubstring.bind(myObj, "I'm Jack.", 2);
var str2 = newFun2(6);
// str2 得到 "m Jac"。

// 甚至我们可以把所有参数在bind的时候都给设置了。
var newFun3 = mySubstring.bind(myObj, "I'm Jack.", 2, 6);
var str3 = newFun2();
// str3 得到 "m Jac"。

通过bind处理了之后,我们可以让许多函数产生一个新的适用于自己模块的替代函数出来,从而实现一些底层的工作。还有一点值得一提,当我们通过bind得到了新的函数后,如果你再用新的函数去通过call或者apply去执行的话,函数会执行,但是不会修改this指向了,函数执行时的this执行还是bind指定的那个。

Full text complete, Reproduction please indicate the source. Help you? Not as good as one:
Comment(Comments need to be logged in. You are not logged in.)
You need to log in before you can comment.

Comments (0 Comments)