我在 JavaScript 中有一个全局变量(实际上是一个 window
属性,但我认为这并不重要),它已经由以前的脚本填充,但我不希望稍后运行另一个脚本来查看它的值或它甚至被定义。
我放了 some_var = undefined
,它用于测试 typeof some_var == "undefined"
,但我真的认为这不是正确的方法。
你怎么看?
delete
运算符从对象中删除属性。它不能删除变量。所以问题的答案取决于全局变量或属性是如何定义的。
(1) 如果用var
创建,则不能删除。
例如:
var g_a = 1; //create with var, g_a is a variable
delete g_a; //return false
console.log(g_a); //g_a is still 1
(2) 如果创建时没有var
,可以删除。
g_b = 1; //create without var, g_b is a property
delete g_b; //return true
console.log(g_b); //error, g_b is not defined
技术说明
1. 使用 var
在这种情况下,引用 g_a
是在 ECMAScript 规范所称的“VariableEnvironment”中创建的,它附加到当前范围 - 这可能是在函数内部使用 var
的情况下的函数执行上下文(尽管当您考虑 let
) 或在“全局”代码的情况下,VariableEnvironment 附加到全局对象(通常为 window
)可能会变得更复杂一些。
VariableEnvironment 中的引用通常不可删除 - ECMAScript 10.5 中详述的过程详细解释了这一点,但只要说除非您的代码在 eval
上下文中执行(大多数浏览器-基于开发控制台使用),则不能删除用 var
声明的变量。
2.不使用var
当试图在不使用 var
关键字的情况下为名称分配值时,JavaScript 会尝试在 ECMAScript 规范所称的“LexicalEnvironment”中定位命名引用,主要区别在于 LexicalEnvironment s 是嵌套的——即 LexicalEnvironment 有一个父级(ECMAScript 规范称之为“外部环境引用”),当 JavaScript 无法在 LexicalEnvironment 中找到引用时,它在父 LexicalEnvironment 中查找(详见 10.3.1 和 10.2.2.1)。顶层 LexicalEnvironment 是“global environment”,它绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您尝试访问未在当前范围或任何外部范围内使用 var
关键字声明的名称,JavaScript 最终将获取 window
对象的属性以用作该引用。正如我们之前所了解的,对象的属性可以被删除。
笔记
重要的是要记住 var 声明是“提升的”——即它们总是被认为发生在它们所在作用域的开头——尽管不是可能在 var 语句中完成的值初始化——即留在这是。因此,在下面的代码中,a 是来自 VariableEnvironment 而不是 window 属性的引用,它的值在代码末尾将为 10: function test() { a = 5;变量 a = 10;上面的讨论是当“严格模式”没有启用时。使用“严格模式”时查找规则有点不同,在没有“严格模式”的情况下解析为窗口属性的词法引用将在“严格模式”下引发“未声明的变量”错误。我真的不明白这是在哪里指定的,但它是浏览器的行为方式。
scunliffe's answer 会起作用,但从技术上讲,它应该是
delete window.some_var;
当目标不是对象属性时,删除应该是空操作。例如,
(function() {
var foo = 123;
delete foo; // wont do anything, foo is still 123
var bar = { foo: 123 };
delete bar.foo; // foo is gone
}());
但是由于全局变量实际上是窗口对象的成员,所以它可以工作。
当涉及原型链时,使用 delete 变得更加复杂,因为它只从目标对象中删除属性,而不是原型。例如,
function Foo() {}
Foo.prototype = { bar: 123 };
var foo = new Foo();
// foo.bar is 123
foo.bar = 456;
// foo.bar is now 456
delete foo.bar;
// foo.bar is 123 again.
所以要小心。
注意:我的答案是somewhat inaccurate(见最后的“误解”)。该链接解释了所有血淋淋的细节,但总结是浏览器之间可能存在很大差异,具体取决于您要从中删除的对象。 delete object.someProp
通常应该与 object !== window
一样安全。我仍然不会使用它来删除用 var
声明的变量,尽管您可以在适当的情况下。
var
声明的变量的唯一情况是使用 eval
声明的变量。
如果您在没有 var
的情况下隐式声明变量,则正确的方法是使用 delete foo
。
但是,在您删除它之后,如果您尝试在诸如添加之类的操作中使用它,则会抛出 ReferenceError
,因为您无法将字符串添加到未声明的未定义标识符。例子:
x = 5;
delete x
alert('foo' + x )
// ReferenceError: x is not defined
在某些情况下,将其分配给 false、null 或 undefined 可能更安全,因此它被声明并且不会引发此类错误。
foo = false
请注意,在 ECMAScript 中,null
、false
、undefined
、0
、NaN
或 ''
都将计算为 false
。只需确保在类型检查布尔值时不使用 !==
运算符而是使用 !=
并且您不希望进行身份检查(因此 null
将使用 == false
和 false == undefined
)。
另请注意,delete
不会“删除”引用,而只是直接在对象上的属性,例如:
bah = {}, foo = {}; bah.ref = foo;
delete bah.ref;
alert( [bah.ref, foo ] )
// ,[object Object] (it deleted the property but not the reference to the other object)
如果您使用 var
声明了一个变量,则不能删除它:
(function() {
var x = 5;
alert(delete x)
// false
})();
在犀牛中:
js> var x
js> delete x
false
您也不能删除一些预定义的属性,例如 Math.PI
:
js> delete Math.PI
false
与任何语言一样,delete
也有一些奇怪的例外,如果您足够在意,您应该阅读:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/delete_Operator
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
请参阅 noah's answer 了解完整详情
//Option A.) set to null
some_var = null;
//Option B.) set to undefined
some_var = undefined;
//Option C.) remove/delete the variable reference
delete obj.some_var
//if your variable was defined as a global, you'll need to
//qualify the reference with 'window'
delete window.some_var;
参考:
MDN 删除 API
在严格模式下删除不合格的变量名时出现 MDN SyntaxError
delete
的缺陷。
delete
仅适用于属性。设置它 null
变量仍然存在。
TLDR:可以使用 delete
删除简单定义的变量(没有 var
、let
、const
)。如果您使用 var
、let
、const
- 它们既不能用 delete
也不能用 Reflect.deleteProperty
删除。
铬 55:
simpleVar = "1";
"1"
delete simpleVar;
true
simpleVar;
VM439:1 Uncaught ReferenceError: simpleVar is not defined
at <anonymous>:1:1
(anonymous) @ VM439:1
var varVar = "1";
undefined
delete varVar;
false
varVar;
"1"
let letVar = "1";
undefined
delete letVar;
true
letVar;
"1"
const constVar="1";
undefined
delete constVar;
true
constVar;
"1"
Reflect.deleteProperty (window, "constVar");
true
constVar;
"1"
Reflect.deleteProperty (window, "varVar");
false
varVar;
"1"
Reflect.deleteProperty (window, "letVar");
true
letVar;
"1"
Firefox Nightly 53.0a1 显示相同的行为。
var
的情况。对我来说,测试和分享 let
和 const
案例也很有趣。不过,感谢您的注意。下次会尝试更具体。
ECMAScript 2015 提供 Reflect API。可以使用 Reflect.deleteProperty() 删除对象属性:
Reflect.deleteProperty(myObject, 'myProp');
// it is equivalent to:
delete myObject.myProp;
delete myObject['myProp'];
要删除全局 window
对象的属性:
Reflect.deleteProperty(window, 'some_var');
在某些情况下,无法删除属性(当属性不可配置时),然后此函数返回 false
(以及 delete operator)。在其他情况下,它返回 true
:
Object.defineProperty(window, 'some_var', {
configurable: false,
writable: true,
enumerable: true,
value: 'some_val'
});
var frozen = Object.freeze({ myProperty: 'myValue' });
var regular = { myProperty: 'myValue' };
var blank = {};
console.log(Reflect.deleteProperty(window, 'some_var')); // false
console.log(window.some_var); // some_var
console.log(Reflect.deleteProperty(frozen, 'myProperty')); // false
console.log(frozen.myProperty); // myValue
console.log(Reflect.deleteProperty(regular, 'myProperty')); // true
console.log(regular.myProperty); // undefined
console.log(Reflect.deleteProperty(blank, 'notExistingProperty')); // true
console.log(blank.notExistingProperty); // undefined
在严格模式下运行时,deleteProperty
函数和 delete
运算符之间存在区别:
'use strict'
var frozen = Object.freeze({ myProperty: 'myValue' });
Reflect.deleteProperty(frozen, 'myProperty'); // false
delete frozen.myProperty;
// TypeError: property "myProperty" is non-configurable and can't be deleted
⚠️ 接受的答案(和其他)已经过时了!
TL;博士
delete 不会删除变量。 (仅用于从对象中删除属性。)
“取消设置”的正确方法是简单地将变量设置为空。 (来源)(这使 JavaScript 的自动进程能够从内存中删除变量。)
例子:
x = null;
😉
更多信息:
自 2012 年所有浏览器都实施(自动)mark-and-sweep garbage-collection 以来,已弃用对变量使用 delete
运算符。该过程通过自动确定对象/变量何时变为“unreachable”(确定代码是否仍需要它们)来工作。
使用 JavaScript,在所有现代浏览器中:
垃圾收集是自动执行的。我们不能强迫或阻止它。对象在可访问时保留在内存中。被引用与可访问不同:一组相互关联的对象可能会整体变得不可访问。 (资源)
delete
运算符仅用于从对象中删除属性; 它不会删除变量。
与人们普遍认为的不同(可能是由于其他编程语言,如 C++ 中的 delete),delete 运算符与直接释放内存无关。内存管理是通过中断引用间接完成的。 (资源)
使用 strict mode('use strict';
,与常规/"sloppy mode" 相对)时,尝试删除变量将引发错误并且不允许。 JavaScript 中的普通变量无法使用 delete
运算符 (source)(或任何其他方式,截至 2021 年)删除。
...唉,唯一的解决方案:
释放变量的内容
要释放变量的内容,只需将其设置为 null:
变量 x; // ... x = null; // (x 现在可以被垃圾回收)
(source)
延伸阅读:
内存管理(MDN 文档)
垃圾收集(厄勒布鲁大学)
垃圾收集的基础知识 (javascript.info)
了解使用垃圾收集的 JavaScript 内存管理
消除 Javascript 中的内存泄漏
null
是一个有效值 - 如果将变量设置为 null
会导致它消失(即导致将来的引用抛出 ReferenceError: x is not defined
),那么很多软件都会崩溃。如果您会说将其设置为 undefined
,我们可能会有一些事情要讨论。
null
不会删除它) ,或者它是全局对象的一个属性,在这种情况下 delete
将删除它就好了。
请注意,delete
成功时会返回 true
。
2021 年更新:在 Chrome 88 和 Firefox 84 上测试:
implicit_global = 1;
delete implicit_global; // true
window.explicit_global = 1;
delete explicit_global; // true
const _object = {property: 1};
delete _object.property; // true
function_set = function() {};
delete function_set; // true
function function_declaration() {};
delete function_declaration; // false
(function () {
var _var = 1;
console.log(delete _var); // false
console.log(_var); // 1
})()
(function () {
let _let = 1;
console.log(delete _let); // false
console.log(_let); // 1
})()
(function () {
const _const = 1;
console.log(delete _const); // false
console.log(_const); // 1
})()
由于浏览器更新,此答案的先前编辑不再相关。
let
vars 和 const
vars 它返回 true 应该意味着该变量已删除,但事实并非如此。您可以在 Chrome 和 FF 中检查它。 FF 似乎返回正确的值,而 Chrome 没有。所以不确定你是否真的可以依赖它。让我们看看:let letVar = "1"; undefined delete letVar; true letVar "1" typeof letVar; "string" const constVar="1"; undefined delete constVar; true constVar; "1" typeof constVar; "string"
delete
运算符的工作原理和方式。但这并没有描述为什么与功能相反的情况。可惜。然而,关于变量,事情开始变得更加清晰。
与简单属性相比,变量具有属性 [[Configurable]],这意味着无法通过删除运算符删除变量。
但是,有一个执行上下文不受此规则影响。它是 eval 上下文:没有为变量设置 [[Configurable]] 属性。
删除操作符从对象中删除一个属性。
delete object.property
delete object['property']
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
根据问题,您需要以下之一
delete some_var;
delete window.some_var;
delete window['some_var'];
如果您在首次使用时声明了变量(使用 var x;
),则无法删除该变量。但是,如果您的变量 x
首次出现在脚本中没有声明,那么您可以使用 delete
运算符 (delete x;
) 并且您的变量将被删除,非常类似于删除数组的元素或删除对象的属性。
delete
用于使对象忘记正在定义的属性,它不会影响变量。
我有点困惑。如果您只想让变量值不传递给另一个脚本,那么就没有必要从范围中删除该变量。
只需使变量无效,然后显式检查它是否为空。为什么要麻烦从范围中删除变量?这是为了什么目的而无效化不能呢?
foo = null;
if(foo === null) or if(foo !== null)
null
值的行为。
<?php if(isset($_POST['somevariable']) unset($_POST['somevariable']); if(isset($_GET['somevariable']) unset($_GET['somevariable']); ?>
var
)是“全局对象”的属性,在 Web 浏览器中是window
。所以 -var a = 1; delete window.a; console.log(a);
将成功删除变量并导致最后一行发出引用错误。var a = 1; delete window.a; console.log(a);
显示 1。1
。在真实文档中运行,您的代码示例是正确的。我选择您的答案是正确的,但如果您可以编辑它以包括解释window.a = 1; delete window.a;
和可能的机制,我将不胜感激。如果你不介意,我也可以这样做。