帮女朋友整理的call、bind、apply,一看就懂

248 阅读3分钟

须知:

首先要知道call、bind、apply的作用是什么?都知道是强制绑定this的指向。那么就要搞明白,
this的指向的规则到底是什么?如何去改变他?官方给的说法是:this表示的是函数的调用者。
也就是说谁调用了函数,那么这个函数的this就是调用了这个函数的对象。
举个栗子:
let obj = {
    a:1,
    b:2,
    fn(){
        console.log('我是obj的方法',this)
    }
}

// 调用
obj.fn()
// 打印结果 this为obj对象

总结:重要的事情说三遍,除了特殊调用(比如new等),this就是你调用函数前面的那个对象,this就是你调用函数前面的那个对象,this就是你调用函数前面的那个对象。 好了,到这里准备工作就结束了。下面进入正文。

call方法的实现

  • call 接收多个参数,第一个为函数上下文也就是this,后边参数为函数本身的参数。
// 正常使用是call时 fn.call(context,参数1,参数2,...)
//传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替
Function.prototype.myCall = function (context, ...args) {
    //context就是想让this指向的对象,这里默认不传就是指向window
    context = context || window 
    // 也可以用es6给参数设置默认参数,类数组先转化为数组,方便后面使用'...'展开
    args = args ? Array.from(args) : [] 
    //给context新增一个独一无二的属性以免覆盖原有属性 
    const key = Symbol() 
    // 下面的这个this是call函数中的this(标识call前面的调用者,即fn),不是你调用方法的this,要注意区分。
    context[key] = this 
    //通过隐式绑定的方式调用函数 (即开头须知中所说的,把fn放到context的属性上通过context.fn的形式调用,这样就可以把this指向到context上了)
    //(很多人不明白就是这一步没搞清楚,我把这一步详细说明一下,如果感觉帮到你了,还请不要吝惜赐赞一枚,哈哈)
    const result = context[key](...args) 
    //删除添加的属性,不改变原对象 
    delete context[key] 
    //返回函数调用的返回值 
    return result 
 }

apply方法的实现

  • apply和call类似,就是参数接收的类型不同,apply接收两个参数,第一个参数为函数上下文this,第二个参数为函数参数只不过是通过一个数组的形式传入的。
Function.prototype.myApply = function (context, args) { 
    //这里默认不传就是给window,也可以用es6给参数设置默认参数 
    context = context || window 
    args = args ? args : [] 
    //给context新增一个独一无二的属性以免覆盖原有属性 
    const key = Symbol() 
    context[key] = this 
    //通过隐式绑定的方式调用函数 const result = context[key](...args) 
    //删除添加的属性 
    delete context[key] 
    //返回函数调用的返回值 
    return result 
}

bind方法的实现

  • 这个和call、apply区别还是很大的,咱们需要好好捋一捋,先分析bind都能干些什么,有什么特点 1、函数调用,改变this 2、返回一个绑定this的函数 3、接收多个参数 4、支持柯里化形式传参 fn(1)(2)
Function.prototype.myBind = function (context, ...args) { 
    const fn = this 
    args = args ? args : [] 
    // 返回一个函数
    return function newFn(...newFnArgs) { 
        if (this instanceof newFn) { 
            return new fn(...args, ...newFnArgs) 
        } 
    // 执行了apply上述的操作
    return fn.apply(context, [...args,...newFnArgs]) } }

  • 有一个需要判断的点,因为返回新的函数,要考虑到使用new去调用

到这就基本上理清楚了,在call方法中讲的比较详细,其他方法是在call的基础上做一些变动,只要call方法看明白了,那就都是小问题。希望对你能有所帮助。(撰文不易,点赞鼓励,哈哈)

  • 前端知识整理 ( 文档中有很多知识点总结,相信对你有一定的帮助,你会回来感谢我的!)