你不知道的js封装call和apply

call和apply的实质在于去借用别人的方法和属性(本身没有)。

回顾call:   foo.call(obj)  可以理解为 obj借用了foo这个函数。

var name = 'window'
var obj = {
    name: 'obj'
}
function foo() {
    console.log(this.name)
}
foo() //空执行。相当于window.foo() ==>结果为window
foo.call(obj)  //this指向为obj  ==>以结果为 obj

模拟实现call

var name = 'window'
var obj = {
    name: 'obj'
}
function foo() {
    console.log(this.name)
}
foo() //空执行。相当于window.foo() ==>结果为window

foo.call(obj)  //this指向为obj  ==>以结果为 obj

obj.foo = foo  // 把外界的foo函数添加到obj.foo上,此时this指向在执行这个方法是发现变化

obj.foo()  //结果也为obj

以上代码的不足是给obj添加了新的方法。这不是我们想要的。通常在编程的时候,我们很少用到增删改查中的删。

这里我们可以通过  delete obj.foo  直接删除这个借用过来的方法。所以对于源码的封装,我们有了初步的思路

Function.prototype.mycall = function(){
    var foo = arguments[0]  //call 形参的第一位是确定this指向。也就是谁调用这个方法
    foo.fn = this           //fn为借来调用的方法。
    foo.fn()                
    delete foo.fn
}

以上简单实现了没有传参时候模拟实现的call ,对于传入形参的封装实在不想用eval这个改变作用域链的魔鬼~

探讨问题。如何将一个字符串分割从多个字符串(能做到),如何将分割好的字符串当实参传给函数执行

Function.prototype.mycall = function () {
    var foo = arguments[0]  //call 形参的第一位是确定this指向。也就是谁调用这个方法
    foo.fn = this           //fn为借来调用的方法。
    var arr = []            //创建一个数组来接收形参

    for (var i = 1; i < arguments.length; i++) {
        arr.push(arguments[i])
    }
    eval('foo.fn(' + arr.join() + ')')  //因为join返回的是一个字符串(不传参默认为逗号)。
    delete foo.fn
}

未完待续~

猜你喜欢

转载自blog.csdn.net/qq_35401191/article/details/82701265