«

»

Feb 21 2017

Javascript坑两则

偶然在SegmentFault上看到个链接,结果引导到知乎上了:如果你想靠前端技术还房贷,你不能连这个都不会。里面提出了两个问题:

注意,蓝色文本为完全引用知乎原文:

第一个是经典问题,考察闭包的使用:

第一问,这段代码输出什么?第二问,如果想让这段代码输出0123456789,应该怎么修改?

 

第二个问题是口述实现,设计场景如下:

请问如何设计代码,解决这个问题?

解答

第一题

第一题我以为答案是10个null,后来发现这是js不是php。

setTimeout执行的函数是在线程结束后才执行的,所以会一口气执行10个function () {console.log(i)},这时的i是循环结束时的i,所以i==10,所以输出10个10。

如果想要输出0123456789,setTimeout的时候给console.log给值0123456789,再引入个变量并执行就好了。

不过我就纳了闷了,这道题真的要用闭包这种方法去解决吗?为什么不直接把var换成let?

总感觉出题者意淫的厉害。

第二题

我用jquery的ajax试了一下,写了70行左右代码。当然是有优化余地的,但是没什么心情。

主要思想是flag,即最后点击的哪个按钮,就显示哪个按钮的结果,渲染的时候不由ajax.success来做,而交给一个专门刷新input的函数来做,ajax.success只处理返回的数据和触发刷新。

至少这个思路简单且完全没有阻塞。下面讨论有纯阻塞的,也有队列的。感觉用队列的思路不错,不过我不知道什么时候从队列里触发刷新。我主职是linux和php,对js只了解常用的,而且对MVVM不熟。

那篇文章下面精选评论说10行代码就能搞定的,我有点纳闷。

嘛,农民们都是充满了鄙视链的,而且这毕竟是逼乎嘛。

再说了,连Git都不会用的都能买得起房,工资收入什么的跟技术没什么关系。主要还是看风大不大,跟猪重不重没什么关系。

当然了,真的会飞的猪还是很NB的!

全部代码

有考虑传到GitHub上,但是感觉自己写的太渣,再说吧。

7 comments

Skip to comment form

  1. 第一个问题:
    console.log结尾是会换行的,我不知道上面代码是怎么可能输出0123456789的
    第二个问题
    既然你的b都已经比a慢了,又要显示a,直接等2个都返回结果不就行了
    ···
    let res = await Promise.all([fetch(A),fetch(B)]);
    ele.value = res[0].body;
    await sleep(2000);
    ele.value = res[1].body;
    ···
    反正最重要的效果是A,B都要显示

    或者就是先创建2个Promise
    利用Promise.race,判断最快的是不是A,如果是b就await A, ele.val = a.body,然后再从B赋值。反之亦然

    1. 石樱灯笼

      不要太纠结细节,纠结细节的话没一道题是正经题。

      1. yolo

        真的还都是比较正经的题目。类似的场景经常能遇到的。

  2. 阿偶,第二题好像看错了。。
    那就存一个变量记录fetching状态好了www
    如果fetching = true 就 setInterval 自己,在定时的函数里检查fetching以赋值。只有A,B2个用boolean就够了
    多了用个number存order…

  3. yolo

    看幽灵诡计的东西偶然看到这个文章,一个是闭包,一个是异步,都是很基础但是非常核心的内容。
    第一个直接加个匿名函数就行:
    for (var i = 0; i < 10; ++i) {
    (function(i) {
    setTimeout(function () {console.log(i)}, 0);
    })(i)
    }

    第二题,可以实现的方式很多,比较好的处理方式是,抛开A、B、C、D,不管有多少个请求,也不管哪个请求比较快哪个请求比较慢。构造一个通用的场景,记录最后一次试图触发input修改的时间戳,当执行修改的时候验证是否一致。大概结构:

    const inputObj = {
    lastTrigger,
    triggerChange(thisTime) {
    // 在这里可以验证是否真正执行修改
    }
    }

  4. shyling

    对了,之前回复忘了说…

    第一个和闭包没什么关系的。。只是 var i 在 for 里不会在每次 loop 自动 copy,setTimeout 的 Task 会在当前代码执行完成后执行。

    闭包是指 自由变量被函数捕捉带出了作用域。
    而在你的例子里var j = i; 和 楼上的例子里的 IIFE 都是把循环的变量复制了一遍而已。

    唔,所以说没必要写的这么麻烦啦。


    for (var i = 0; i < 10; ++i) {
    setTimeout(function (i) {console.log(i)}, 0, i);
    }

    这个东西自己是有补自己的坑的,setTimeout(fn,delay[, …args])

    1. 石樱灯笼

      额外复制一个变量其实是个习惯。因为很多人的很多代码写的都很烂,i 很有可能有在其他作用域里存在(当然这个例子里的i是干净的),额外复制一份,就可以在自己的代码块中随意修改了。
      如果不这样做,很有可能会因为你的代码「本身没问题」,却在添加到项目中后其他功能就挂掉,导致最终 Bug 分配到你头上。那种全局级别的垃圾代码不是你想修就能修得了的,尽量避免引屎上身。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据