如何取消设置JavaScript变量?

Gus*_*uss 573 javascript global-variables undefined

我有一个JavaScript中的全局变量(实际上是一个window属性,但我认为不重要)已经填充了以前的脚本,但我不希望以后运行的另一个脚本看到它的值或者它是偶数定义.

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

你怎么看?

Day*_*ong 420

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
Run Code Online (Sandbox Code Playgroud)

(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
Run Code Online (Sandbox Code Playgroud)

技术解释

1.使用 var

在这种情况下,引用g_a是在ECMAScript规范所谓的" VariableEnvironment "中创建的,它附加到当前作用域 - 这可能是在函数var内部使用时的函数执行上下文(尽管它可能会变得更复杂一些)当你考虑let)或在"全局"代码的情况下,VariableEnvironment附加到全局对象(通常window).

VariableEnvironment中的引用通常不可删除 - ECMAScript 10.5中详述的过程详细解释了这一点,但只要说明除非您的代码在eval上下文中执行(大多数基于浏览器的开发控制台使用),否则声明的变量var不能被删除.

2.不使用 var

当试图在不使用var关键字的情况下为名称赋值时,Javascript尝试在ECMAScript规范称为" LexicalEnvironment "的位置找到命名引用,主要区别在于LexicalEvironment是嵌套的 - 这是LexicalEnvironment有一个父级( ECMAScript规范称之为"外部环境引用"),当Javscript未能在LexicalEenvironment中找到引用时,它会查找父级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. 以上讨论是在未启用"严格模式"的情况下.当使用"严格模式"时,查找规则有点不同,并且在没有"严格模式"的情况下解析为窗口属性的词法引用将在"严格模式"下引发"未声明的变量"错误.我真的不明白这是指定的位置,而是浏览器的行为方式.

  • 你说的是一个常见的误解,但实际上是错误的 - 在Javascript中没有"全局变量".没有显式范围定义的变量(例如在函数外部使用`var`)是"全局对象"的属性,在Web浏览器中是"窗口".所以 - `var a = 1; 删除window.a; console.log(a);`将成功删除变量并导致最后一行发出引用错误. (8认同)
  • @Guss,你的代码`var a = 1; 删除window.a; console.log(a);`显示1. (5认同)
  • 我使用的是Google Chrome v36.我在其他浏览器上测试过.看起来它不是一致的跨浏览器.Chrome和Opera显示1,而我的计算机上的Firefox,Safari和IE 11出错. (4认同)
  • 好的,我的错误.见http://www.ecma-international.org/ecma-262/5.1/#sec-10.5(分2和8.c.ii):在开发者控制台中运行我的测试时,通常认为"评估上下文"(虽然可能不在Chrome中),因此会引发错误.真实文档的全局上下文中的相同代码将在所有浏览器中正确输出"1".在真实文档中运行,您的代码示例是正确的.我选择你的答案是正确的,但如果你能编辑它以包括解释`window.a = 1;我会很感激.删除window.a;`和可能的机制.如果你不介意,我也可以这样做. (2认同)
  • @KlaiderKlai 是的。每次执行函数时都会创建和销毁函数作用域变量。可能关闭是一个例外。 (2认同)

noa*_*oah 277

@scunlife的答案会起作用,但从技术上说它应该是

delete window.some_var; 
Run Code Online (Sandbox Code Playgroud)

当目标不是对象属性时,delete应该是无操作.例如,

(function() {
   var foo = 123;
   delete foo; // wont do anything, foo is still 123
   var bar = { foo: 123 };
   delete bar.foo; // foo is gone
}());
Run Code Online (Sandbox Code Playgroud)

但由于全局变量实际上是窗口对象的成员,因此它起作用.

当涉及原型链时,使用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.
Run Code Online (Sandbox Code Playgroud)

所以要小心.

编辑:我的回答有些不准确(最后请参阅"误解").该链接解释了所有血腥细节,但摘要是浏览器之间可能存在很大差异,具体取决于您要删除的对象.delete object.someProp一般应该是安全的object !== window.var虽然你可以在适当的情况下使用它,但我仍然不会用它来删除声明的变量.

  • 感谢@jedierikb链接到那篇有趣的文章.更具体地说,该文章<http://perfectionkills.com/understanding-delete/#misconceptions>,其中作者声称诺亚的声明"删除应该是一个无操作"是相当不准确的,并且具有出色的扩展性为什么它不准确.(不要射击信使!) (12认同)
  • 关于修订答案的最后一句,你可以删除用`var`声明的变量的唯一情况是用`eval`声明变量. (2认同)

med*_*iev 35

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

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

x = 5;
delete x
alert('foo' + x )
// ReferenceError: x is not defined
Run Code Online (Sandbox Code Playgroud)

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

foo = false
Run Code Online (Sandbox Code Playgroud)

需要注意的是在ECMAScript中null,false,undefined,0,NaN,或者''将所有的计算结果为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)
Run Code Online (Sandbox Code Playgroud)

如果您已声明变量,var则无法将其删除:

(function() {
    var x = 5;
    alert(delete x)
    // false
})();
Run Code Online (Sandbox Code Playgroud)

在犀牛:

js> var x
js> delete x
false
Run Code Online (Sandbox Code Playgroud)

你也不能删除一些预定义的属性,如Math.PI:

js> delete Math.PI
false
Run Code Online (Sandbox Code Playgroud)

delete与任何语言一样,有一些奇怪的例外,如果你足够关心,你应该阅读:


scu*_*ffe 30

some_var = null;

//or remove it..
delete some_var;
Run Code Online (Sandbox Code Playgroud)

  • 如果此代码的范围是函数,则这不起作用.有关正确的解决方案,请参阅@ noah的答案. (11认同)
  • 这是不正确的.`delete`仅适用于属性.将其设置为"null"变量仍然存在. (7认同)
  • 不用担心......我给了一个"快速肮脏"的简单答案 - @noah为"其他"案件添加了所有细节,因此他也值得称赞.;-) (3认同)

Ser*_*.by 15

TLDR:简单定义的变量(无var,let,const)可以与被删除delete.如果使用var,let,const-他们不能既不删除delete也不符合Reflect.deleteProperty.

Chrome 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"
Run Code Online (Sandbox Code Playgroud)

FF Nightly 53.0a1显示相同的行为.

  • 同意.但是只提到了`var` case.至于我,测试和分享`let`和`const`案例也很有趣.但是,谢谢你的注意.下次会尝试更具体. (4认同)

ash*_*awg 10

\xe2\x9a\xa0\xef\xb8\x8f接受的答案(和其他答案)已经过时了!

\n

长话短说

\n
    \n
  • delete删除变量
    \n (它仅用于从对象中删除属性。)

    \n
  • \n
  • “取消设置”的正确方法是将变量简单地设置为null()
    \n (这使得 JavaScript 的自动进程能够从内存中删除\n变量。)

    \n
  • \n
\n

例子:

\n
x = null;\n
Run Code Online (Sandbox Code Playgroud)\n

\n


\n

更多信息:

\n

delete自 2012 年以来,所有浏览器都实现了(自动)标记和清除 垃圾收集,因此不推荐在变量上使用运算符。该过程的工作原理是自动确定对象/变量何时变得“无法访问”(决定代码是否仍然需要它们)。

\n

使用 JavaScript,在所有现代浏览器中:

\n
\n
    \n
  • 垃圾收集是自动执行的。我们无法强迫或阻止它。
  • \n
  • 对象在可访问时保留在内存中。
  • \n
  • 引用与可访问不同:一组相互链接的对象作为一个整体可能变得不可访问。\n 来源
  • \n
\n
\n

delete运算符仅用于从对象中删除属性;\n它不删除变量。

\n
\n

与普遍看法不同(可能是由于deleteC++等其他编程语言),该delete运算符与直接释放内存无关。内存管理是通过中断引用间接完成的。\n 来源

\n
\n

当使用严格模式(与常规/ “草率模式”\'use strict\';相反)时,尝试删除变量将引发错误并且是不允许的。JavaScript 中的普通变量无法使用运算符( source )(或自 2021 年起的任何其他方式)删除。delete

\n

\xc2\xa0

\n
\n

\xc2\xa0

\n

...唉,唯一的解决方案:

\n

释放变量的内容

\n

要释放变量的内容,您只需将其设置为null

\n
\n
var x;\n\n// ...\n\nx = null;    // (x can now be garbage collected)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

来源

\n
\n

进一步阅读:

\n\n


mad*_*ox2 6

ECMAScript 2015 提供了 Reflect API。可以使用Reflect.deleteProperty()删除对象属性:

Reflect.deleteProperty(myObject, 'myProp');
// it is equivalent to:
delete myObject.myProp;
delete myObject['myProp'];
Run Code Online (Sandbox Code Playgroud)

要删除全局window对象的属性:

Reflect.deleteProperty(window, 'some_var');
Run Code Online (Sandbox Code Playgroud)

在某些情况下,无法删除属性(当属性不可配置时),然后此函数返回false(以及删除运算符)。在其他情况下,它返回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
Run Code Online (Sandbox Code Playgroud)

在严格模式下运行时,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
Run Code Online (Sandbox Code Playgroud)