最近在学习JavaScript中的闭包,涉及到其中一个案例,想着改写一下。案例挺简单,但是改bug过程有些曲折,在此分享一下在改bug过程中的自我怀疑自我否定直到曲径通幽的心路历程。
需求说明:我们知道arguments对象如果想调用Array的push方法,需要使用Array.prototype.push.apply(argument,[1,2])这样的方式,但每次都写这么一长串代码特别繁琐,想着提取一个push方法,方便以后直接调用。
废话不多说,,直接贴代码。
//提取的方法
var push = (function(){
return function(){
var obj = Array.prototype.shift.apply(arguments);
Array.prototype.push.apply(obj,arguments);
return arguments;
}
})()
方法洋洋洒洒写完之后,进入自测阶段。为了偷懒,再次使用了自执行函数,代码如下:
//自测代码
(function(){
push(arguments,4)
console.log(arguments);
})(1,2,3)
在node环境中执行,结果抛错如下:
Array.prototype.push.apply(obj,arguments);
^
TypeError: Cannot assign to read only property 'length' of function 'function (){
push(arguments,4)
console.log(arguments);
}'
这个报错很明显,当给一个function调用Array.porotype.push方法时会抛出这样的错误,因为一个function的length属性是只读的,而push的源码中length属性是需要可以修改的,即一个对象具有可读写的length属性之后才可以调用Array.porototype.push方法。
回到我提取的push方法中分析,Array.prototype.push.apply(obj,arguments);此刻我的obj应该是一个类数组{ '0': 1, '1': 2, '2': 3 },所以报错提示无法直观解决问题。
首先为了排除测试案例的原因,我修改了我的测试案例,避免function的介入,代码如下:
//测试案例
var fn = function(){
push(arguments,4);
console.log(arguments);
}
fn(1,2,3);
修改完成之后发现测试顺利通过,说明我提取的方法没有问题。到此,牵扯出了一个新问题,我使用自执行函数时为啥会导致出错。
首先来到我脑海的原因是自执行函数的执行顺序,是否有异步一说。因为我提取push方法也是用的自执行函数,测试案例也是自执行函数,有可能两自执行函数的先后执行顺序导致了问题,为了验证这个答案,我决定将自测案例延时执行,代码如下:
setTimeout(function(){
(function(){
push(arguments,4)
console.log(arguments);
})(1,2,3)
},10);
测试发现顺利通过,这个测试结果更加怀疑了刚才的假设(虽然心里一万个不相信)。然后开始查js自执行函数的执行顺序的问题,未果,说明大家都没遇到这样的问题,那很有可能我这假设不对。没办法,只能继续修改测试,既然是因为调用push.apply时候出错,我先注释掉它试试。代码如下:
//提取方法代码
var push = (function(){
return function(){
var obj = Array.prototype.shift.apply(arguments);
// Array.prototype.push.apply(obj,arguments);
return arguments;
}
})()
//测试案例代码
(function(){
// push(arguments,4)
console.log(arguments);
})(1,2,3)
运行结果,抛出了不一样的错误,不一样的烟花,错误如下
D:\github\jsStudy\heightFn.js:174
})(1,2,3)
^
TypeError: (intermediate value)(...)(...) is not a function
这个错误提示很容易定位到了问题,自执行函数结尾未写分号导致。
这个问题其实是一个小问题导致的,无关乎技巧。分享这个主要是想表达:在遇到问题时,我们看到的问题可能只是表象,寻找解决方案的过程就是一个不断自我猜想,验证猜想,不断否定的过程,需要持续不断的挖掘。
最后贴出最终代码:
var push = (function(){
return function(){
var obj = Array.prototype.shift.apply(arguments);
Array.prototype.push.apply(obj,arguments);
return arguments;
}
})();
//测试案例
;(function(){
push(arguments,4)
console.log(arguments);
})(1,2,3);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。