如何取消设置JavaScript变量?

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

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

你怎么看?

824416 次浏览

详见诺亚的回答

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

引用:

  • < p > # EYZ0

  • < p > # EYZ0

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

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

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

在某些情况下,将它赋值为false、null或undefined可能更安全,这样它就被声明了,不会抛出这种类型的错误。

foo = false

请注意,在ECMAScript中nullfalseundefined0NaN''都将计算为false。只要确保在类型检查布尔值时不使用!==操作符,而是使用!=操作符,并且您不想进行身份检查(因此nullfalse0和false1)。

还要注意,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
})();

在Rhino中:

js> var x
js> delete x
false

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

js> delete Math.PI
false

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

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

但是由于全局变量实际上是窗口对象的成员,所以它是可行的。

当涉及到原型链时,使用删除会变得更加复杂,因为它只从目标对象中删除属性,而不是从原型中删除。例如,

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操作符从对象中删除一个属性。它不能删除变量。所以这个问题的答案取决于全局变量或属性是如何定义的。

(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

技术说明

. < h3 id = " using-var-b0z2 " > 1。使用# EYZ0 < / h3 >

在这种情况下,引用g_a被创建在ECMAScript规范中称为"< em > VariableEnvironment < / em >"这可能是在函数中使用var的情况下的函数执行上下文(尽管当你考虑let时可能会变得有点复杂),或者在"global"代码中,VariableEnvironment附加到全局对象(通常是window)。

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

< h3 id = " without-using-var-jknj " > 2。没有使用var

当试图在不使用var关键字的情况下为一个名称赋值时,JavaScript会尝试在ECMAScript规范中称为“& < em > LexicalEnvironment < / em >"”的地方找到命名的引用,主要的区别是LexicalEnvironment是嵌套的——即LexicalEnvironment有一个父对象(ECMAScript规范中称为“外部环境引用")当JavaScript无法在LexicalEnvironment中找到引用时,它会在父对象LexicalEnvironment中查找(详见10.3.110.2.2.1)。顶层的LexicalEnvironment是"var1",它被绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您试图在当前作用域或任何外部作用域中访问未使用var关键字声明的名称,JavaScript最终将获取window对象的属性作为该引用。正如我们之前所了解的,对象上的属性可以被删除。

指出< h3 id = " notes-ip5f " > < / h3 >
  1. 重要的是要记住var声明是"-也就是说,它们总是被认为发生在它们所在作用域的开头——尽管不是在var语句中可能完成的值初始化——它被留在原来的位置。所以在下面的代码中,a是来自VariableEnvironment而不是window属性的引用,它的值将是代码末尾的10:

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

注意,当执行成功时,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
})()

由于浏览器更新,此答案的先前编辑已不再相关。

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

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

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(以及删除操作符)。在其他情况下,它返回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
如果你在第一次使用时声明了一个变量(使用var x;),你就不能删除它。 然而,如果你的变量x第一次出现在脚本中没有声明,那么你可以使用delete操作符(delete x;),你的变量将被删除,非常类似于删除一个数组的元素或删除一个对象的属性

TLDR:简单定义的变量(没有varletconst)可以用delete删除。如果你使用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"

Firefox Nightly 53.0a1显示相同的行为。

与简单的属性相比,变量具有[[可]]属性,这意味着不可能通过删除操作符删除变量。

但是,有一个执行上下文不受此规则的影响。它是eval上下文:其中没有为变量设置[[Configurable]]属性。

我有点糊涂了。如果你只是想让一个变量的值不传递给另一个脚本,那么就没有必要从作用域中删除这个变量。

只需使变量为空,然后显式检查它是否为空。为什么要麻烦地从作用域删除变量呢?这样做的目的是什么呢?

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

⚠️# EYZ0

博士TL;

    <李> < p > # EYZ1。
    (仅用于从对象中删除属性)

  • “取消设置”的正确方法就是简单地将变量设置为< em > <强> # EYZ0 < /强> < / em >。# EYZ3
    (允许JavaScript的自动进程删除 变量来自内存)

例子:

x = null;

😉


更多信息:

不赞成在变量上使用delete操作符自2012年起,当时所有浏览器都实现了(自动)标记和清扫 垃圾收集。该过程通过自动确定对象/变量何时变成“;遥不可及的"(决定代码是否仍然需要它们)。

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

  • 自动执行垃圾收集。# EYZ0
  • 对象在可获得的时保留在内存中。
  • 作为引用和作为可获得的是不一样的:一组相互链接的对象作为一个整体可能变得不可到达。 (# EYZ0) < /子>

delete操作符仅用于对象中的删除属性; 它执行删除变量

与人们通常认为的不同(可能是由于其他编程语言,如delete在c++), delete操作符与直接释放内存无关。内存管理是通过断续引用间接完成的。 (# EYZ0) < /子>

当使用严格模式 ('use strict';,而不是常规的/“草率mode")时,试图删除一个变量会抛出一个错误,并且是不允许的。JavaScript中的普通变量不能使用delete操作符(source)(或任何其他方式,截至2021年)删除。

 


 

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

释放变量的内容

释放变量的内容,或者将其设置为null:

var x;


// ...


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

(source)


进一步阅读: