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


592

JavaScriptにグローバル変数(実際にはwindowプロパティですが、重要ではないと思います)があり、以前のスクリプトによって既に入力されていますが、後で実行される別のスクリプトがその値を確認したり、それが定義された。

私はsome_var = undefined試してみましたが、それはテストの目的で機能しますtypeof some_var == "undefined"が、実際にそれを実行する正しい方法だとは思いません。

どう思いますか?

回答:


454

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」と呼んでいる名前付き参照を見つけようとします。主な違いは、LexicalEvironmentがネストされていることです。つまりLexicalEnvironmentには親( ECMAScript仕様で「外部環境参照」と呼ばれているもの)、およびJavscriptがLexicalEenvironmentで参照を見つけられなかった場合は、親LexicalEnvironment10.3.1および10.2.2.1で説明)を調べます。最上位のLexicalEnvironmentは「地球環境"そして、その参照はグローバルオブジェクトのプロパティであるという点で、グローバルオブジェクトにバインドされています。したがってvar、現在のスコープまたは任意の外部スコープでキーワードを使用して宣言されていない名前にアクセスしようとすると、JavaScriptは最終的にプロパティをフェッチしますwindowオブジェクトその基準となる。我々は以前に学んだように、オブジェクトのプロパティを削除することができます。

ノート

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

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

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


8
あなたが言ったことは一般的な誤解ですが、実際には正しくありません-JavaScriptには「グローバル変数」はありません。明示的なスコープなしで定義された変数(var関数の外部での使用など)は、「グローバルオブジェクト」のプロパティであり、Webブラウザーではwindowです。つまりvar a = 1; delete window.a; console.log(a);、変数は正常に削除され、最後の行で参照エラーが発生します。
ガス

7
@Guss、あなたのコードがvar a = 1; delete window.a; console.log(a);表示されます1.
Dayong

5
Google Chrome v36を使用しています。他のブラウザでテストしました。それは一貫したクロスブラウザではないようです。ChromeとOperaは1を表示しましたが、私のコンピューターのFirefox、Safari、IE 11はエラーを出しました。
Dayong

3
わかりました、私の間違い。ecma-international.org/ecma-262/5.1/#sec-10.5(サブポイント2および8.c.ii)を参照してください:開発者コンソールでテストを実行するとき、それは一般に「評価コンテキスト」と見なされます(多分Chromeではないため)、エラーが発生します。実際のドキュメントのグローバルコンテキストの同じコードは、1すべてのブラウザーで正しく出力されます。実際のドキュメントで実行すると、コード例は正しいです。正解を選択しましたが、編集して説明window.a = 1; delete window.a;やメカニズムを含めることができるように編集していただければ幸いです。よろしければ、そうすることもできます。
Guss、

2
@KlaiderKlaiはい。関数スコープ変数は、関数が実行されるたびに作成および破棄されます。おそらく閉鎖は例外です。
Dayong

278

@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た変数を削除しませんが、適切な状況下ではできます。


14
その興味深い記事へのリンクを@jedierikbに感謝します。より具体的には、この記事のこの部分< perfectionkills.com/understanding-delete/#misconceptions >で、著者はnoahのステートメント「削除はノーオペレーションであるはずです」はかなり不正確であり、不正確である理由を説明していると述べています。 。(メッセンジャーを撮影しない!)
ロブ・ウェルズ

2
改訂された回答の最後の文に関して、で宣言された変数を削除できる唯一の状況varは、変数がで宣言されたときevalです。
Stephen Booher

1
ではこのような場合、delete文は全く何もする表示されません。何が起きてる?
アンダーソングリーン

@AndersonGreen-デカールされたグローバル変数はDontDeleteフラグで作成されるため、削除できません。そのコードは期待どおりに動作します。
RobG 2014

35

なしvarで暗黙的に変数を宣言している場合、適切な方法はを使用することdelete fooです。

ただし、削除した後、追加などの操作でこれを使用しようとするReferenceErrorと、宣言されていない未定義の識別子に文字列を追加できないため、a がスローされます。例:

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

状況によっては、false、null、またはundefinedに割り当てた方が安全な場合があるため、宣言されてこのタイプのエラーをスローしません。

foo = false

ECMAScriptの中にいることを注意nullfalseundefined0NaN、または''すべてに評価されますfalse!==演算子を使用!=しないで、ブール型のタイプチェック時にIDのチェックが不要であることを確認してください(そう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
})();

Rhinoの場合:

js> var x
js> delete x
false

また、次のような定義済みのプロパティを削除することもできませんMath.PI

js> delete Math.PI
false

deleteどの言語でもそうであるように、奇妙な例外がいくつかあります。


すべての詳細を含む完全な回答をありがとう。このためにマークアップしましたが、ノアの答えを受け入れました。単純な質問では、簡潔さのほうが完成よりも重要だと思うからです。繰り返しますが、この回答に対してすばらしい作業を行っていただきありがとうございます。
Guss

30
some_var = null;

//or remove it..
delete some_var;

11
このコードのスコープが関数の場合、これは機能しません。正しい解決策については、@ noahの回答を参照してください。
Roatin Marth

1
答えてくれてありがとう。ノアの答えは、の落とし穴をよく説明しているので受け入れましたdelete
Guss

3
心配は無用です。私は「素早い」の簡単な答えを出しました。@ noahは「その他」のケースの詳細をすべて追加したので、彼も信用に値します。;-)
scunliffe

7
これは正しくありません。deleteプロパティに対してのみ機能します。null変数を設定してもまだ存在します。
Derek━會功夫

1
この答えは、「もし(some_var){..}」でご確認最も可能性が高い場合に適して十分です
BearCode

16

TLDRは:(なしの単純な変数を定義しvarletconst)で削除される可能性がありdelete。、、、を使用するvar場合letconstそれらは、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仕様へのより多くの詳細と参照を含む選択された答えによってカバーされます-将来的には投稿する前に既存の答えをレビューすることは有用でしょう。
Guss

5
同意した。しかし、そこには唯一のvarケースが記載されていました。私については、テストして共有しletconstケースも興味深いものでした。ただし、ご注意いただきありがとうございます。次回はより具体的にしようとします。
Serj.by 2017年

4

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

4

変数は、単純なプロパティとは対照的に、属性[[Configurable]]を持っています。つまり、削除演算子を使用して変数を削除することはできません。ただし、このルールが影響しない実行コンテキストが1つあります。これは評価コンテキストです。[[Configurable]]属性が変数に設定されていません。



3

誰もが書いたものに加えて、deleteブール値を返すことにも注意してください。削除が成功したかどうかがわかります。

Chromeでテストしたところ、それ以外letはすべて削除できました。delete返されtrueたとき、実際にそれらを削除しました:

implicit_global = 1;
window.explicit_global = 1;
function_set = function() {};
function function_dec() { };
var declared_variable = 1;
let let_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
delete let_variable; // false, tested on Chrome 78

常に正しいとは限りません。特にChromeでは。Firefoxはすべてを正しく返します。他のブラウザではテストしていません。用としてletVARSとconst、変数が削除されたが、それはされていないことを意味すべきことを何trueを返しているvarsは。ChromeとFFの両方で確認できます。FFはChromeが正しくないのに正しい値を返すようです。だから、あなたが本当にそれに頼ることができるかどうかわからない。見てみましょう:let letVar = "1"; undefined delete letVar; true letVar "1" typeof letVar; "string" const constVar="1"; undefined delete constVar; true constVar; "1" typeof constVar; "string"
Serj.by

1
jedierikbが以下で言及するように、kangax perfectionkills.com/understanding-deleteによる完璧な記事があり、主にdeleteオペレーターが動作する理由と方法を説明しています。しかし、文字通り状況が関数と正反対である理由は説明されていません。残念です。ただし、変数に関しては、物事はより明確に見え始めます。
Serj.by 2017年

2

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


1

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

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

要件は、私の制御下にない注文スクリプトが変数が存在することを認識しないことです。特にOPの場合、ターゲットスクリプトには、nullトリガーしたくない値の動作があります。
ガス

この質問の作成中に「バックエンド」が悪用されることはありませんでした。これらは、この1つのスクリプト以外は何も制御できないWebサイト上のいくつかのスクリプトです。
ガス

両方のスクリプトが同じドキュメント内にありますか、または一方が他方をロードするために呼び出す別のドキュメント内にありますか?注文スクリプトとターゲットスクリプトについて説明しました。変数がget / post変数を介して別のスクリプトに渡される場合は、JavaScriptが手に入る前にバックエンドでその変数を削除します。PHPでのこの例は次のようになります。 <?php if(isset($_POST['somevariable']) unset($_POST['somevariable']); if(isset($_GET['somevariable']) unset($_GET['somevariable']); ?>
designdrumm

そうですか。ええと、nullのチェックとバランスがある場合、それを値に設定すると、ターゲットスクリプトは何もせず、スコープから変数を削除するよりも論理的に見えますが、あなたの答えがあるように見えるので、馬を産ませます。ご回答ありがとうございます。
designdrumm

簡単な質問です。あなたの後には呼び出されず、あなたの制御下にはないが、まだこの変数が必要なスクリプトはありますか?もしそうなら、スコープから変数を削除することは悪い考えです。
designdrumm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.