JavaScript中call、apply、bind的简单实现

先实现个call

call:可以指定函数运行时的this。与apply之间的区别是传参方式不同,call的参数是若干参数列表,apply接受的是一个包含多个参数的数组。
首先,我们先实现第一个功能,指定函数运行时的this:

Function.prototype.fakeCall = function(obj) {
    // 在传入的 obj 上创建一个属性,将该属性指向调用的函数
    obj.fn = this
    // 然后执行 fn,则会将调用的函数的 this 指向 obj
    obj.fn()
    // 最后将创建的 fn 属性删除
    delete obj.fn
}

尝试下效果:

Function.prototype.fakeCall = function(obj) {
    obj.fn = this
    obj.fn()
    delete obj.fn
}
let foo = {
    value: 1
}
function bar(name, age) {
    console.log(this) // {value: 1, fn: ƒ}
    console.log(this.value) // 1
}
bar.fakeCall(foo)

跟预想的一样,已将barthis强行改变成了foo
原生的call方法还可以接受参数,现在实现这个功能。很简单,没错,就是用es6去实现es3,当然用eval也可以。

Function.prototype.fakeCall = function(obj) {
    // 取出除 obj 参数外剩下的参数
    let args = [].slice.call(arguments, 1)
    obj.fn = this
    // 传入参数
    obj.fn(...args)
    delete obj.fn
}

看下效果如何:

Function.prototype.fakeCall = function(obj) {
    let args = [].slice.call(arguments, 1)
    obj.fn = this
    obj.fn(...args)
    delete obj.fn
}
let foo = {
    value: 1
}
function bar(name, age) {
    console.log(name) // xuedinge
    console.log(age) // 20
}
bar.fakeCall(foo, "xuedinge", "20")

可以看出,基本上已经实现了原生的call了。现在考虑一些特殊情况。
1、当调用函数有返回值时,会怎么样。(会是undefined
2、当调用函数传入的this参数是null或者是其他基本数据类型时,会发生什么。(会报错)
根据上面个特殊情况,我们对fakeCall稍作调整。

Function.prototype.fakeCall = function(obj) {
    // 处理传入的值是基本数据类型的情况,特别是 null
    obj = typeof obj !== "object" ? window : obj || window
    let args = [].slice.call(arguments, 1)
    obj.fn = this
    // 将调用函数的返回值保存下来,然后用 return 返回
    let result = obj.fn(...args)
    delete obj.fn
    return result
}

看下效果如何。

Function.prototype.fakeCall = function(obj) {
    obj = typeof obj !== "object" ? window : obj || window
    let args = [].slice.call(arguments, 1)
    obj.fn = this
    let result = obj.fn(...args)
    delete obj.fn
    return result
    }
let foo = {
    value: 1
}
function bar(name, age) {
    console.log(name) // xuedinge
    console.log(age) // 20
    return {
        color: "yuanliangse"
    }
}
console.log(bar.fakeCall(undefined, "xuedinge", "20")) // {color: "yuanliangse"}

apply的实现

aplly:跟call的实现基本相同,区别是对出this外,剩余的参数处理方式不同。直接上代码。

Function.prototype.fakeApply = function(obj) {
    obj = typeof obj !== "object" ? window : obj || window
    let args = [].slice.call(arguments, 1)
    obj.fn = this
    // args的第一个值就是传入的数组
    let result = obj.fn(...args[0])
    delete obj.fn
    return result
}

bind的实现

待续。。。

猜你喜欢

转载自www.cnblogs.com/yangrenmu/p/10633526.html
今日推荐