643

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

我已经提出some_var = undefined并且它可以用于测试目的,typeof some_var == "undefined"但我真的认为这不是正确的方法。

你怎么看?

4

12 回答 12

511

操作员从对象中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附加到全局对象(通常window)。

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

2.不使用var

当试图在不使用var关键字的情况下为名称分配值时,JavaScript 会尝试在 ECMAScript 规范所称的“ LexicalEnvironment ”中定位命名引用,主要区别在于LexicalEnvironment是嵌套的——即LexicalEnvironment有一个父级 ( ECMAScript 规范称为“外部环境引用”),当 JavaScript 无法在LexicalEnvironment中找到引用时,它会在父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. 上面的讨论是没有启用“严格模式”的情况。使用“严格模式”时查找规则有点不同,在没有“严格模式”的情况下解析为窗口属性的词法引用将在“严格模式”下引发“未声明的变量”错误。我真的不明白这是在哪里指定的,但它是浏览器的行为方式。

于 2014-09-18T18:33:28.943 回答
283

斯昆利夫的回答会奏效,但从技术上讲,它应该是

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

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

当涉及原型链时,使用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.

所以要小心。

注意:我的回答有些不准确(见最后的“误解”)。该链接解释了所有血淋淋的细节,但总结是浏览器之间可能存在很大差异,具体取决于您要从中删除的对象。delete object.someProp一般只要object !== window. 我仍然不会使用它来删除声明的变量,var尽管您可以在适当的情况下。

于 2009-10-20T19:47:34.990 回答
39

如果您在没有 的情况下隐式声明变量var,则正确的方法是使用delete foo.

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

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

在某些情况下,将其分配给 false、null 或 undefined 可能更安全,因此它被声明并且不会引发此类错误。

foo = false

请注意,在 ECMAScriptnull中,false, undefined, 0, NaN, or''都会计算为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)

如果你已经声明了一个变量,var你不能删除它:

(function() {
    var x = 5;
    alert(delete x)
    // false
})();

在犀牛中:

js> var x
js> delete x
false

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

js> delete Math.PI
false

任何语言都有一些奇怪的例外delete,如果你足够在意,你应该阅读:

于 2009-10-20T19:31:04.003 回答
35

有关详细信息,请参阅诺亚的答案

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

参考:

于 2009-10-20T19:24:58.960 回答
15

TLDR:简单定义的变量(没有var, let, const)可以用delete. 如果您使用var, let, - 它们既不能用也不const能用 删除。deleteReflect.deleteProperty

铬 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 显示相同的行为。

于 2017-01-05T15:13:36.707 回答
6

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
于 2016-01-25T15:37:13.217 回答
3

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

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

于 2015-11-23T10:36:38.750 回答
3

与简单属性相比,变量具有属性[[Configurable]],这意味着无法通过删除运算符删除变量。

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

于 2017-01-25T04:46:55.657 回答
3

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

TL;博士

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

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

例子:

x = null;


更多信息:

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

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

  • 垃圾收集是自动执行的。我们不能强迫或阻止它。
  • 对象在可访问时保留在内存中。
  • 引用可访问不同:一组相互关联的对象可能会整体变得不可访问。 来源

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

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

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

 


 

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

释放变量的内容

要释放变量的内容,您可以简单地将其设置为null

var x;

// ...

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

(source)


Further Reading:

于 2021-02-02T00:09:45.737 回答
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'];
于 2015-12-14T21:11:58.943 回答
2

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

于 2016-03-31T17:48:42.737 回答
0

我有点困惑。如果您只想让变量值不传递给另一个脚本,那么就没有必要从范围中删除该变量。

只需使变量无效,然后显式检查它是否为空。为什么要麻烦从范围中删除变量?这是为了什么目的而无效化不能呢?

foo = null;
if(foo === null) or if(foo !== null)
于 2019-04-13T04:59:46.350 回答