如何取消设置JavaScript变量?

How to unset a JavaScript variable?

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

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

你怎么认为?


delete运算符从对象中移除属性。它不能删除变量。所以问题的答案取决于全局变量或属性是如何定义的。

(1)如果是用var创建的,则不能删除。

例如:

1
2
3
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,则可以删除。

1
2
3
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时或在"glo"时,它可能会变得更复杂一些。bal"代码变量环境附加到全局对象(通常是window)。

变量环境中的引用通常不可删除-ECMAScript 10.5中详细介绍的过程对此进行了详细说明,但足以说明除非您的代码在eval上下文(大多数基于浏览器的开发控制台使用)中执行,否则无法删除使用var声明的变量。

2。不使用var

当尝试在不使用var关键字的情况下为名称赋值时,javascript尝试在ecmascript规范称之为"lexicalenvironment"的内容中定位命名引用,主要区别在于lexicalenvironment是嵌套的——即lexicalenvironment具有父级(ecmascript规范称之为"外部环境引用")。e"),当javscript在LexicaleEnvironment中找不到引用时,它会在父级LexicaleEnvironment中查找引用(如10.3.1和10.2.2.1中所述)。顶级词汇环境是"全局环境",它绑定到全局对象,因为它的引用是全局对象的属性。因此,如果您试图访问一个没有在当前作用域或任何外部作用域中使用var关键字声明的名称,javascript最终将获取window对象的属性作为该引用。正如我们之前所了解的,对象的属性可以被删除。

笔记

  • 重要的是要记住,var声明是"挂起的"——即,它们总是被认为发生在它们所处的范围的开始部分——尽管不是在var语句中可以完成的值初始化——它保留在它所在的位置。因此,在下面的代码中,a是来自可变环境而不是window属性的引用,其值在代码末尾将是10

    function test() { a = 5; var a = 10; }

  • 以上讨论是在未启用"严格模式"时进行的。当使用"严格模式"时,查找规则有点不同,如果词汇引用解析为没有"严格模式"的窗口属性,则会在"严格模式"下引发"未声明的变量"错误。我不太明白这是在哪里指定的,但它是浏览器的行为方式。


  • @斯坎利夫的回答是可行的,但从技术上讲应该是可行的。

    1
    delete window.some_var;

    当目标不是对象属性时,delete应该是no-op。例如。,

    1
    2
    3
    4
    5
    6
    (function() {
       var foo = 123;
       delete foo; // wont do anything, foo is still 123
       var bar = { foo: 123 };
       delete bar.foo; // foo is gone
    }());

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    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声明的变量,尽管您可以在正确的情况下使用它。


    如果隐式声明不带var的变量,则正确的方法是使用delete foo

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

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

    在某些情况下,将它赋给false、null或undefined可能更安全,因此它是声明的,不会抛出这种类型的错误。

    1
    foo = false

    注意,在ecmascript中,nullfalseundefined0NaN''都将对false进行评估。只需确保在对布尔值进行类型检查时不使用!==运算符,而是使用!=,并且不希望进行身份检查(因此null会使用== falsefalse == undefined)。

    还要注意,delete不"删除"引用,而只是直接在对象上的属性,例如:

    1
    2
    3
    4
    5
    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声明了一个变量,则不能删除它:

    1
    2
    3
    4
    5
    (function() {
        var x = 5;
        alert(delete x)
        // false
    })();

    Rhino:

    1
    2
    3
    js> var x
    js> delete x
    false

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

    1
    2
    js> delete Math.PI
    false

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

    • 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


    1
    2
    3
    4
    some_var = null;

    //or remove it..
    delete some_var;


    tldr:简单定义的变量(没有varletconst可以用delete删除。如果您使用varletconst—既不能删除delete,也不能删除Reflect.deleteProperty

    铬55:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    simpleVar ="1";
    "1"
    delete simpleVar;
    true
    simpleVar;
    VM439:1 Uncaught ReferenceError: simpleVar is not defined
        at :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提供反映API。可以使用reflect.delete property()删除对象属性:

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

    删除全局window对象的属性:

    1
    Reflect.deleteProperty(window, 'some_var');

    在某些情况下,无法删除属性(当属性不可配置时),然后此函数返回false(以及delete运算符)。在其他情况下,返回true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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运算符之间存在差异:

    1
    2
    3
    4
    5
    6
    7
    '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


    与简单属性相比,变量具有属性[[可配置]],这意味着无法通过删除运算符删除变量。但是,有一个执行上下文不受此规则影响。它是eval上下文:这里没有为变量设置[[可配置]]属性。


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

    1
    2
    delete object.property
    delete object['property']

    https://developer.mozilla.org/en-us/docs/web/javascript/reference/operators/delete

    根据你需要的问题

    1
    2
    3
    delete some_var;
    delete window.some_var;
    delete window['some_var'];

    除了每个人都写过的以外,还要注意delete返回布尔值。它可以告诉您删除是否成功。

    更新:

    在最新的Chrome上测试,一切都是可以删除的。delete函数为以下所有方法返回true并实际删除了它们:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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


    如果在首次使用时声明了变量(使用var x;),则不能删除该变量。但是,如果变量x第一次出现在脚本中而没有声明,则可以使用删除运算符(delete x;)删除变量,这与删除数组元素或删除对象属性非常相似。


    我有点困惑。如果您只想让一个变量值不传递给另一个脚本,那么就不需要从作用域中删除该变量。只需使变量无效,然后显式检查它是否为空。为什么要从作用域中删除变量?这台服务器的无效不能有什么目的?

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