如何取消设置JavaScript变量?

时间:2009-10-20 19:23:59

标签: javascript global-variables undefined

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

我放了some_var = undefined,它的目的是为了测试typeof some_var == "undefined",但我真的不认为这是正确的方法。

您怎么看?

12 个答案:

答案 0 :(得分:388)

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规范调用的内容创建的,并且#34; VariableEnvironment"附加到当前作用域 - 这可能是在函数内部使用var时的函数执行上下文(尽管在考虑let时可能会稍微复杂一些)或者"全球"代码 VariableEnvironment 附加到全局对象(通常为window)。

VariableEnvironment 中的引用通常不可删除 - ECMAScript 10.5中详述的过程详细说明了这一点,但只需说明,除非您的代码在{{1}中执行上下文(大多数基于浏览器的开发控制台使用),然后无法删除用eval声明的变量。

2。不使用var

尝试在不使用var关键字的情况下为名称指定值时,Javascript会尝试在ECMAScript规范调用的内容中找到命名引用" LexicalEnvironment"和主要区别在于 LexicalEvironment 是嵌套的 - 这是 LexicalEnvironment 有一个父级(ECMAScript规范称之为"外部环境参考")以及何时Javscript未能在 LexicalEenvironment 中找到引用,它在父 LexicalEnvironment 中查找(详见10.3.110.2.2.1)。顶级 LexicalEnvironment 是" global environment",并且绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您尝试访问未在当前作用域或任何外部作用域中使用var关键字声明的名称,Javascript最终将获取var对象的属性以用作该引用。正如我们之前所了解的那样,可以删除对象的属性。

注释

  1. 重要的是要记住window声明是"悬挂" - 即它们总是被认为发生在它们所在范围的开头 - 尽管不是可以在var语句中完成的值初始化 - 它就在它所在的位置。因此,在以下代码中,var是来自 VariableEnvironment 的引用,而不是a属性,其值在代码末尾为window

    10

  2. 上述讨论是在严格模式下进行的。未启用。使用"严格模式"时,查找规则略有不同和词汇引用,如果没有"严格模式"将解析为窗口属性将提出"未声明的变量" "严格模式"下的错误。我并不是真正理解指定的位置,而是浏览器的行为方式。

答案 1 :(得分:273)

@ scunlife的答案会奏效,但从技术上来说应该是

delete window.some_var; 
当目标不是对象属性时,

delete应该是无操作。如,

(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.somePropobject !== window通常应该是安全的。我仍然不会用它来删除用var声明的变量,尽管你可以在适当的情况下。

答案 2 :(得分:34)

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

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

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

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

foo = false

请注意,在ECMAScript null中,falseundefined0NaN''都将评估为{{1} }}。确保您不使用false运算符,而是使用!==进行类型检查布尔值并且您不需要进行身份检查(因此!=null和{{1 }})。

另请注意,== 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)

在Rhino:

var

您也无法删除某些预定义属性,例如(function() { var x = 5; alert(delete x) // false })();

js> var x
js> delete x
false

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

答案 3 :(得分:28)

some_var = null;

//or remove it..
delete some_var;

答案 4 :(得分:13)

TLDR:可以使用var删除简单定义的变量(不包含letconstdelete)。如果您使用varletconst,则无法使用deleteReflect.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"

FF每夜53.0a1显示相同的行为。

答案 5 :(得分:3)

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

答案 6 :(得分:2)

除了每个人写的内容之外,还要注意delete返回布尔值。它可以告诉您删除是否成功。

<强>更新

在最新的Chrome上测试,一切都是可删除的。 delete函数为以下所有方法返回true,并实际删除了它们:

implicit_global = 1;
window.explicit_global = 1;
function_set = function() {};
function function_dec() { };
var declared_variable = 1;

delete delete implicit_global; // true, tested on Chrome 52
delete window.explicit_global; // true, tested on Chrome 52
delete function_set; // true, tested on Chrome 52
delete function_dec; // true, tested on Chrome 52
delete declared_variable; // true, tested on Chrome 52

答案 7 :(得分:2)

删除操作符从对象中删除属性。

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'];

答案 8 :(得分:2)

与简单属性相比,变量具有属性 [[Configurable]] ,这意味着无法通过 delete 运算符删除变量。但是,此规则不会影响一个执行上下文。它是 eval 上下文:没有为变量设置[[Configurable]]属性。

答案 9 :(得分:2)

⚠️ 接受的答案(和其他答案)已过时!

TL;DR

  • delete不会删除变量
    (仅用于从对象中删除属性。)

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

示例:

x = null;

?


更多信息:

在变量上使用 delete 运算符已被弃用,因为 2012 年所有浏览器都实现了(自动)mark-and-sweep garbage-collection。该过程的工作原理是自动确定对象/变量何时变为“unreachable”(决定代码是否仍然需要它们)。

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

<块引用>
  • 垃圾收集是自动执行的。 我们无法强迫或阻止它。
  • 对象在 reachable 时保留在内存中。
  • 引用可达不同:一组相互关联的对象作为一个整体可能变得不可达。 (source)

delete 运算符仅用于从对象中删除属性不会删除变量。

<块引用>

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

当使用 strict mode'use strict';,而不是常规/"sloppy mode")时,尝试删除变量将引发错误并且是不允许的。无法使用 delete 运算符 (source)(或任何其他方式,截至 2021 年)删除 JavaScript 中的普通变量。


...唉,唯一的解决办法:

Freeing the contents of a variable

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

<块引用>
var x;

// ...

x = null;    // (x can now be garbage collected)

(source)


进一步阅读:

答案 10 :(得分:1)

如果在首次使用时声明了变量(使用var x;),则无法删除变量。 但是,如果你的变量x首先出现在没有声明的脚本中,那么你可以使用delete运算符(删除x;),你的变量将被删除,非常类似于删除数组的元素或删除对象的属性

答案 11 :(得分:0)

我有点困惑。如果您只希望变量值不传递给另一个脚本,则无需从作用域中删除变量。只需使变量无效,然后显式检查其是否为null。为什么要麻烦从范围中删除变量?无效的服务器不能达到什么目的?

foo = null;
if(foo === null) or if(foo !== null)