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

我已经把some_var = undefined,它用于测试类型的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附加到全局对象(通常是窗口)。

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

2. 不使用var

When trying to assign a value to a name without using the var keyword, JavaScript tries to locate the named reference in what the ECMAScript spec calls "LexicalEnvironment", and the main difference is that LexicalEnvironments are nested - that is a LexicalEnvironment has a parent (what the ECMAScript spec calls "outer environment reference") and when JavaScript fails to locate the reference in a LexicalEnvironment, it looks in the parent LexicalEnvironment (as detailed in 10.3.1 and 10.2.2.1). The top level LexicalEnvironment is the "global environment", and that is bound to the global object in that its references are the global object's properties. So if you try to access a name that was not declared using a var keyword in the current scope or any outer scopes, JavaScript will eventually fetch a property of the window object to serve as that reference. As we've learned before, properties on objects can be deleted.

笔记

It is important to remember that var declarations are "hoisted" - i.e. they are always considered to have happened in the beginning of the scope that they are in - though not the value initialization that may be done in a var statement - that is left where it is. So in the following code, a is a reference from the VariableEnvironment and not the window property and its value will be 10 at the end of the code: function test() { a = 5; var a = 10; } The above discussion is when "strict mode" is not enabled. Lookup rules are a bit different when using "strict mode" and lexical references that would have resolved to window properties without "strict mode" will raise "undeclared variable" errors under "strict mode". I didn't really understand where this is specified, but its how browsers behave.

其他回答

如果你在第一次使用时声明了一个变量(使用var x;),你就不能删除它。 但是,如果你的变量x第一次出现在脚本中没有声明,那么你可以使用delete操作符(delete x;),你的变量将被删除,这与删除数组的元素或删除对象的属性非常相似。

详见诺亚的回答

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

如果隐式声明变量时不使用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
})();

在Rhino中:

js> var x
js> delete x
false

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

js> delete Math.PI
false

就像任何语言一样,有一些奇怪的例外需要删除,如果你足够在乎,你应该读一下:

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

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

Reflect.deleteProperty(myObject, 'myProp');
// it is equivalent to:
delete myObject.myProp;
delete myObject['myProp'];

删除全局窗口对象的一个属性:

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

斯坎利夫的答案是可行的,但从技术上讲,它应该是可行的

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.

所以要小心。

注:我的回答有些不准确(见末尾的“误解”)。这个链接解释了所有血腥的细节,但总的来说,不同的浏览器之间可能有很大的差异,这取决于你要删除的对象。删除对象。someProp通常应该是安全的,只要object !== window。我仍然不会使用它来删除用var声明的变量,尽管在适当的情况下可以这样做。