美文网首页
抓耳挠腮

抓耳挠腮

作者: 坠入莱茵河 | 来源:发表于2017-11-29 11:44 被阅读0次

    感觉已经解决的时候 经过多次以及大数据量测试 发觉各个方式的耗时都没有不同 就连一开始@二石兄
    抛出的假象,为什么遍历次数多反而耗时少?的现象都不见了 ? 真是令人抓耳挠腮 返回重新看这个问题 重新测试 重新.... 南辕北辙的故事

    看了 二师兄@假象,为什么遍历次数多反而耗时少?抛出的问题
    惊讶的发现 还真是!

    曾想起在之前的学习过程中,读到过 ES6 的 class 是一个基于原型链的一个语法糖

    尝试使用原型链的方式定义这个函数

    
    // es6 Class
    class ParseArray {
      constructor(inputArray) {
          this.inputArray = inputArray
          this.outputArray = [{
              "sub_data": []
          }]
          this.loopLength = 0
      }
      loop(pId, items) {
          this.inputArray.forEach((item, idx) => {
              this.loopLength++
                  if (item[1] === pId) {
                      items.push({
                          main_data: item.slice(2),
                          sub_data: []
                      })
                      delete this.inputArray[idx] // 录入后删掉该条数据 可降低循环次数
                      this.loop(item[0], items[items.length - 1].sub_data)
                  }
          })
      }
    }
    
    console.time("es6class")
    let val = new ParseArray(array.slice())
    val.loop('', val.outputArray[0].sub_data)
    // console.log(JSON.stringify(val.outputArray))
    console.log('es6class', val.loopLength) // => 26
    console.timeEnd("es6class")     // => loop: 3.64501953125ms
    
    
    // es5 prototype
    
    
    function ParseArrayEs5 () {
      this.loopLength = 0
      this.outputArray = []
      this.array2 = JSON.parse(JSON.stringify(array))
    }
    
    ParseArrayEs5.prototype.loop = function(pId, items) { // 注意 箭头表达式的this指向 与function的this指向不一致 function this指向function 箭头表达式this指向函数的上一级
      this.array2.forEach((item, idx) => {
        this.loopLength++
        if (item[1] === pId) {
            items.push({
                main_data: item.slice(2),
                sub_data: []
            })
            delete this.array2[idx] // 录入后删掉该条数据 可降低循环次数
            this.loop(item[0], items[items.length - 1].sub_data)
        }
      })
    }
    
    console.time("es5")
    
    let outputArray666 = new ParseArrayEs5()
    outputArray666.loop('', outputArray666.outputArray)
    console.log('es5', outputArray666.loopLength) // => 26
    console.timeEnd("es5")     // => loop: 0.2919921875ms
    

    Class的运算效率居然差了这么多

    Google 查了一下 常见的分析一般都是 new 一个 Class 要比 new 一个 工厂函数效率要低的多
    测试用例也基本都是循环new Class
    可是本例中只new了一次 照理说 new Class 的损耗只有第一次??

    查看了其他文章中提及 Babel 会将ES6 代码转换为ES5 代码
    这就去转换了一下

    babel转码.png

    仔细查看了一下 和别人文章中讲的一致 创建类时要比原型链复杂许多 具体可以搜索相关文章
    但与本例情况不同 本例中Class 只new了一次 而 递归的部分 才是大头 把注意力放在 _createdClass 下的 value function loop 中
    细看后发现

    value: function loop(pId, items) {
                var _this = this; // 绑定this 
                this.inputArray.forEach(function (item, idx) {
                    _this.loopLength++; // 如果没有临时变量来绑定this, 将会无法获取loopLength
    

    这是function常用的绑定作用域的方式 用一个临时变量来解决 function 作用域 不一致的问题
    但声明临时变量和绑定this是一项多余的动作
    修改一下转码后的代码后

    _createClass(ParseArray, [{
            key: "loop",
            value: function loop(pId, items) {
                // 删除 var _this = this;
                this.inputArray.forEach((item, idx) => { // 原 this.inputArray.forEach(function (item, idx) {
                    this.loopLength++; // 由于修改了作用域 this 生效
                    if (item[1] === pId) {
                        items.push({
                            main_data: item.slice(2),
                            sub_data: []
                        });
                        delete this.inputArray[idx]; // // 由于修改了作用域 this 生效
                        this.loop(item[0], items[items.length - 1].sub_data);
                    }
                });
            }
        }]);
    
    
    
    

    相关文章

      网友评论

          本文标题:抓耳挠腮

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