感觉已经解决的时候 经过多次以及大数据量测试 发觉各个方式的耗时都没有不同 就连一开始@二石兄
抛出的假象,为什么遍历次数多反而耗时少?的现象都不见了 ? 真是令人抓耳挠腮 返回重新看这个问题 重新测试 重新.... 南辕北辙的故事
看了 二师兄@假象,为什么遍历次数多反而耗时少?抛出的问题
惊讶的发现 还真是!
曾想起在之前的学习过程中,读到过 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);
}
});
}
}]);