前端做题家之JavaScript

最近精神状态不太好,没心思写博客。前段时间听说了牛客网,看到上面全是面试题,虽然并不打算找工作,但是做题家的属性觉醒了,就每天做点题玩一玩。虽然我一直自诩“语言律师”,但是看到这些刁钻的面试题,还是有点应付不过来……

不过,今天已经把JS的技能值刷满了,稍微有点心得,想了想觉得还是写个博客,摘录一些我觉得比较有意思的题目。名义上是JS的题目,其实并不完全是,还是有一些别的领域的内容。

  1. 如果不给cookie设置过期时间会怎么样?

    会在浏览器会话结束时过期。

    事实上,我还真没试过……不过我倒是想到了sessionStorage

  2. 下列代码存在几个变量没有被回收?

    var i = 1;
    var i = 2;
    var add = function() {
        var i = 0;
        return function() {
            i++;
            console.log(i);
        }
    }();
    add();
    

    3个。为啥不是2个?别忘了add也是一个变量……当时看到这个我差点吐血。

  3. 以下代码的输出结果是:

    var f = function g() {
        return 23;
    };
    typeof g();
    

    报错,没输出,因为g is not defined。那么函数表达式里的g是干啥的?用于指定函数的name。函数表达式在这一块和函数声明还是有很大区别的。

    f.name // "g"
    
  4. 以下哪些选项可以将集合A转化为数组?

    • Array.from(A)
    • [].slice.apply(A)
    • [...A]
    • [].map.call(A, o => o)

    看起来第二个和第四个也是对的,但是实际运行起来并不会生效,返回的是一个空数组。至于为什么会这样,因为slicemap是基于目标的length属性来进行处理的,Set并没有length属性(用的是size),所以不会生效。

    同时,map还有一个tricky的地方,会跳过数组中的空当;也就是说,不会对数组中empty的地方做处理。这个后面会说。

  5. 以下表达式不会出现错误的有:

    • 2.toString()
    • 2..toString()
    • 2 .toString()
    • (2).toString()

    这其实也是一个老生常谈的话题。由于无法分辨数字后面紧跟的那个.到底是小数点还是方法调用,所以直接toString是会报错的。想要不报错,就要让小数点和方法调用区分开。多加一个点、多加一个空格、加个括号都是可以的。

  6. JS的全局函数。

    这个我上次专门写了一篇文章,探讨这个问题。并且,我还是对全局函数这个概念本身存在疑义。

    全局函数到底是全局作用域里的函数,还是仅仅指全局对象里的函数,似乎并不太明确。如果不严格地说,全局作用域里的函数都可以算是全局函数,这其实也更符合我们平时使用时的习惯。不过,如果从狭义上说,可能在全局作用域中预定义的函数才是全局函数。

  7. 什么操作会触发reflow(重排,或译为回流)?

    与之并列的往往还有一个问题,什么操作会触发repaint(重绘)?

    我个人理解,重排是在布局可能发生变化时触发的,重绘则是在不改变布局的样式发生变化时触发的。减少重排对于性能优化来说非常重要,我个人觉得这也是骨架屏的一个意义所在,提前渲染好占位元素可以减少异步数据到达时的重排损耗。

    重排主要有这么几种情况吧,我觉得这篇文章写得挺好的,摘录如下:

    1. 改变窗囗大小
    2. 改变文字大小
    3. 添加/删除样式表
    4. 内容的改变,如用户在输入框中敲字
    5. 激活伪类,如:hover (IE里是一个兄弟结点的伪类被激活)
    6. 操作class属性
    7. 脚本操作DOM
    8. 计算offsetWidth和offsetHeight(以及scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft等等属性,主要是需要获得当前最新的位置,所以必须触发一次重排)
    9. 设置style属性
  8. 如何判断一个js对象是否是Array, arr为要判断的对象?

    Object.prototype.toString.call(arr) === '[object Array]';

    事实上一直是这么用的,但是为什么用instanceof不行,倒是值得商榷。其实正常情况下是可以的,但是在跨frame的情况下就不行了。比如这段代码(摘自这篇文章):

    var iframe = document.createElement('iframe');   
    document.body.appendChild(iframe);   
    xArray = window.frames[window.frames.length-1].Array;      
    var arr = new xArray("1","2","3","4","5");
    
    alert(arr instanceof Array); // false
    alert(arr.constructor === Array); // false
    

    因为跨frame了,所以constructor.prototype肯定不会出现在目标的原型链上,就无法正确判断了。

  9. require的模块查找机制

    这里先留个坑,后面搞明白了会仔细说这个事情,因为我自己也搞不太清楚,只用过CommonJS(而且用得也不多,Node没怎么用过,现在主要是用Java),后面就一直用ES6的exports和import了。

    主要是这么一个顺序,先是内置模块,再是按路径依次查找.js .json .node,最后是node_modules/里的模块,然后依次往上,直到找不到报错。

  10. 页面生命周期,摘自这篇文章

    • script executed
    • readyState : interactive
    • DOMContentLoaded
    • image onload
    • iframe onload
    • readyState : complete
    • window onload

    同步的Script总是先于其它事件执行,而window.onload事件总是最后执行。而image onload和iframe onload的先后顺序并不确定。

  11. 能够冒泡与不能冒泡的事件,我觉得这个整理挺好的:

    不过,如果可以现场写代码的话,倒是可以通过这个属性来判断一下:event.bubbles

  12. 以下哪种js中字符串连接方式较为高效:

    • a+=b
    • a = a+b
    • Array.join()
    • Array.push()

    这个问题其实并不太具有参考价值,因为现代浏览器已经基本上做了优化了,不太会有很大的差别。但是在早期的时候(IE时代),对字符串数组使用join是最高效的。

    我个人怀疑这个和C++的实现有关,因为+运算符返回的是新创建的对象,而+=运算符是直接在后面添加,返回的是引用。

    X& operator+=(const X& rhs);
    X operator+(const X& rhs);
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值