JavaScript 之实现 call apply
2019-11-08 本文已影响0人
临安linan
[个人博客]:(https://github.com/zenglinan/blog)
如果对你有帮助,欢迎star。
实现call
call可以指定函数调用的this, 并传入多个参数执行
举个例子:
var a = {
val: 1
}
var b = {
fn: function(){
console.log(this.val)
}
}
b.fn.call(a)
观察一下call的调用形式, 只需将call指定的this提前到b前面, 即: a.fn()
但是a中并没有fn这个属性, 所以还需将fn属性添加到a中
总结一下: 只需要在a中添加fn, 然后执行a.fn, 然后删除这个属性(ÒωÓױ!必须要删除啊, 不然a会凭空多了个属性)
实现过程:
Function.prototype.call = function(target){
target.fn = this // 这里fn随便取名字
target.fn()
delete target.fn
}
基础版完成! 但还需支持传参, 原版的call除了传this还可以传函数的参数
但是这里不知道函数的参数有多少个, 这里可以借助arguments来取出参数
Function.prototype.call = function(target){
const arg = []
for(let i = 1; i < arguments.length; i ++){
arg.push(arguments[i])
}
target.fn = this
target.fn(...arg) // 因为不知道有几个参数, 这里用...arg取出所有参数, 当然也可以用eval(还是算了 = =)
delete target.fn
}
这里就实现了传参了, 但还差点意思, 当call传的是null或者undefined的时候应该返回window
Function.prototype.call = function(target){
target = target || window // 判断target为null或undefined时设为window
const arg = []
for(let i = 1; i < arguments.length; i ++){
arg.push(arguments[i])
}
target.fn = this
target.fn(...arg)
delete target.fn
}
最后差一步, 原生的call是有返回值的, 这里我们给call设一下返回值
Function.prototype.call = function(target){
target = target || window
const arg = []
let result
for(let i = 1; i < arguments.length; i ++){
arg.push(arguments[i])
}
target.fn = this
result = target.fn(...arg)
delete target.fn
return result
}
基本完成(▽), 但是以上方法还存在的不足是: 当传入基础类型时, 原生的call对基础类型进行了类包装
比如将字符串包装成new String("xxx")
的包装类对象
实现apply
跟call类似, 无非是参数形式变了, apply 里要求第二个参数形式是数组
Function.prototype.apply = function(target, arr){
target = target || window
let result
target.fn = this
if(!arr){
result = target.fn()
}else{
const arg = []
for(let i = 0; i < arr.length; i ++){
arg.push(arr[i])
}
result = target.fn(...arg)
}
delete target.fn
return result
}