美文网首页
十道前端面试题第【02】篇

十道前端面试题第【02】篇

作者: 夏海峰 | 来源:发表于2021-03-15 01:05 被阅读0次

    摘要:本篇分享了5道算法题、手写bind函数、跨域解决方案、Vuex工作流程、ES6新特性、学习CSS布局等。


    面试题

    1、运行下面代码,请依次写出控制台打印的顺序。

    console.log(1)
    setTimeout(()=>console.log(2), 0)
    new Promise((resolve,reject)=>{
      console.log(3)
      setTimeout(()=>resolve(4), 0)
    }).then(res=>{
      console.log(res)
      console.log(5)
    })
    requestAnimationFrame(()=>console.log(6))
    console.log(7)
    

    答案:有可能是1 3 7 6 2 4 5,也有可能是1 3 7 2 4 5 6

    2、封装方法 arr2tree,把下面数组转化成树结构。

    # 输入:源数组
    var arr = [
      { id: 0, name: '新闻' },
      { id: 1, name: '体育', pid: 0 },
      { id: 2, name: '篮球', pid: 1 },
      { id: 3, name: '足球', pid: 1 },
      { id: 4, name: 'NBA', pid: 2 },
      { id: 5, name: 'CBA', pid: 2 },
      { id: 6, name: '娱乐', pid: 0 },
      { id: 7, name: '小品', pid: 6 },
      { id: 8, name: '相声', pid: 6 },
    ]
    
    # 输出:树结构
    var tree = [
      { 
        "id": 0, "name": "新闻", 
        "children": [
          { 
            "id": 1, "name": "体育", "pid": 0, 
            "children": [
              { 
                "id": 2, "name": "篮球", "pid": 1, 
                "children": [
                  { "id": 4, "name": "NBA", "pid": 2 }, 
                  { "id": 5, "name": "CBA", "pid": 2 }
                ] 
              }, 
              { "id": 3, "name": "足球", "pid": 1 }
            ] 
          }, 
          { 
            "id": 6, "name": "娱乐", "pid": 0, 
            "children": [
              { "id": 7, "name": "小品", "pid": 6 }, 
              { "id": 8, "name": "相声", "pid": 6 }
            ] 
          }
        ] 
      }
    ]
    
    # 参考答案
    function arr2tree(sourceArr) {
      let obj = {}
      for (let i = 0; i < sourceArr.length; i++) {
        obj[sourceArr[i].id] = sourceArr[i]
      }
      const result = []
      sourceArr.forEach(node => {
        if (!obj[node.pid]) {
          result.push(node)
          return
        }
        obj[node.pid].children = obj[node.pid].children || []
        obj[node.pid].children.push(node)
      })
      return result
    }
    

    3、观察下方示例代码中的输入与输出关系,封装 add() 方法。

    add(1);       // 1
    add(1)(2);    // 3
    add(1)(2)(3); // 6
    add(1)(2,3);  // 6
    add(1,2)(3);  // 6
    add(1,2,3);   // 6
    
    function add() {
      let args = [].slice.call(arguments); 
      let fn = function(){
       let fn_args = [].slice.call(arguments)
       return add.apply(null,args.concat(fn_args))
      }
      fn.toString = function(){
        return args.reduce((a,b)=>a+b)
      }
      return fn
    }
    // 测试:
    add(1,2)(3)(4,5)(6);   // 21
    

    4、封装函数,实现千位分隔符。

    // 保留三位小数
    parseToMoney(1234.56); // return '1,234.56'
    parseToMoney(123456789); // return '123,456,789'
    parseToMoney(1087654.32123); // return '1,087,654.321'
    
    function parseToMoney(num) {
      num = parseFloat(num.toFixed(3));
      let [integer, decimal] = String.prototype.split.call(num, '.')
      integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,')
      return integer + '.' + (decimal ? decimal : '')
    }
    

    5、封装方法求任意两个Number数组的交集。

    举例:输入 num1 = [1, 2, 2, 1]nums = [2, 2, 3],返回 [2, 2]

    function union (arr1, arr2) {
      return arr1.filter(item => arr2.indexOf(item)>-1)
    }
    // 测试
    const a = [1, 2, 2, 1];
    const b = [2, 3, 2];
    union(a, b)   // [2, 2]
    

    6、谈一谈 bind、call、apply的区别,并封装实现一个 bind 函数。

    • call 和 apply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。
    let a = { value: 1 }
    function getValue(name, age) {
        console.log(name)
        console.log(age)
        console.log(this.value)
    }
    getValue.call(a, 'geek', '10')
    getValue.apply(a, ['geek', '30'])
    
    • bind 的实现对比其他两个函数略微地复杂了一点,因为 bind 需要返回一个函数,需要判断一些边界问题,参考代码如下。
    Function.prototype.myBind = function (context) {
      if (typeof this !== 'function') {
        throw new TypeError('Error')
      }
      const _this = this
      const args = [...arguments].slice(1)
      // 返回一个函数
      return function F() {
        // 因为返回了一个函数,我们可以 new F(),所以需要判断
        if (this instanceof F) {
          return new _this(...args, ...arguments)
        }
        return _this.apply(context, args.concat(...arguments))
      }
    }
    

    7、请绘制并描述Vuex的工作流程。

    vuex.png

    8、罗列 ES6 的新特性。

    9、常用的 CSS 布局属性(方案)有哪些?

    10、什么是跨域?什么是浏览器同源策略?有哪些常用的解决跨域方案?手动封装一个JSONP的跨域请求函数。

    • 因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。
    • 常用的跨域解决方案有:JSONP、CORS、代理。
    • JSONP跨域请求函数封装如下:
    # 使用JSONP(函数封装)
    function jsonp(url, jsonpCallback, success) {
      let script = document.createElement('script')
      script.src = url
      script.async = true
      script.type = 'text/javascript'
      window[jsonpCallback] = function (data) {
        success && success(data)
      }
      document.body.appendChild(script)
    }
    // 测试示例
    jsonp('http://xxx', 'callback', function (value) {
      console.log(value)
    })
    
    # 使用JSONP(不封装)
    let script = document.createElement('script');
    script.src = 'http://www.baidu.cn/login?username=JasonShu&callback=callback';
    document.body.appendChild(script);
    function callback (res) {
        console.log(res);
    }
    

    本周结束,下周继续!!!

    相关文章

      网友评论

          本文标题:十道前端面试题第【02】篇

          本文链接:https://www.haomeiwen.com/subject/bcyxcltx.html