手撕call、apply和bind

112 阅读1分钟

手撕call、apply和bind

call

/* 
分析call执行原理 
    将函数执行,改变函数的this指向 当传入第一个参数为为null和undefined this->window 可以传入基本类型
*/

Function.prototype.myCall = function (context, ...params) {
    //context为null和undefined时context为window 非对象类型转化为对象类型
    context == null ? context = window : null
    if (!/^(function|object)$/.test(typeof context)) context = Object(context)
    //此时的this是fn
    let key = Symbol('key'),//为了保证不把对象中的属性覆盖和删除,使用一个唯一的key
        result
    context[key] = this
    result = context[key](...params)
    delete context[key]
    return result
}

apply

Function.prototype.myApply = function (context, params) {
    //context为null和undefined时context为window 非对象类型转化为对象类型
    context == null ? context = window : null
    if (!/^(function|object)$/.test(typeof context)) context = Object(context)
    //此时的this是fn
    let key = Symbol('key'),//为了保证不把对象中的属性覆盖和删除,使用一个唯一的key
        result
    context[key] = this
    result = context[key](...params)
    delete context[key]
    return result
}

bind

/* 
分析
    创建一个函数,改变this指向,将参数传递进去
    利用柯里化的函数思想返回函数,函数执行时,改变this和传递参数
*/
Function.prototype.myBind = function (context, ...params) {
    //context为null和undefined时context为window 非对象类型转化为对象类型
    context == null ? context = window : null
    if (!/^(function|object)$/.test(typeof context)) context = Object(context)
    // this->func
    let self = this
    return function (...argu) {
        params = params.concat(argu)
        let key = Symbol('key'),//为了保证不把对象中的属性覆盖和删除,使用一个唯一的key
            result
        context[key] = self
        result = context[key](...params)
        delete context[key]
        return result
    }
}
function fn(x, y) {
    this.total = x + y
    return this
}
let obj = {
    name: 'tw'
}
console.log(fn.myCall(obj, 10, 20))

function func() {
    console.log(this, arguments)
}
document.body.onclick = func.myBind(10, 100, 200)