先实现个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)
跟预想的一样,已将bar
的this
强行改变成了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的实现
待续。。。