如何取消设置 JavaScript 变量?

发布于 2024-08-08 20:15:27 字数 247 浏览 7 评论 0原文

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

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

你怎么认为?

I have a global variable in JavaScript (actually a window property, but I don't think it matters) which was already populated by a previous script, but I don't want another script that will run later to see its value or that it was even defined.

I've put some_var = undefined and it works for the purpose of testing typeof some_var == "undefined" but I really do not think it's the right way to go about it.

What do you think?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

红ご颜醉 2024-08-15 20:15:27

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

当尝试在不使用 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代码> 代码末尾:

    函数 test() { a = 5;变量 a = 10; }
    

  2. 上面讨论的是未启用“严格模式”时的情况。使用“严格模式”时,查找规则有点不同,在没有“严格模式”的情况下解析为窗口属性的词法引用将在“严格模式”下引发“未声明的变量”错误。我不太明白这是在哪里指定的,但它是浏览器的行为方式。

The delete operator removes a property from an object. It cannot remove a variable. So the answer to the question depends on how the global variable or property is defined.

(1) If it is created with var, it cannot be deleted.

For example:

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) If it is created without var, it can be deleted.

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

Technical Explanation

1. Using var

In this case the reference g_a is created in what the ECMAScript spec calls "VariableEnvironment" that is attached to the current scope - this may be the a function execution context in the case of using var inside a function (though it may be get a little more complicated when you consider let) or in the case of "global" code the VariableEnvironment is attached to the global object (often window).

References in the VariableEnvironment are not normally deletable - the process detailed in ECMAScript 10.5 explains this in detail, but suffice it to say that unless your code is executed in an eval context (which most browser-based development consoles use), then variables declared with var cannot be deleted.

2. Without Using 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.

Notes

  1. 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; }
    
  2. 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.

御弟哥哥 2024-08-15 20:15:27

scunliffe的答案会起作用,但从技术上讲应该可以 当目标不是对象属性时, be

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

但是由于全局变量实际上是 window 对象的成员,因此它可以工作。

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

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.

所以要小心。

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

scunliffe's answer will work, but technically it ought to be

delete window.some_var;

delete is supposed to be a no-op when the target isn't an object property. e.g.,

(function() {
   var foo = 123;
   delete foo; // wont do anything, foo is still 123
   var bar = { foo: 123 };
   delete bar.foo; // foo is gone
}());

But since global variables are actually members of the window object, it works.

When prototype chains are involved, using delete gets more complex because it only removes the property from the target object, and not the prototype. e.g.,

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.

So be careful.

Note: My answer is somewhat inaccurate (see "Misconceptions" at the end). The link explains all the gory details, but the summary is that there can be big differences between browsers and depending on the object you are deleting from. delete object.someProp should generally be safe as long as object !== window. I still wouldn't use it to delete variables declared with var although you can under the right circumstances.

初吻给了烟 2024-08-15 20:15:27

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

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

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

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

foo = false

请注意,在 ECMAScript 中 nullfalseundefined0NaN'' 将全部计算为 false。只需确保在对布尔值进行类型检查时不使用 !== 运算符,而是使用 != 并且您不希望进行身份检查(因此 null code> 将 == 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
})();

在Rhino中:

js> var x
js> delete x
false

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

js> delete Math.PI
false

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

If you are implicitly declaring the variable without var, the proper way would be to use delete foo.

However after you delete it, if you try to use this in an operation such as addition a ReferenceError will be thrown because you can't add a string to an undeclared, undefined identifier. Example:

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

It may be safer in some situations to assign it to false, null, or undefined so it's declared and won't throw this type of error.

foo = false

Note that in ECMAScript null, false, undefined, 0, NaN, or '' would all evaluate to false. Just make sure you dont use the !== operator but instead != when type checking for booleans and you don't want identity checking (so null would == false and false == undefined).

Also note that delete doesn't "delete" references but just properties directly on the object, e.g.:

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)

If you have declared a variable with var you can't delete it:

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

In Rhino:

js> var x
js> delete x
false

Nor can you delete some predefined properties like Math.PI:

js> delete Math.PI
false

There are some odd exceptions to delete as with any language, if you care enough you should read:

独孤求败 2024-08-15 20:15:27

有关完整详细信息,请参阅 noah 的回答

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

参考文献:

See noah's answer for full details

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

References:

所谓喜欢 2024-08-15 20:15:27

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

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

TLDR: simple defined variables (without var, let, const) could be deleted with delete. If you use var, let, const - they could not be deleted neither with delete nor with 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"

Firefox Nightly 53.0a1 shows the same behaviour.

似梦非梦 2024-08-15 20:15:27

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

TL;DR

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

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

示例:

x = null;

⚠️ The accepted answer (and others) are outdated!

TL;DR

  • delete does not remove variables.
    (It's only for removing a property from an object.)

  • The correct way to "unset" is to simply set the variable to null. (source)
    (This enables JavaScript's automatic processes to remove the
    variable from memory.)

Example:

x = null;

????


More info:

Use of the delete operator on a variable is deprecated since 2012, when all browsers implemented (automatic) mark-and-sweep garbage-collection. The process works by automatically determining when objects/variables become "unreachable" (deciding whether or not the code still requires them).

With JavaScript, in all modern browsers:

  • Garbage collection is performed automatically. We cannot force or prevent it.
  • Objects are retained in memory while they are reachable.
  • Being referenced is not the same as being reachable: a pack of interlinked objects can become unreachable as a whole.
    (source)

The delete operator is only used to remove a property from an object;
it does not remove variables.

Unlike what common belief suggests (perhaps due to other programming languages like delete in C++), the delete operator has nothing to do with directly freeing memory. Memory management is done indirectly via breaking references.
(source)

When using strict mode ('use strict';, as opposed to regular/"sloppy mode") an attempt to delete a variable will throw an error and is not allowed. Normal variables in JavaScript can't be deleted using the delete operator (source) (or any other way, as of 2021).


...alas, the only solution:

Freeing the contents of a variable

To free the contents of a variable, you can simply set it to null:

var x;

// ...

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

(source)


Further Reading:

╭ゆ眷念 2024-08-15 20:15:27

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 (以及删除运算符< /a>)。在其他情况下,它返回 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

ECMAScript 2015 offers Reflect API. It is possible to delete an object property with Reflect.deleteProperty():

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

To delete a property of the global window object:

Reflect.deleteProperty(window, 'some_var');

In some cases properties cannot be deleted (when the property is not configurable) and then this function returns false (as well as the delete operator). In other cases it returns 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

There is a difference between deleteProperty function and delete operator when run in strict mode:

'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
北风几吹夏 2024-08-15 20:15:27

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

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

Note that delete returns true when it was successful.

Update 2021: tested on Chrome 88 and 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
})()

The previous edit of this answer is no longer relevant due to browser updates.

猫烠⑼条掵仅有一顆心 2024-08-15 20:15:27

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

然而,有一种执行上下文不受此规则的影响。这是eval上下文:没有为变量设置[[Configurable]]属性。

Variables, in contrast to simple properties, have the attribute [[Configurable]], meaning impossibility to remove a variable via the delete operator.

However, there is one execution context in which this rule does not affect. It is the eval context: there the [[Configurable]] attribute is not set for variables.

飘落散花 2024-08-15 20:15:27

删除运算符从对象中删除属性。

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

The delete operator removes a property from an object.

delete object.property
delete object['property']

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

According to the question you need one of followings

delete some_var;
delete window.some_var;
delete window['some_var'];
黯然 2024-08-15 20:15:27

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

You cannot delete a variable if you declared it (with var x;) at the time of first use.
However, if your variable x first appeared in the script without a declaration, then you can use the delete operator (delete x;) and your variable will be deleted, very similar to deleting an element of an array or deleting a property of an object.

过潦 2024-08-15 20:15:27

我有点困惑。如果您想要的只是变量值不传递给另一个脚本,则无需从作用域中删除该变量。

只需使变量无效,然后显式检查它是否为空。为什么要经历从作用域中删除变量的麻烦呢?这能达到什么目的,而无效则不能呢?

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

I am bit confused. If all you want is for a variables value to not pass to another script then there isn't any need to delete the variable from the scope.

Simply nullify the variable and then explicit check if it is or is not null. Why go through the trouble of deleting the variable from the scope? What purpose does this serve that nullifying can not?

foo = null;
if(foo === null) or if(foo !== null)
心欲静而疯不止 2024-08-15 20:15:27
configurable--> deletable
var a=1
Object.getOwnPropertyDescriptor(window,"a")
return
{value: 1, writable: true, enumerable: true, configurable: false}
b=1
Object.getOwnPropertyDescriptor(window,"b")
return
{value: 1, writable: true, enumerable: true, configurable: true}
a=null or a=undefined not working for delete variable 
return same only changing saved data
{value: null, writable: true, enumerable: true, configurable: false}
configurable--> deletable
var a=1
Object.getOwnPropertyDescriptor(window,"a")
return
{value: 1, writable: true, enumerable: true, configurable: false}
b=1
Object.getOwnPropertyDescriptor(window,"b")
return
{value: 1, writable: true, enumerable: true, configurable: true}
a=null or a=undefined not working for delete variable 
return same only changing saved data
{value: null, writable: true, enumerable: true, configurable: false}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文