抓耳撓腮

感覺已經解決的時候 經過多次以及大數據量測試 發覺各個方式的耗時都沒有不同 就連一開始@二石兄
拋出的假象,為什么遍歷次數多反而耗時少?的現象都不見了 ? 真是令人抓耳撓腮 返回重新看這個問題 重新測試 重新.... 南轅北轍的故事

看了 二師兄@假象,為什么遍歷次數多反而耗時少?拋出的問題
驚訝的發現 還真是!

曾想起在之前的學習過程中,讀到過 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);
                }
            });
        }
    }]);


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容