web-dev-qa-db-ja.com

JavaScript変数を設定解除する方法

私はJavaScriptでグローバル変数(実際にはwindowプロパティですが、それは重要ではないと思います)を持っていました。でも定義されています。

私はsome_var = undefinedを入れました、そしてそれはtypeof some_var == "undefined"をテストする目的のために働きます、しかし、私は本当にそれがそれについて取り組むための正しい方法だとは思わない。

どう思いますか?

545
Guss

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 "、および主な違いは、LexicalEvironmentsがネストされていることです-つまり、LexicalEnvironmentには親(ECMAScript仕様では「外部環境参照」と呼ばれるもの)があり、JavscriptがLexicalEenvironment、親を探しますLexicalEnvironment(詳細は 10.3.1 および 10.2.2.1 )。トップレベルLexicalEnvironmentは、「 global environment "であり、その参照がグローバルオブジェクトのプロパティであるという点で、グローバルオブジェクトにバインドされています。したがって、現在のスコープまたは外部スコープでvarキーワードを使用して宣言されていない名前にアクセスしようとすると、Javascriptは最終的にその参照として機能するwindowオブジェクトのプロパティをフェッチします。以前に学んだように、オブジェクトのプロパティは削除できます。

ノート

  1. var宣言は「ホイスト」されていることを覚えておくことが重要です。つまり、varステートメントで行われる可能性のある値の初期化ではなく、常にスコープの先頭で発生したと見なされます。そうです。したがって、次のコードでは、aVariableEnvironmentからの参照であり、windowプロパティではなく、その値はコードの最後で10になります。

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

  2. 上記の説明は、「厳格モード」が有効になっていない場合です。 「厳格モード」を使用する場合、ルックアップルールは少し異なり、「厳格モード」なしでウィンドウプロパティに解決されたレキシカル参照は、「厳格モード」の下で「宣言されていない変数」エラーを発生させます。これがどこで指定されているかは本当に理解していませんでしたが、ブラウザの動作はどのようになっているのでしょうか。

404
Dayong

@ 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.

ので注意してください。

編集:私の答えは やや不正確です (最後の「誤解」を参照)。リンクはすべての厄介な詳細を説明します、しかし要約はブラウザとあなたが削除しようとしているオブジェクトに依存して大きな違いがあるということです。 delete object.somePropは一般にobject !== windowである限り安全であるべきです。 varで宣言された変数を削除するために私はまだそれを使用しないでしょうが、あなたは正しい状況下で可能です。

272
noah

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

deleteには、他の言語と同じように奇妙な例外がいくつかあります。

34
meder omuraliev
some_var = null;

//or remove it..
delete some_var;
28
scunliffe

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"

FF Nightly 53.0a1は同じ振る舞いを示します。

13
Serj.by

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演算子 )を返します。それ以外の場合は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
3
madox2

Delete演算子は、オブジェクトからプロパティを削除します。

delete object.property
delete object['property']

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

質問によると、あなたは以下のうちの1つを必要とします

delete some_var;
delete window.some_var;
delete window['some_var'];
2
Swarnendu Paul

単純なプロパティとは対照的に、変数は [[Configurable]] という属性を持ち、 delete 演算子を使って変数を削除することは不可能であることを意味します。ただし、この規則が影響しない実行コンテキストが1つあります。それは eval contextです:there [[Configurable]]属性は変数に設定されていません。

2

誰もが書いたことに加えて、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
2
oriadam

最初の使用時に(var x;を使用して)宣言した変数は削除できません。ただし、変数xが宣言なしで最初にスクリプトに表示された場合は、delete演算子(delete x;)を使用すると、変数が削除されます。これは、配列の要素の削除やオブジェクトのプロパティの削除とよく似ています。 。

1

少し混乱しています。変数の値が別のスクリプトに渡されないようにしたいだけであれば、スコープから変数を削除する必要はありません。単に変数を無効にしてから、それがnullかどうかを明示的にチェックします。なぜスコープから変数を削除するのが面倒ですか?このサーバーは無効にすることができません。

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