我有一个JavaScript中的全局变量(实际上是一个window
属性,但我认为不重要)已经填充了以前的脚本,但我不希望以后运行的另一个脚本看到它的值或它是甚至定义。
我放some_var = undefined
,它的目的是测试typeof 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
var
在这种情况下,参考g_a
是在ECMAScript规范所谓的“VariableEnvironment”中创建的,它附加到当前作用域 - 这可能是在函数内使用var
的情况下的函数执行上下文(尽管它可能会得到一些当你考虑let
时更复杂)或者在“全局”代码的情况下,VariableEnvironment附加到全局对象(通常是window
)。
变量环境中的引用通常不可删除 - ECMAScript 10.5中详述的过程详细解释了这一点,但只要说明除非您的代码在eval
上下文(大多数基于浏览器的开发控制台使用)中执行,否则使用var
声明的变量就足够了无法删除。
var
当试图在不使用var
关键字的情况下为名称赋值时,Javascript尝试在ECMAScript规范中称为“LexicalEnvironment”的位置找到命名引用,主要区别在于LexicalEvironments是嵌套的 - 这是LexicalEnvironment有一个父级( ECMAScript规范称之为“外部环境引用”),当Javscript无法在LexicalEenvironment中找到引用时,它会查找父级LexicalEnvironment(详见10.3.1和10.2.2.1)。顶级LexicalEnvironment是“global environment”,它绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您尝试访问未在当前作用域或任何外部作用域中使用var
关键字声明的名称,Javascript最终将获取window
对象的属性以用作该引用。正如我们之前所了解的,可以删除对象的属性。
var
声明是“悬挂的” - 即它们总是被认为发生在它们所在的范围的开头 - 尽管不是可以在var
语句中完成的值初始化 - 这是留在哪里它是。所以在下面的代码中,a
是来自VariableEnvironment的引用而不是window
属性,它的值将是代码末尾的10
:
function test() { a = 5; var a = 10; }
如果在首次使用时声明了变量(使用var x;),则无法删除变量。但是,如果你的变量x首先出现在没有声明的脚本中,那么你可以使用delete运算符(删除x;),你的变量将被删除,非常类似于删除数组的元素或删除对象的属性。
我有点困惑。如果你想要的是变量值不能传递给另一个脚本,那么就不需要从范围中删除变量。只需使变量无效,然后显式检查它是否为空。为什么要从范围中删除变量呢?这个无效的服务器有什么用途呢?
foo = null;
if(foo === null) or if(foo !== null)
@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.someProp
一般应该是安全的,只要object !== window
。我仍然不会用它来删除用var
声明的变量,尽管你可以在适当的情况下。
如果你隐式声明没有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
})();
在犀牛:
js> var x
js> delete x
false
你也不能删除像Math.PI
这样的预定义属性:
js> delete Math.PI
false
与任何语言一样,delete
有一些奇怪的例外,如果你足够关心,你应该阅读:
some_var = null;
//or remove it..
delete some_var;
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"
FF Nightly 53.0a1显示相同的行为。
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
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'];
除了每个人都写的,还要注意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
与简单属性相比,变量具有[[Configurable]]属性,这意味着无法通过delete运算符删除变量。但是,此规则不会影响一个执行上下文。它是eval上下文:没有为变量设置[[Configurable]]属性。