前端

bind,apply,call的理解以及手写

2020-01-02  本文已影响0人  agamgn

前言

    在JavaScript中,call、apply和bind,他们是Function对象自带的三个方法,他们主要用作改变函数执行时的上下文,也就是改变this的指向。

一、call()

语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])

定义:调用一个对象的一个方法,以另一个对象替换当前对象。
thisObj的取值有以下4种情况:

二、apply()

语法:apply([thisObj[,argArray]])

定义:应用某一对象的一个方法,用另一个对象替换当前对象。

注:apply和call几乎一样,只是接受参数的方式不太一样。
例子:

var obj1={
    num:10,
    fn:function (n) { 
        console.log(this.num+n);
     }
}
var obj2={
    num:20,
    fn:function (n) { 
        console.log(this.num+n);
     }
}
obj1.fn.apply(obj2,[10]); //30

关于运行效率:

demo4.png
call 比 apply 速度快,也
可以用这个网站测试https://jsperf.com/call-apply-segu,这是什么原因造成这样的呢?
因为 apply 运行前要对作为参数的数组进行一系列检验和深拷贝,而 call 则没有

三、bind()

bind用法和call类似,只不过调用bind后方法不能立即执行需要再次调用,其实就是柯里化(把接受多个参数的函数变换成接受一个单一参数[最初函数的第一个参数]的函数)的一个语法糖。

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

例子: demo5.png

自己实现

1.实现call()

我们猜测call是怎么实现的,代码:


demo6.png 如果Person1有say方法那么Person1直接执行Person1.say() 结果就是我是agamgn1,接下来写我们的代码: demo7.png 看样子好像是实现了一样,不过我们还缺少一些细节:
1、call支持零或多个参数。

2、考虑多参数时要把参数传给扩展方法。
3、给上下文定义的函数要保持唯一。
4、需要把自定义的函数删除。

我们首先添加支持零个参数: demo8.png 接下来一起解决,使用了es6中新的类型Symbol: demo9.png 测试:
Person.say.call(Person1, 18)//我叫agamgn1我今年18

2.实现apply()

有了上面的基础,实现apply就简单多了,只有多参数时第二个参数是数组。 demo10.png

3.实现bind()

还是先分析bind都能干些什么,有什么特点 :
1、函数调用,改变this
2、返回一个绑定this的函数
3、接收多个参数
4、支持柯里化形式传参 fn(1)(2)


demo11.png

参考

MDN
call,bind,apply实现
面试感悟,手写bind,apply,call
代码地址

上一篇 下一篇

猜你喜欢

热点阅读