假设我创建一个对象如下:
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
删除属性regex
以最终使用新的myObject
的最佳方法是什么,如下所示?
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI"
};
喜欢这个:
delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];
演示
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
delete myObject.regex;
console.log(myObject);
对于有兴趣阅读更多相关内容的人来说,Stack Overflow 用户kangax在他们的博客上发表了一篇关于delete
声明的非常深入的博客文章, 了解删除 。强烈推荐。
delete
意外慢! 看看基准 。
删除是删除对象属性而没有任何剩余的唯一真正方法,但与其 “替代” 相比,它的工作速度要慢 100 倍 ,设置object[key] = undefined
。
这个替代方案不是这个问题的正确答案!但是,如果你小心使用它,你可以大大加快一些算法。如果您在循环中使用delete
并且性能有问题,请阅读详细说明。
delete
并将设置值设置为undefined
? 对象可以被视为一组键值对。我称之为 '值' 的是原始的或对其他对象的引用,与该'key' 相关联。
当您将结果对象传递给您无法控制的代码时(或者您不确定您的团队或您自己时) ,请使用delete
。
它从 hashmap 中删除密钥 。
var obj = {
field: 1
};
delete obj.field;
当您关心性能时,请使用设置为undefined
。它可以大大提升您的代码。
密钥保留在 hashmap 中的位置 ,只有值被undefined
替换。明白, for..in
循环仍会迭代该键。
var obj = {
field: 1
};
obj.field = undefined;
使用此方法,并非所有确定属性存在的方法都将按预期工作。
但是,这段代码:
object.field === undefined
两种方法的行为都相同。
总而言之,差异都是关于确定属性存在的方法,以及关于for..in
循环的方法。
console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."');
console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *');
console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *');
console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\'s type is "undefined". *');
console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *');
console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!');
//Object.keys().indexOf() is an overkill that runs much slower :)
var counter = 0,
key;
for (key in obj) {
counter++;
}
console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *');
虽然使用obj[prop] = undefined
比delete obj[prop]
更快,但另一个重要的考虑因素是obj[prop] = undefined
可能并不总是合适的。 delete obj[prop]
从obj
删除prop
并从内存中删除它,而obj[prop] = undefined
只是将prop
的值设置为undefined
,使prop
仍然在内存中。因此,在创建和删除许多密钥的情况下,使用obj[prop] = undefined
会强制进行昂贵的内存协调(导致页面冻结)并可能导致内存不足错误。检查以下代码。
"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
nodeRecords[i] = [];
current = theNodeList[i] = document.createElement("div");
current.textContent = i;
document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
var currentTime = Math.round( performance.now()*1000 )
for (i = 0; i !== numberOfNodes; i++) {
if (lastTime !== -1) {
// the previously collected data is no longer in use
/*************************************************/
/****/ nodeRecords[i][lastTime] = undefined; /****/
/*************************************************/
}
nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
}
lastTime = currentTime;
requestAnimationFrame( recordUpdates );
});
在上面的代码中,只需执行nodeRecords[i][lastTime] = undefined;
因为每个动画帧都会导致大量的内存泄漏。每个帧,所有 65536 个 DOM 元素将占用另外 65536 个单独的插槽,但之前的 65536 个插槽只会被设置为未定义,这会使它们挂在内存中。来吧,尝试在控制台中运行上面的代码并亲自查看。强制出现内存不足错误后,尝试再次运行它,除非使用以下版本的代码使用delete
运算符。
"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
nodeRecords[i] = [];
current = theNodeList[i] = document.createElement("div");
current.textContent = i;
document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
var currentTime = Math.round( performance.now()*1000 )
for (i = 0; i !== numberOfNodes; i++) {
if (lastTime !== -1) {
// the previously collected data is no longer in use
/********************************************/
/****/ delete nodeRecords[i][lastTime]; /****/
/********************************************/
}
nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
}
lastTime = currentTime;
requestAnimationFrame( recordUpdates );
});
如上面的代码片段所示, delete
运算符有一些罕见的适当用例。但是,不要太担心这个问题。这只会成为长寿命对象的问题,这些对象会不断添加新密钥。在任何其他情况下(几乎在实际编程中都是这种情况),最合适的是使用obj[prop] = undefined
。本节的主要目的只是为了引起您的注意,以便在您的代码中这很可能成为一个问题,那么您可以更轻松地理解问题,从而不必浪费时间来解析您的代码来定位并了解这个问题。
undefined
Javascript 的一个重要考虑因素是多态性。多态性是指分配相同变量 / 对象中的不同类型,如下所示。
var foo = "str";
foo = 100; // variable foo is now labeled polymorphic by the browser
var bar = ["Some", "example"];
bar[2] = "text"; // bar is a monomorphic array here because all its entries have the
// same type: string primitive
bar[1] = undefined; // bar is now a polymorphic array
但是,多态数组有两个主要的无法解决的问题:
人们可能将多态性比作药物成瘾。乍一看,它似乎非常有利可图:漂亮的蓬松代码。然后,编码器将他们的阵列引入多态性药物。即时地,多态数组变得效率较低,并且由于它是药物,它永远不会像以前那样有效。为了将这种情况与现实生活联系起来,可卡因的某些人甚至可能无法操作简单的门把手,更不用说能够计算 PI 的数字了。同样,多态性药物上的阵列也不能像单态阵列那样有效。
但是,药物旅行类比如何与delete
操作相关?答案在上面的代码片段中包含了最后一行代码。因此,让它重新审视,这次是扭曲。
var bar = ["Some", "example"];
bar[2] = "text"; // bar is not a polymorphic array here because all its entries have the
// same type: string primitive
bar[1] = ""; // bar is still a monomorphic array
bar[1] = undefined; // bar is now a polymorphic array
观察。 bar[1] = ""
不强制多态,而bar[1] = undefined
。因此,应该始终尽可能为对象使用相应的类型,以免意外地导致多态性。一个这样的人可以使用以下列表作为一般参考来使他们前进。但是,请不要明确使用以下想法。相反,使用任何适用于您的代码的方法。
false
或undefined
作为空值。虽然避免不必要的多态性是好的,但重写所有代码以明确禁止它可能实际上会导致性能下降。使用共同的判断! 0
作为空值。请注意,在内部,有两种类型的数字:快速整数(包括 2147483647 到 - 2147483648)和慢浮点双精度(包括NaN
和Infinity
在内的任何其他内容)。当一个整数降级为 double 时,它不能被提升回整数。 ""
作为空值。 null
。 不过,请注意!现在不要突然开始使用所有预先存在的代码执行此操作,因为它可能会破坏此类预先存在的代码和 / 或引入奇怪的错误。相反,这种有效的实践需要从一开始就实现,并且在转换预先存在的代码时,建议您对所有与之相关的行进行双倍,三倍,四倍检查,因为尝试将旧代码升级到此新实践可以是有风险,因为它是有益的。
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
这适用于 Firefox 和 Internet Explorer,我认为它适用于所有其他人。