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
}
未完待续~