资讯专栏INFORMATION COLUMN

一次关于bug的自我否定

levy9527 / 326人阅读

摘要:案例挺简单,但是改过程有些曲折,在此分享一下在改过程中的自我怀疑自我否定直到曲径通幽的心路历程。首先来到我脑海的原因是自执行函数的执行顺序,是否有异步一说。这个问题其实是一个小问题导致的,无关乎技巧。

最近在学习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:githubjsStudyheightFn.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);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94018.html

相关文章

  • JavaScript代码风格要素

    摘要:删除不必要的代码。而简化前的代码包含的语法要素对于传达代码意义本身作用并不大。删除不必要的代码有时候,我们试图为不必要的事物命名。例如,大多数情况下,你应该省略仅仅用来当做返回值的变量。你的函数名应该已经说明了关于函数返回值的信息。 原文地址 本文已在前端早读课公众号首发:【第952期】JavaScript代码风格要素 译者:墨白 校对:野草 1920年,由威廉·斯特伦克(Will...

    YPHP 评论0 收藏0
  • 异步 JavaScript 与 Promise

    摘要:为这些回调函数分别命名并分离存放可以在形式上减少嵌套,使代码清晰,但仍然不能解决问题。如果在一个结束成功或失败,同前面的说明后,添加针对成功或失败的回调,则回调函数会立即执行。 异步? 我在很多地方都看到过异步(Asynchronous)这个词,但在我还不是很理解这个概念的时候,却发现自己常常会被当做已经很清楚(* ̄ロ ̄)。 如果你也有类似的情况,没关系,搜索一下这个词,就可以得到大致...

    livem 评论0 收藏0
  • Clean Code之JavaScript代码示例

    摘要:坏的命名方式好的命名方式避免使用过多参数。你只需要在每一个函数的末尾返回,之后的代码会更加的简洁。在很多情况下,你可能搞出重复代码。自从年双十一正式上线,累计处理了亿错误事件,付费客户有金山软件百姓网等众多品牌企业。 译者按: 简洁的代码可以避免写出过多的BUG。 原文: JavaScript Clean Code - Best Practices 译者: Fundebug ...

    zhangrxiang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<