如何取消设置 JavaScript 变量?

IT技术 javascript global-variables undefined variable-declaration unset
2021-01-13 19:25:46

我在 JavaScript 中有一个全局变量(实际上是一个window属性,但我认为它并不重要)已经由以前的脚本填充,但我不希望另一个脚本稍后运行以查看其值或它是甚至定义。

我已经把some_var = undefined它用于测试的目的,typeof some_var == "undefined"但我真的认为这不是正确的方法。

你怎么认为?

6个回答

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是嵌套的——即LexicalEnvironment有一个父级( ECMAScript 规范称之为“外部环境引用”),当 JavaScript 无法在LexicalEnvironment 中定位引用时,它会在父LexicalEnvironment 中查找(详见10.3.110.2.2.1)。顶级LexicalEnvironment是“全局环境",并且它绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您尝试访问未var在当前作用域或任何外部作用域中使用关键字声明的名称,JavaScript 最终将获取一个属性该的window对象充当参考。正如我们之前了解到,在对象的属性可以被删除。

笔记

  1. 重要的是要记住var声明是“提升的”——即它们总是被认为发生在它们所在作用域的开始——尽管不是可能在var语句中完成的值初始化——它留在原处. 所以在下面的代码中,a是来自VariableEnvironment而不是window属性的引用,它的值将10在代码的末尾:

    function test() { a = 5; var a = 10; }
    
  2. 上面的讨论是在没有启用“严格模式”的情况下。使用“严格模式”时查找规则略有不同,在没有“严格模式”的情况下解析为窗口属性的词法引用将在“严格模式”下引发“未声明的变量”错误。我真的不明白这是在哪里指定的,但它是浏览器的行为方式。

好吧,我的错。请参阅ecma-international.org/ecma-262/5.1/#sec-10.5(子点 2 和 8.c.ii):在开发者控制台中运行我的测试时,它通常被认为是“评估上下文”(尽管也许不在 Chrome 中),所以它会引发错误。真实文档全局上下文中的相同代码将1在所有浏览器中正确输出在真实文档中运行,您的代码示例是正确的。我选择您的答案是正确的,但如果您可以编辑它以包括解释window.a = 1; delete window.a;和可能的机制,我将不胜感激如果你不介意,我也可以这样做。
2021-03-19 19:25:46
@Guss,您的代码var a = 1; delete window.a; console.log(a);显示 1。
2021-03-28 19:25:46
我正在使用谷歌浏览器 v36。我在其他浏览器上测试过。看起来它不是一致的跨浏览器。Chrome 和 Opera 显示 1,而我电脑上的 Firefox、Safari 和 IE 11 出现错误。
2021-03-31 19:25:46
@KlaiderKlai 是的。每次执行函数时都会创建和销毁函数作用域变量。可能关闭是一个例外。
2021-04-02 19:25:46
你所说的是一个常见的误解,但实际上是不正确的 - 在 Javascript 中没有“全局变量”。在没有明确作用域的情况下定义的变量(例如var在函数外部使用)是“全局对象”的属性,在 Web 浏览器中是window. 所以 -var a = 1; delete window.a; console.log(a);将成功删除变量并导致最后一行发出引用错误。
2021-04-03 19:25:46

scunliffe的答案会起作用,但从技术上讲应该是

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
}());

但是由于全局变量实际上是 window 对象的成员,所以它可以工作。

当涉及原型链时,使用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.

所以要小心。

注意:我的回答有点不准确(见最后的“误解”)。该链接解释了所有血腥的细节,但总而言之,浏览器之间可能存在很大差异,具体取决于您要从中删除的对象。delete object.someProp一般应该是安全的,只要object !== window我仍然不会使用它来删除声明的变量,var尽管在适当的情况下可以。

这种情况下,delete 语句似乎根本没有做任何事情。这里发生了什么?
2021-03-14 19:25:46
这个答案是过时的,这使用的delete过时(见这里,和这个答案。)
2021-03-20 19:25:46
关于修改后的答案的最后一句,您可以删除声明var的变量的唯一情况是当变量声明为 时eval
2021-03-24 19:25:46
感谢@jedierikb 提供该有趣文章的链接。更具体地说,那篇文章的这一部分 < perfectkills.com/understanding-delete/#misconceptions >,其中作者指出诺亚的陈述“删除应该是一个空操作”相当不准确,并且很好地解释了为什么不准确. (不要射击使者!)
2021-03-25 19:25:46
@AndersonGreen -使用DontDelete标志创建贴标的全局变量,因此不可删除。该代码的行为完全符合预期。
2021-03-29 19:25:46

如果您隐式声明变量没有var,正确的方法是使用delete foo.

但是,在删除它之后,如果您尝试在诸如添加之类的操作中使用它,则会ReferenceError抛出 a ,因为您无法向未声明的未定义标识符添加字符串。例子:

x = 5;
delete x
alert('foo' + x )
// ReferenceError: x is not defined

在某些情况下,将它分配给 false、null 或 undefined 可能更安全,因此它被声明并且不会抛出此类错误。

foo = false

请注意,在 ECMAScript 中nullfalse, undefined, 0, NaN, or''都会评估为false只要确保你不使用的!==运营商,而是!=当布尔类型检查,你不想身份检查(所以null== falsefalse == 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任何语言都有一些奇怪的例外,如果你足够关心你应该阅读:

感谢您提供所有详细信息的完整答案。我为此做了标记,但我接受了诺亚的回答,因为我相信对于一个简单的问题,简洁比完成更重要。再次 - 感谢您在此答案上所做的出色工作。
2021-03-17 19:25:46

请参阅诺亚的答案以获取完整详细信息

//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;

参考:

如果此代码的范围是函数,则这不起作用。请参阅@noah 的答案以获取正确的解决方案。
2021-03-17 19:25:46
不用担心......我给出了一个“快速和肮脏”的简单答案 - @noah 添加了“其他”案例的所有细节,因此他也值得称赞。;-)
2021-03-24 19:25:46
感谢您的回答,但我已经接受了诺亚的回答,因为它更好地解释了delete.
2021-03-26 19:25:46
对于最有可能使用“if (some_var) { .. }”进行检查的情况,这个答案已经足够了
2021-03-29 19:25:46
这是不正确的。delete仅适用于属性。设置它null变量仍然存在。
2021-04-03 19:25:46

TLDR:简单定义的变量(没有var, let, const)可以用 删除delete如果您使用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案件。不过,感谢您的注意。下次将尝试更具体。
2021-03-11 19:25:46
您的答案在技术上是正确的,所以您得到了一个点,但是您写的所有内容都包含在所选答案中,其中包含更多详细信息和对 ECMAScript 规范的引用 - 将来在发布之前查看现有答案会很有用。
2021-04-05 19:25:46