JS的call、apply、bind

108 阅读2分钟

原理:改变函数的this指向

举个例子.png

class Par{
    constructor(name,age){
        this.name = name
        this.age = age
    }
    say(sex='',like=''){
        return (`姓名---${this.name},年龄---${this.age},性别---${sex},爱好---${like}`)
    }
}

let son = new Par('TTT',18)
son.say()// 姓名---TTT,年龄---18
let obj = {name:'ttt',age:10}
son.say.call(obj,'男','美女')//姓名---ttt,年龄---10,性别---男,爱好---美女,直接执行函数
son.say.apply(obj,['男','美女'])// 姓名---ttt,年龄---10,性别---男,爱好---美女,直接执行函数
son.say.bind(obj,['男','美女'])()// 姓名---ttt,年龄---10,性别---男,爱好---美女,返回的是个函数,还需要调用

son.say的this指向为实例 son (谁调用的say,this就是指向谁),通过调用Function原型的call,改变了this指向为 obj

手写一个粗略版call(顺便把apply也说一下)

call 内部是怎么改变这个this指向的呢,上面说到根据谁调用这个函数,这个函数内部的this就是指向谁,那么我们是不是把 son.say.call(obj) 里面的 son.say, 改成 obj.say 的话,this 不就是指向obj 了吗?


Function.prototype.newCall = function(content=window){
    //son.say.call2(obj2)   
    //我们需要把this改成obj2

    //this = say,content = obj2,我们在obj添加一个属性,指向say函数
    content.fn = this

    //call2的第二个参数----传给say函数的参数
    //apply的话,就判断 arguments[1] 存在的话,直接结构 ...arguments[1] ,因为它本身就是一个数组
    let args = [...arguments].slice(1);

    //执行这个say函数,此时,say里面的this指向就变成了content
    let result = content.fn(...args)    
    
    // 删除临时属性
    Reflect.deleteProperty(content,'fn')
    //delete content.fn  delete在严格模式下会报错

    //如果 say 函数需要一个返回值,这里是需要 return 才能拿到执行函数后的返回的
    //例:son.say.call2(obj2) 可以不需要return
    //let conSon = son.say.call2(obj2) 如果要获取 conSon 则需要 return 回执行函数的返回值
    return result

}

class Par{
    constructor(name,age){
        this.name = name
        this.age = age
    }
    say(sex='',like=''){
        return (`姓名---${this.name},年龄---${this.age},性别---${sex},爱好---${like}`)
    }
}

let son = new Par('TTT',18)
son.say()// 姓名---TTT,年龄---18
let obj = {name:'ttt',age:10}
son.say.call(obj)// 姓名---ttt,年龄---10,性别---'',爱好---''
son.say.newCall(obj)// 姓名---ttt,年龄---10,性别---'',爱好---''



手写一个粗略版bind

bind 返回的是一个函数,所以在函数内部的thisargs会改变,需要在函数外部定义

    Function.prototype.newBind = function (content = window) {
        let that = this
        let args = arguments[1]?...arguments[1]:'';
        return function () {
            //this = say,content = obj,我们在obj添加一个属性,指向say函数
            content.fn = that

            //执行这个say函数,此时,say里面的this指向就变成了content
            let result = content.fn(args)

            // 删除临时属性
            Reflect.deleteProperty(content, 'fn')

            //如果 say 函数需要一个返回值,这里是需要 return 才能拿到执行函数后的返回的
            //例:son.say.newCall(obj) 可以不需要return
            //let conSon = son.say.newCall(obj1) 如果要获取 conSon 则需要 return 回执行函数的返回值
            return result
        }
    }

以上!!!