背景😯
今天重刷 leetcode 的时候,刷到这么一道题102. 二叉树的层序遍历,很简单的二叉树遍历题目,三下五除二把代码写了出来
其他代码都不重要,重要的是第 27 行那里。
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*//*** @param {TreeNode} root* @return {number[][]}*/var levelOrder = function(root) {if(!root) return[]const res = [],que = [root, null]let tmpLevel = []while(que.length){const t = que.shift()if(t){tmpLevel.push(t.val)t.left && que.push(t.left)t.right && que.push(t.right)}else {// t为nullres.push(tmpLevel)// tmpLevel.length = 0tmpLevel = [] //第27行que.length && que.push(null)}}return res};
const 和 let 的书写习惯
其他代码都不重要,重要的是第 27 行那里。我个人写代码的习惯时,能用const就用const,用了const后面要修改时报错了再改为let。
不知道你们是怎么呢
所以自然我的tmpLevel一开始就是用const定义,也就自然而然地在tmpLevel = []处报错了。
改成let定义后,也是自然而然地过了,但是我一下想起来,好像用tmp.length = 0就能清空数组呀,还不用改const~ 说不定性能还高一点? 真机(han)智(han) [doge]
数组清空的方式😏
splice
首先是 JavaScript 数组自身API:splice
arr.splice 方法可以说是处理数组的瑞士军刀。它可以做所有事情:添加,删除和插入元素。
语法:
arr.splice(start[, deleteCount, elem1,..., elemN])它从索引 start 开始修改 arr:删除 deleteCount 个元素并在当前位置插入 elem1, …, elemN。最后返回已被删除元素的数组。
那直接从下标为 0,删掉数组长度那么长不就好了~
let arr = [1,2,3]arr.splice(0,arr.length);console.log(arr)//[]
arr.length
如果我们手动增加它,则不会发生任何有趣的事儿。但是如果我们减少它,数组就会被截断。该过程是不可逆的
let arr = [1, 2, 3, 4, 5];arr.length = 2; // 截断到只剩 2 个元素console.log(arr); // [1, 2]arr.length = 5; // 又把 length 加回来console.log(arr[3]); // undefined:被截断的那些数值并没有回来
也就是说,我们直接将其赋值为0 就行
let arr = [1, 2, 3, 4, 5];arr.length = 0console.log(arr); // []
= []
直接将 arr 重新赋值为空数组,之前的数组如果没有被引用就等待垃圾回收就完事了~
三种方式的性能比较😎
我当时就想啊,算法题,肯定要追求一下效率的吗,上性能最好的干他~
测试
let a = [];console.time('splice');for(let i =0 ; i < 10;i++){a = new Array(100).fill(111)a.splice(0,a.length);}console.timeEnd('splice');console.time('length');for(let i =0 ; i < 10;i++){a = new Array(100).fill(111)a.length = 0;}console.timeEnd('length');console.time('赋值[]');for(let i =0 ; i < 10;i++){a = new Array(100).fill(111)a = [];}console.timeEnd('赋值[]')
一开始用了贼大的循环,直接卡死了🙃
结果

ok 那就是直接赋值性能最好, 直接修改 length 为0 性能其次,但是相差不多呀,用lenngth还能保持我使用const的习惯,那就上 第二种方法呗
结果😐

结果一看,不对劲啊,这清零怎么把最后结果的也给清了,猛地一下想到原因,直呼自己睿智
原因
其实这个我是知道的,但是写题的时候真就没想起来
注意 JS 数组重置的方式,虽然经测试arr.length = 0的速度会比arr = []快很多,但是这样是得不到正确答案的,原因是因为:
arr =[]创建的是一个新的数组,并为其赋予一个新的引用。其他引用不收影响,仍指向原数组
arr.length = 0修改数组本身,就算通过不同的变量访问它,得到的是同一个数组
直观测试
测试图解

也就是说 =[] 是创建了一个新数组,length=0之后操作的仍是原来的引用~所以答案数组中的自然也就给一同清零了
总结🤔
唉这个东西,真是基础不牢地洞山摇啊~虽然是非常基础的知识点,但是可能到实际运用中就可能带来一些没料到的 bug 。
一开始测到性能差异,先入为主的就以为因为=[]会创建一个新的引用吗~就会导致性能较差,导致性能测试结果都看歪来了😖也就导致自己”美滋滋地”用上不用改const的方法…
不过有时这也说明,该用 let时就用let啊,不要头铁…
基础、基础,还是 的基础!
