ホームページ >ウェブフロントエンド >jsチュートリアル >Javascriptオブジェクトの途中のキーを削除する_基礎知識

Javascriptオブジェクトの途中のキーを削除する_基礎知識

WBOY
WBOYオリジナル
2016-05-16 16:30:581681ブラウズ

あなたもこれはできません、家に帰って農作業をしてください

コードをコピーします コードは次のとおりです:

thisIsObject[キー]
を削除します または
thisIsObject.key
を削除します

ところで、delete の使い方についてお話しましょう

数週間前、Stoyan Stefanov の著書『オブジェクト指向 JavaScript』をチェックする機会がありました。この本は Amazon で高評価 (レビュー 12 件、星 5 つ) だったので、そのような本なのか知りたいと思っていました。この本は関数に関する章を読み始めました。この本の説明の仕方がとても気に入りました。また、例が非常に素晴らしく進歩的な方法でまとめられているので、一見したところ、初心者でもこれを習得できそうに見えました。しかし、すぐに、この章全体で発生した興味深い誤解に気付きました。関数の削除については、他にもいくつかの間違いがありましたが (関数宣言や関数式など)、ここでは説明しません。

この本の主張は次のとおりです。

「関数は通常の変数のように扱われ、別の変数にコピーしたり、削除したりすることもできます。」 この説明の後に例を示します:

コードをコピーします コードは次のとおりです:

var sum = function(a, b) {return a b;}
var add = sum;
合計を削除
本当
合計の種類;
「未定義」

欠落しているセミコロンを無視して、これらのコード行のどこにエラーがあるかわかりますか? 明らかに、エラーは、sum 変数の削除が成功しないこと、および typeof sum が返されないことです。 「未定義」も、JavaScript では変数の削除が不可能なためです。

それでは、この例で何が起こっているのでしょうか? それとも、特別な使用法なのでしょうか? このコードは実際には Firebug コンソールの出力であり、Stoyan はそれをツールとして使用したに違いありません。簡単なテストです。まるで Firebug が他の削除ルールに従っているかのようです。Stoyan が迷走したのは Firebug でした。それでは、何が起こっているのでしょうか?

この質問に答える前に、まず JavaScript での delete 演算子の仕組みを理解する必要があります。何が削除でき、何が削除できないのでしょうか。今日は、この質問について Firebug について詳しく説明します。 「奇妙な」動作を確認し、結局のところ、変数、関数の宣言、プロパティへの値の割り当て、およびそれらの削除の背後にあるものを詳しく見ていきます。ブラウザの互換性といくつかの最も悪名高いバグについても説明します。ES5 の厳密モードと、削除演算子の動作がどのように変わるかについても説明します。

ここでは JavaScript と ECMAScript を同じ意味で使用します。どちらも ECMAScript を意味します (明らかに Mozilla の JavaScript 実装について話している場合を除く)

当然のことながら、削除に関する説明は Web 上でほとんどありません。おそらく、MDC の記事が理解するのに最適なリソースです。しかし、残念ながら、この件に関する興味深い詳細がいくつか欠けています。そう、忘れられているものの 1 つが原因です。 Firebug の奇妙な動作については、MSDN リファレンスはこれらの点ではほとんど役に立ちません。

理論

それでは、なぜオブジェクトのプロパティを削除できるのでしょうか:

コードをコピーします コードは次のとおりです:
var o = { x: 1 };
o.x を削除します。 // true
o.x; // 未定義


ただし、次のように宣言されたオブジェクトは削除できません:

コードをコピーします コードは次のとおりです:
var x = 1;
x を削除します。 // false
x; // 1


または関数:

コードをコピーします コードは次のとおりです:
関数 x(){}
x を削除します。 // false
typeof x; // "関数"

注: 属性を削除できない場合、削除演算子は false のみを返します

これを理解するには、まず変数インスタンスとプロパティ プロパティに関するこれらの概念を理解する必要があります。これらの概念は、残念ながら JavaScript の本ではほとんど言及されていません。これらの概念については、次の数段落で簡単に説明します。 . これらの概念は理解するのが難しいです。 「なぜこれらのことがそのように機能するのか」に興味がない場合は、この章を飛ばしてください。

コードの種類:

ECMAScript には、グローバル コード、関数コード、および Eval コードという 3 つの異なるタイプの実行可能コードがあります。これらのタイプは、名前がほぼ同じであるため、簡単に説明します。

ソース コードの一部がプログラムとして表示されると、それはグローバル環境で実行され、ブラウザ環境ではグローバル コードとみなされ、通常、スクリプト要素のコンテンツはプログラムとして解釈されるため、グローバルとして実行されます。コード。

関数内で直接実行されるコードは、明らかに関数コードとみなされます。ブラウザでは、通常、イベント属性 (

など) の内容が関数コードに解釈されます。

最後に、組み込み関数 eval に適用されたコード テキストは Eval コードとして解釈されます。この型が特別である理由がすぐにわかります。

実行コンテキスト:

ECMAScript コードが実行されるとき、それは通常、特定の実行コンテキストで発生します。実行コンテキストは、スコープ (Scope) と変数のインスタンス化 (Variable instantiation) がどのように機能するかを理解するのに役立つ、やや抽象的なエンティティの概念です。関数が実行されると、それに対応する実行コンテキストが存在します。グローバル コードが実行されると、プログラム コントロールが実行コンテキストに入ります。グローバルコードなど

ご覧のとおり、実行コンテキストは論理的にスタックを形成できます。まず、独自の実行コンテキストを持つグローバル コードがあり、そのコードが実行コンテキストを引き連れて関数を呼び出すことがあります。この関数は別の関数などを呼び出すことができます。関数が再帰的に呼び出された場合でも、呼び出されるたびに新しい実行コンテキストに入ります。

アクティブ化オブジェクト/変数オブジェクト:

各実行コンテキストには、いわゆる変数オブジェクトが関連付けられています。実行コンテキストと同様に、変数オブジェクトは抽象エンティティであり、変数インスタンスを記述するために使用されるメカニズムです。ソース コードは通常、この変数オブジェクトにプロパティとして追加されます。

プログラム制御がグローバル コードの実行コンテキストに入ると、グローバル オブジェクトが変数オブジェクトとして使用されます。これが、グローバルとして宣言された関数変数がグローバル オブジェクトのプロパティになる理由です。

コードをコピーします コードは次のとおりです:
/* グローバル スコープ内の場合、`this` はグローバル オブジェクトを参照することに注意してください */
var GLOBAL_OBJECT = this;
var foo = 1;

GLOBAL_OBJECT.foo; // 1
foo === GLOBAL_OBJECT.foo // true

関数バー(){}

typeof GLOBAL_OBJECT.bar // "関数"
GLOBAL_OBJECT.bar === バー; // true

それで、グローバル変数はグローバル オブジェクトのプロパティになりますが、ローカル変数 (関数コードで定義されたもの) は実際にはどうなるのでしょうか? それらは実際には変数オブジェクト (Variable オブジェクト) になるときだけ異なります。関数コードでは、変数オブジェクトはグローバル オブジェクトではなく、いわゆるアクティベーション オブジェクトであり、関数コードの実行コンテキストに入るたびに呼び出されます。

関数コードで宣言された変数と関数だけがアクティブ オブジェクトのプロパティになるわけではありません。これは、各関数パラメータ (対応する仮パラメータの名前に対応) および特別な Arguments オブジェクト (引数付き) でも行われます。アクティブなオブジェクトは内部記述メカニズムであり、プログラム コードからアクセスできないことに注意してください。

コードをコピー コードは次のとおりです:

(関数(foo){
var bar = 2;
関数 baz(){}
/*
抽象的に言えば、
特別な `arguments` オブジェクトは、関数の Activation オブジェクトを含むプロパティになります:
ACTIVATION_OBJECT.arguments; // 引数オブジェクト
...引数 `foo`:
と同様に ACTIVATION_OBJECT.foo; // 1
...変数 `bar` と同様に:
ACTIVATION_OBJECT.bar // 2
...ローカルで宣言された関数と同様に:
ACTIVATION_OBJECT.baz の種類 // "関数"
*/
})(1);

最後に、Eval コードで宣言された変数は、呼び出し元コンテキストの変数オブジェクトのプロパティになります。Eval コードは、それを呼び出すコードの実行コンテキストの変数オブジェクトを単に使用します。

コードをコピーします コードは次のとおりです:
var GLOBAL_OBJECT = this;
/* `foo` は呼び出し元コンテキスト変数オブジェクトのプロパティとして作成されます
この場合、これはグローバル オブジェクトです */
eval('var foo = 1;');
GLOBAL_OBJECT.foo; // 1
(関数(){
/* `bar` は呼び出し元コンテキスト変数オブジェクトのプロパティとして作成されます,
この場合、これは関数 */
を含む Activation オブジェクトです。 eval('var bar = 1;');
/*
抽象的に言えば、
ACTIVATION_OBJECT.bar // 1
*/
})();

プロパティ属性

変数に何が起こるか (変数がプロパティになる) についてはほぼ理解できました。理解する必要がある唯一の概念は、各プロパティが 0 個以上の属性を持つことができることです。次のセット: ReadOnly、DontEnum、DontDelete、および Internal。これらはフラグとして考えることができます。属性は属性に存在する場合と存在しない場合があります。今日の説明では、DontDelete のみに興味があります。

宣言された変数と関数が変数オブジェクト (または関数コードのアクティブ オブジェクト、またはグローバル コードのグローバル オブジェクト) の属性になると、これらの属性は DontDelete 属性を使用して作成されます。ただし、明示的なプロパティは作成されます。 by (または暗黙的) プロパティの割り当てには DontDelete 属性がありません。これが、一部のプロパティを削除できるのですが、他のプロパティは削除できないのです。

コードをコピーします コードは次のとおりです:
var GLOBAL_OBJECT = this;
/* `foo` は Global オブジェクトのプロパティです。
変数宣言によって作成されるため、DontDelete 属性があります。
このため、削除できません。 */
var foo = 1;
foo を削除します。 // false
typeof foo; // "数値"
/* `bar` は Global オブジェクトのプロパティです。
関数宣言によって作成されるため、DontDelete 属性があります。
そのため、*/
も削除できません。 関数 bar(){}
バーを削除; // false
バーの種類; // "関数"
/* `baz` も Global オブジェクトのプロパティです。
ただし、プロパティの割り当てによって作成されるため、DontDelete 属性はありません。
これが削除できる理由です。 */
GLOBAL_OBJECT.baz = 'まあ';
GLOBAL_OBJECT.baz を削除します。 // true
typeof GLOBAL_OBJECT.baz; // "未定義"


組み込みオブジェクトと DontDelete

これがすべてです (DontDelete): この属性の特別な特性。この属性を削除できるかどうかを制御するために使用されます。一部の組み込みオブジェクト属性は DontDelete を含むように指定されているため、削除できないことに注意してください。たとえば、特殊な引数変数 (または、現在ではアクティブなオブジェクトのプロパティ) には DontDelete プロパティがあります。関数インスタンスの length プロパティにも DontDelete プロパティがあります。

コードをコピーします コードは次のとおりです: (関数(){
/* DontDelete があるため、`arguments` は削除できません */
引数を削除; // false
引数の種類; // "オブジェクト"
/* 関数の `length` は削除できません */
もあります。 関数 f(){}
f.length を削除します。 // false
typeof f.length; // "数値"
})();

関数のパラメータに対応する属性も作成時から DontDelete 属性を持っているため、削除できません。

コードをコピーします コードは次のとおりです:

(関数(foo, bar){
foo を削除します。 // false
foo; // 1
バーを削除; // false
バー; // 'まあ'
})(1, 'まあ');

未宣言の割り当て:

宣言されていない代入は、グローバル オブジェクトの前にスコープ チェーン内の他の場所でプロパティが既に見つかっていない限り、グローバル オブジェクトにプロパティを作成することを覚えているかもしれません。これで、プロパティの代入と変数について理解できました。宣言の違いについては説明しました。後者は DontDelete プロパティを設定しますが、前者は設定しません。なぜ未宣言の代入によって削除可能なプロパティが作成されるのかを理解する必要があります。

コードをコピーします コードは次のとおりです:

var GLOBAL_OBJECT = this;
/* 変数宣言を介してグローバル プロパティを作成します。プロパティには DontDelete があります */
var foo = 1;
/* 宣言されていない代入を介してグローバル プロパティを作成します。プロパティには DontDelete がありません */
バー = 2;
foo を削除します。 // false
typeof foo; // "数値"
バーを削除; // true
バーの種類; // "未定義"

注意: プロパティはプロパティの作成時に決定され、その後の割り当てでは既存のプロパティのプロパティは変更されません。この違いを理解することが重要です。

コードをコピーします コードは次のとおりです:

/* `foo` は DontDelete を使用してプロパティとして作成されます */
関数 foo(){}
/* その後の割り当てでは属性は変更されません */
foo = 1;
foo を削除します。 // false
typeof foo; // "数値"
/* ただし、存在しないプロパティに代入すると、
空の属性 (DontDelete なし) でそのプロパティを作成します */
this.bar = 1;
バーを削除; // true
バーの種類; // "未定義"

Firebug の混乱:

Firebug では何が起こったのでしょうか? コンソールで宣言された変数はなぜ削除できるのでしょうか? これは、以前に学習したことに違反しませんか? 前に述べたように、Eval コードは変数を宣言するときに特殊な動作をします。 Eval で宣言された変数は、実際には DontDelete 属性のないプロパティとして作成されます。

コードをコピーします コードは次のとおりです:

eval('var foo = 1;');
foo; // 1
foo を削除します。 // true
typeof foo; // "未定義"

また、関数コード内で呼び出された場合も同様に:

コードをコピーします コードは次のとおりです:

(関数(){

eval('var foo = 1;');
foo; // 1
foo を削除します。 // true
typeof foo; // "未定義"

})();

これは、Firebug の異常な動作の基礎です。コンソール内のすべてのテキストは、グローバル コードや関数コードではなく、Eval コードとして解析され、実行されます。明らかに、ここで宣言されたすべての変数は、最終的に DontDelete 属性のないプロパティになります。すべて簡単に削除できます。グローバル コードと Firebug コンソールの違いを理解する必要があります。

Eval 経由で変数を削除します:

この興味深い eval 動作は、ECMAScript の別の側面と組み合わせることで、技術的には「削除不可能な」属性を削除できる可能性があります。関数宣言の特徴は、同じ実行コンテキスト内で同じ名前の変数をオーバーライドできることです。

コードをコピーします コードは次のとおりです:

関数 x(){ }
var x;
typeof x; // "関数"

関数宣言がどのように優先され、同じ名前の変数 (つまり、変数オブジェクト内の同じプロパティ) をオーバーライドするかに注目してください。これは、関数宣言が変数宣言の後にインスタンス化され、許可されるためです。それらをオーバーライドします (変数宣言)。関数宣言はプロパティの値を置き換えるだけでなく、そのプロパティの属性も置き換えます。eval を介して関数を宣言した場合、その関数はそれを元の属性に置き換える必要があります。また、eval で宣言された変数は DontDelete 属性のないプロパティを作成するため、この新しい関数をインスタンス化すると、実際には既存の DontDelete 属性がプロパティから削除され、A プロパティを削除できるようになります (そして、明らかに、そのプロパティをポイントします)。値を新しく作成した関数に代入します)。

コードをコピーします コードは次のとおりです:

var x = 1;
/* 削除できません。`x` には DontDelete があります */
x を削除します。 // false
typeof x; // "数値"
eval('function x(){}');
/* `x` プロパティは関数を参照するようになったため、DontDelete を含めるべきではありません */
typeof x; // "関数"
delete x; // `true`
である必要があります typeof x; // 「未定義」である必要があります

残念ながら、この「チート」は現在の実装では機能しません。おそらく、ここに何かが欠けているか、実装者が気づいていないほど動作が曖昧なのかもしれません。

ブラウザの互換性:

理論的にどのように機能するかを理解することは役に立ちますが、実践することが最も重要です。変数/プロパティの作成/削除に関しては、ブラウザは標準に従っていますか? 答えは次のとおりです。ほとんどの場合、「はい」です。

私は、グローバル コード、関数コード、および Eval コードでのテストを含む、削除演算子とブラウザの互換性をテストするための簡単なテスト セットを作成しました。このテスト セットは、削除演算子の戻り値と属性値を (必要に応じて) チェックしました。 delete の戻り値は、実際の結果ほど重要ではありません。 delete が false ではなく true を返すかどうかはあまり重要ではありません。重要なのは、 DontDelete 属性を持つ属性が削除されないことです。その逆も同様です。

最近のブラウザは一般的に互換性が高く、前述した eval 機能を除き、次のブラウザはすべてのテスト セットに合格しました: Opera 7.54、Firefox 1.0、Safari 3.1.2、Chrome 4。

Safari 2.x および 3.0.4 では、関数パラメータの削除に問題があります。これらのプロパティは DontDelete を使用せずに作成されているようです。そのため、Safari 2.x にはさらに問題があります。非参照型変数の削除 (例: delete. 1) 例外をスローします。関数宣言は削除可能なプロパティを作成します (ただし、不思議なことに、変数宣言は削除できません)。eval の変数宣言は削除できなくなります。

Safari と同様に、Konqueror (4.3 ではなく 3.5) は、非参照型 (delete 1 など) を削除するときに例外をスローし、誤って関数変数を削除可能にしてしまいます。

翻訳者注:

Chrome、Firefox、IE の最新バージョンをテストし、失敗した 23 と 24 を除いて基本的にパスを維持しました。Nokia E72 の内蔵ブラウザに加えて、UC と一部のモバイル ブラウザもテストしました。失敗 15 と 16 を除いて、他のほとんどの内蔵ブラウザはデスクトップ ブラウザと同じ効果がありますが、Blackberry Curve 8310/8900 の内蔵ブラウザがテスト 23 に合格できることには言及する価値があります。これには驚きました。

Gecko DontDelete バグ:

Gecko 1.8.x ブラウザ - Firefox 2.x、Camino 1.x、Seamonkey 1.x など - 非常に興味深いバグがあり、プロパティに明示的に割り当てると、属性が作成されている場合でも DontDelete 属性が削除されます。変数宣言または関数宣言を通じて。

コードをコピーします コードは次のとおりです:

関数 foo(){}
delete foo; // false (予想通り)
typeof foo; // "関数" (期待通り)
/* 明示的にプロパティに割り当てます */
this.foo = 1 // DontDelete 属性を誤ってクリアします
foo を削除します。 // true
typeof foo; // "未定義"
/* プロパティを暗黙的に割り当てる場合はこれが起こらないことに注意してください */
関数 bar(){}
バー = 1;
バーを削除; // false
typeof bar; // "数値" (割り当てはプロパティに置き換わります)

驚くべきことに、Internet Explorer 5.5 ~ 8 は、非参照型の削除 (例: delete 1) が例外をスローすることを除いて、完全なテストに合格します (古い Safari と同様)。しかし、IE ではさらに深刻なバグがあります。それほど明らかではありませんが、これらのバグはグローバル オブジェクトに関連しています。

IE のバグ:

この章全体は Internet Explorer のバグについてです。驚きですね!

IE (少なくとも IE 6 ~ 8) では、次の式は例外をスローします (グローバル コードで実行される場合):

this.x = 1;
delete x; // TypeError: オブジェクトはこのアクションをサポートしていません
これも同様ですが、別の例外をスローするため、事態はより興味深いものになります。

var x = 1;
delete this.x; // TypeError: 'this.x' を削除できません
IE では、グローバル コード内の変数宣言ではグローバル オブジェクトにプロパティが作成されないようです。割り当て (this.x = 1) によってプロパティを作成し、それを delete x によって削除すると、プロパティの作成を宣言するとエラーがスローされます。 (var x = 1) その後、delete this.x で削除すると、別のエラーがスローされます。

しかし、それだけではありません。明示的な割り当てによってプロパティを作成すると、実際には削除時に例外がスローされます。作成されるプロパティには DontDelete 属性があるように見えますが、これはもちろんそうではありません。

this.x = 1;

delete this.x; // TypeError: オブジェクトはこのアクションをサポートしていません
typeof x; // "number" (まだ存在しますが、削除されるべきではありませんでした!)

delete x; // TypeError: オブジェクトはこのアクションをサポートしていません
typeof x; // "数値" (再度削除されませんでした)
ここで、IE では、宣言されていない割り当て (グローバル オブジェクトにプロパティを作成する必要がある) が実際に削除可能なプロパティを作成すると仮定します。

x = 1;

x を削除します。 // true
typeof x; // "未定義"
ただし、グローバル コードのこの参照を通じてこの属性を削除すると (this.x を削除)、同様のエラーがポップアップ表示されます。

x = 1;

delete this.x; // TypeError: 'this.x' を削除できません
この動作を一般化したい場合、delete this.x を使用してグローバル コードから変数を削除すると、問題のプロパティが明示的な割り当て (this.x = 1) によって作成されると、プロパティがエラーをスローするようです。未宣言の代入 (x = 1) または宣言 (var x = 1) によって作成された場合、削除すると別のエラーがスローされます。
一方、

delete x は、プロパティが明示的な代入 (this.x = 1) によって作成された場合にのみエラーをスローします。プロパティが宣言 (var x = 1) によって作成された場合、削除は行われません。プロパティが宣言されていない代入 (x = 1) によって作成された場合、削除は正しく false を返します。

私は 9 月にこの問題について再度考え、Garrett Smith が IE では次のように提案しました。

「グローバル変数オブジェクトは JScript オブジェクトとして実装され、グローバル オブジェクトはホストによって実装されます。」

ギャレットは、エリック・リッパートのブログエントリーを参考として使用しました。

いくつかのテストを実装することで、この理論を多かれ少なかれ確認できます。this と window は同じオブジェクト (=== 演算子を信頼できる場合) を指しているように見えますが、変数オブジェクト (関数宣言が指定されているオブジェクト) を指していることに注意してください。ある) は、this が指すものとは異なります。

コードをコピーします コードは次のとおりです:
/* グローバル コード内 */
関数 getBase(){ これを返す }
getBase() === this.getBase() // false

this.getBase() === this.getBase() // true
window.getBase() === this.getBase() // true
window.getBase() === getBase() // false

誤解:

なぜ物事がそのように機能するのかを理解することの美しさは、ウェブ上で削除演算子に関するいくつかの誤解を見てきました。たとえば、Stackoverflow でのこの回答 (驚くほど高い評価を得ています) は、

「ターゲット オペランドがオブジェクト プロパティではない場合、削除は何も行われません。」

削除操作の動作の中核を理解したので、この回答の間違いは明らかになります。削除は変数とプロパティを区別せず(実際、削除の場合、両方とも参照型です)、実際にはDontDeleteのみを気にします。属性 (および属性自体が存在するかどうか)。

さまざまな誤解が互いに反論されているのを見るのは非常に興味深いものです。同じスレッドで、ある人は最初に変数を削除するだけを提案しました (評価で宣言されない限り効果はありません)、別の人はバグ修正を提供しましたdelete を使用してグローバル コードで変数を削除できるが、関数コードでは使用できないことを説明します。

インターネット上での JavaScript の解釈には細心の注意を払ってください。理想的なアプローチは、問題の性質を常に理解することです ;)

削除とホストオブジェクト:

削除のアルゴリズムはおおよそ次のとおりです:

オペランドが参照型でない場合、true を返します

オブジェクトにこの名前の直接プロパティがない場合は、true を返します (ご存知のとおり、オブジェクトはアクティブ オブジェクトまたはグローバル オブジェクトにすることができます)
属性が存在するが DontDelete 属性がある場合は、false
を返します。 それ以外の場合は、属性を削除して true を返します
ただし、ホスト オブジェクトに対する削除演算子の動作は予測不可能であり、実際にはこの動作に問題はありません。(標準に従って) ホスト オブジェクトは読み取り (内部 [[Get]])、書き込みなどの関数を実行できます。 (内部 [[Put]] メソッド) および delete (内部 [[Delete]] メソッド) いくつかの演算子は任意の動作を実装します。この猶予により、ホスト オブジェクトが混乱の原因となります。

特定のオブジェクト (明らかにホスト オブジェクトとして実装されている) を削除すると、Firefox の一部のバージョンで window.location を削除するとエラーがスローされるという IE の不具合が発生しました。オブジェクトがホスト オブジェクトの場合の delete の戻り値 Firefox で何が起こるか見てみましょう:

コードをコピーします コードは次のとおりです:
/* "alert" は `window` の直接のプロパティです (`hasOwnProperty` を信じる場合) */
window.hasOwnProperty('alert') // true
window.alert を削除します。// true

typeof window.alert; // "関数"

このプロパティがそのような結果を引き起こす理由がまったくない場合でも、window.alert を削除すると true が返されます (したがって、最初のステップでは true は返されません)。したがって、delete が true を返すことができるのは、4 番目のステップに到達して実際にその属性を削除するときだけです。ただし、この属性は決して削除されません。

この話の教訓は、ホスト オブジェクトを決して信頼しないでください。

ES5 厳密モード:

では、厳密モードの ECMAScript 5 では、delete 演算子の式が変数、関数パラメータ、または関数識別子への直接参照である場合に、構文エラーがほとんど発生しません。 、プロパティに内部属性 [[Configurable]] == false がある場合、型エラーがスローされます。

コードをコピーします コードは次のとおりです:
(関数(foo){
"use strict"; // この関数内で strict モードを有効にします
var bar;
関数 baz(){}
delete foo; // SyntaxError (引数削除時)
delete bar; // SyntaxError (変数削除時)
delete baz; // SyntaxError (関数宣言で作成した変数を削除する場合)
/* 関数インスタンスの `length` には { [[Configurable]] : false } */
delete (function(){}).length; // TypeError
})();

また、宣言されていない変数 (または未解決の参照) を削除すると、構文エラーがスローされます。

「厳密に使用する」;
delete i_dont_exist; // 構文エラー
未宣言の代入は、厳密モードの未宣言の変数と同様に動作します (ただし、今回は構文エラーではなく参照エラーが発生します):

「厳密に使用する」;
i_dont_exist = 1 // 参照エラー
; もうお分かりいただけると思いますが、変数、関数宣言、パラメータの削除は非常に多くの混乱を引き起こすため、すべての制限は多かれ少なかれ意味があります。厳密モードでは削除を黙って無視するのではなく、より積極的でより記述的な手段が講じられます。

概要:

このブログ投稿は非常に長くなったので、delete による配列オブジェクトの削除やその意味などについては説明しません。専用の説明については MDC の記事を参照してください (または標準を読んでください)。独自の実験を行ってください)。

JavaScript での削除の仕組みを簡単にまとめます。

変数と関数の宣言は、アクティブ オブジェクトまたはグローバル オブジェクトのプロパティです
属性にはいくつかの特性があり、その中の DontDelete は属性を削除できるかどうかを決定する特性です
。 グローバル コードまたは関数コード内の変数および関数の宣言は、常に DontDelete 属性を持つプロパティを作成します。
関数パラメータは常にアクティブなオブジェクトのプロパティであり、DontDelete を持ちます。
Eval コードで宣言された変数と関数は、常に DontDelete プロパティなしで作成されます。 新しいプロパティには、作成時に属性がありません (もちろん、DontDelete もありません)。 ホスト オブジェクトは、削除操作にどのように反応するかを決定できます。
ここで説明されている内容をさらに詳しく知りたい場合は、ECMA-262 第 3 版の仕様を参照してください。

この記事を楽しんでいただき、何か新しいことを学んでいただければ幸いです。ご質問、ご提案、修正は大歓迎です。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。