基础:递归实现dependArray和dependObject
这两个不用说,实现起来非常简单
function dependArray(array){
let length = array.length
let clone = new Array(length)
let cur = length
let curTarget
while(cur--){
curTarget = array[cur]
// 第二个参数的用处下面会说
clone[cur] = chooseOpeByType(curTarget,clone)
}
return clone
}
唯一要注意的是,利用while(cur--)这样的技巧时,cur不要初始化为length - 1
function dependObject(object){
let clone = Object.create(null)
let keys = Object.keys(object)
let cur = keys.length
let curTarget
while(cur--){
curTarget = object[keys[cur]]
clone[keys[cur]] = chooseOpeByType(curTarget,clone)
}
return clone
}
chooseOpeByType只是一个选择函数
function chooseOpeByType(curTarget,obj=undefined){
switch(Object.prototype.toString.call(curTarget)){
case '[object Object]':
return dependObject(curTarget)
case '[object Array]':
return dependArray(curTarget)
case '[object Function]':
return dependFunc(curTarget,obj)
default:
return curTarget
}
}
执行函数
接下来是重点,如何clone一个函数?我们想想deepClone有哪几种
- messageChannel 无法发送函数
- JSON.stringify clone了无法使用
但是我们又想到,在实现webworker时,我们可以利用func.string -> blob-> createObjectURL -> webworker实现定制化无需脚本的webworker,我们这里能不能使用呢?
function dependFunc(func){
let funcStr = func.toString()
return function(){
eval(`(${funcStr}).call(ctx)`)
}
}
尝试一下,确实是可以运行的。
正确执行
函数能运行了,问题又来了,this和箭头函数怎么处理呢?
this和箭头函数的执行规律
一眼以蔽之
- 箭头函数的this是最近的非箭头函数的函数this值,或全局this
- this就很简单了,谁调用归谁
于是我们似乎可以暂时不管箭头函数,反正它不属于调用者管。那么对普通函数,this就是调用的作用域咯,把obj传进去试试?
function dependFunc(func,obj){
const ctx = obj
let funcStr = func.toString()
return function(){
eval(`(${funcStr}).call(ctx)`)
}
}
数组?
数组的this很奇怪,它有额外的length属性,所以我们把数组也搞进去吧,于是dependArray和dependObject时传入第二个参数,也就是clone后返回的对象。
问题
当然,箭头函数问题还是没能解决,当它在函数内调用时,箭头函数clone时就会丢掉函数作用域,需要把箭头函数改为非箭头函数,然后让用户自行传入外层作用域,这就比较复杂了。 有好的建议可以分享