Why系列:谨慎使用delete (2)

我们可以看一下ES3的定义, ES5的定义是有变动的。

The delete Operator The production UnaryExpression : delete UnaryExpression is evaluated as follows: 1. Evaluate UnaryExpression. 2. If Type(Result(1)) is not Reference, return true. 3. Call GetBase(Result(1)). 4. Call GetPropertyName(Result(1)). 5. Call the [[Delete]] method on Result(3), providing Result(4) as the property name to delete. 6. Return Result(5).

我简单翻译一下,可能不太正确哈:

执行一元表达式

如果第一步返回的未被引用,返回真

console.log(delete xxxxxxxxxx) //true console.log(delete "a") // true console.log(delete {a:1}) // true console.log(delete 1) // true

取到对象

取属性名

用第四步获得的属性名,在第三步返回的结果上进行删除操作

返回第五步返回的结果。

这里的Resuslt(1)本身应该不是数据本身,类似一个引用地址吧。

小结一下

delete 返回false, 一定是没删除成功

delete 返回true, 不一定删除成功
所以,delete返回true,最好自己再动手检查一下。万无一失。

额,我是不是跑题了,今天的主题,不是告诉你如何使用delete,而是谨慎用delete。

比较一下性能

我们先创建1万个对象,每个对象都有p0到p24 一共25个属性。
然后我们按照一定的规则删除属性设置属性为undefined

function createObjects(counts = 10000) { var arr = []; for (let i = 0; i < counts; i++) { const obj = {}; // for (let j = 0; j < pcounts; j++) { // obj[`p${j}`] = `value-${i}-${j}`; // } arr.push({ "p0": `value-${i}-0`, "p1": `value-${i}-1`, "p2": `value-${i}-2`, "p3": `value-${i}-3`, "p4": `value-${i}-4`, "p5": `value-${i}-5`, "p6": `value-${i}-6`, "p7": `value-${i}-7`, "p8": `value-${i}-8`, "p9": `value-${i}-9`, "p10": `value-${i}-10`, "p11": `value-${i}-10`, "p12": `value-${i}-10`, "p13": `value-${i}-10`, "p14": `value-${i}-10`, "p15": `value-${i}-10`, "p16": `value-${i}-10`, "p17": `value-${i}-10`, "p18": `value-${i}-10`, "p19": `value-${i}-10`, "p20": `value-${i}-10`, "p21": `value-${i}-10`, "p22": `value-${i}-10`, "p23": `value-${i}-10`, "p24": `value-${i}-10` }); } return arr; } const arr = createObjects(); const arr2 = createObjects(); console.time("del"); for (let i = 0; i < arr.length; i++) { const rd = i % 25; delete arr[i][`p${rd}`] } console.timeEnd("del"); console.time("set"); for (let i = 0; i < arr2.length; i++) { const rd = i % 25; arr2[i][`p${rd}`] = undefined; } console.timeEnd("set"); // del: 31.68994140625 ms // set: 6.875 ms // del: 24.43310546875 ms // set: 3.7861328125 ms // del: 79.622802734375 ms // set: 3.876953125 ms // del: 53.015869140625 ms // set: 3.242919921875 ms // del: 18.84619140625 ms // set: 3.645751953125 ms

我们记录了大约五次执行事件对比。
可以看出来delete 时间不稳定,而且性能低不少。

到这里,我们还不要惊讶。看我稍微改动一下代码:

function createObjects(counts = 10000) { var arr = []; for (let i = 0; i < counts; i++) { const obj = {}; // for (let j = 0; j < pcounts; j++) { // obj[`p${j}`] = `value-${i}-${j}`; // } arr.push({ 0: `value-${i}-0`, 1: `value-${i}-1`, 2: `value-${i}-2`, 3: `value-${i}-3`, 4: `value-${i}-4`, 5: `value-${i}-5`, 6: `value-${i}-6`, 7: `value-${i}-7`, 8: `value-${i}-8`, 9: `value-${i}-9`, 10: `value-${i}-10`, 11: `value-${i}-10`, 12: `value-${i}-10`, 13: `value-${i}-10`, 14: `value-${i}-10`, 15: `value-${i}-10`, 16: `value-${i}-10`, 17: `value-${i}-10`, 18: `value-${i}-10`, 19: `value-${i}-10`, 20: `value-${i}-10`, 21: `value-${i}-10`, 22: `value-${i}-10`, 23: `value-${i}-10`, 24: `value-${i}-10` }); } return arr; } const arr = createObjects(); const arr2 = createObjects(); console.time("del"); for (let i = 0; i < arr.length; i++) { const rd = i % 25; delete arr[i][rd] } console.timeEnd("del"); console.time("set"); for (let i = 0; i < arr2.length; i++) { const rd = i % 25; arr2[i][rd] = undefined; } console.timeEnd("set"); // del: 1.44189453125 ms // set: 2.43212890625 ms // del: 1.737060546875 ms // set: 3.10400390625 ms // del: 1.281005859375 ms // set: 2.85107421875 ms // del: 1.338134765625 ms // set: 1.877197265625 ms // del: 1.3203125 ms // set: 2.09912109375 ms

到这里,画风一转。 del居然比set还快了。。。。。。
而set的速度实际基本没有什么变化。

常规属性 (properties) 和排序属性 (element)

这里就要提出几个概念:
常规属性 (properties)排序属性 (element)

上面的代码变化不多,就是属性名称从p0格式修改为了0格式。
p0正式常规属性,0是排序属性。

对象中的数字属性称为排序属性,在 V8 中被称为 elements。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxwff.html