国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript 中的 delete

Hancock_Xu / 3134人閱讀

摘要:所有在控制臺(tái)中的調(diào)試文本似乎是以來編譯和執(zhí)行的,而不是在全局或函數(shù)代碼中執(zhí)行。所以要小心普通的全局代碼和控制臺(tái)中代碼的區(qū)別。

原文:Understanding delete

譯文:javascript 中的 delete

譯者:@justjavac


在這篇文章中作者從《JavaScript面向?qū)ο缶幊讨改稀芬粫嘘P(guān)于 delete 的錯(cuò)誤講起,詳細(xì)講述了關(guān)于 delete 操作的實(shí)現(xiàn), 局限以及在不同瀏覽器和插件(這里指 firebug)中的表現(xiàn)。

下面翻譯其中的主要部分。

...書中聲稱

  

“函數(shù)就像一個(gè)普通的變量那樣——可以拷貝到不同變量,甚至被刪除”

并附上了下面的代碼片段作為說明:

>>> var sum = function(a, b) {return a+b;};
>>> var add = sum;
>>> delete sum;
true
>>> typeof sum;
"undefined"

你能發(fā)現(xiàn)片段中的問題嗎? 這個(gè)問題就是——?jiǎng)h除 sum 變量的操作不應(yīng)該成功; delete 的聲明不應(yīng)該返回 true 而 typeof sum 也不應(yīng)該返回為 undefined。 因?yàn)椋琷avascript 中不能夠刪除變量,至少不能以這個(gè)方式聲明刪除。

那么這個(gè)例子發(fā)生了什么? 是打印錯(cuò)誤或者玩笑? 應(yīng)該不是。 這個(gè)片段是 firebug 控制臺(tái)中的一個(gè)實(shí)際輸出,而 Stoyan(上面所說書的作者)應(yīng)該正是用它做的快速測(cè)試。 這仿佛說明了 firebug 有一些不同的刪除規(guī)則。 正是 firebug 誤導(dǎo)了 Stoyan! 那么這里面究竟是怎么回事呢?

為了回答這個(gè)問題,我們需要了解 delete 運(yùn)算符在 Javascript 中是如何工作的: 哪些可以被刪除,哪些不能刪除以及為什么。 下面我試著解釋一下這方面的細(xì)節(jié)。 我們將通過觀察 firebug 的“奇怪”的表現(xiàn)而認(rèn)識(shí)到它實(shí)際上完全不“奇怪”; 我們將深入了解那些,當(dāng)我們聲明變量、函數(shù),賦值屬性和刪除它們時(shí)的,隱藏在背后的細(xì)節(jié); 我們將看一下瀏覽器對(duì)此的實(shí)現(xiàn)和一些有名的 bug; 我們還會(huì)討論到 ECMAScript 版本 5 中的嚴(yán)格模式(strict mode)以及它如何改變 delete 運(yùn)算符的行為。

  

我在下面交替使用的 Javascript 和 ECMPScript 一般都指 ECMAScript(除非當(dāng)明確談到 Mozilla 的 JavaScript? 實(shí)現(xiàn)時(shí))。

意料之中的,網(wǎng)絡(luò)上目前對(duì)于 delete 的解釋非常少(筆者按:這篇文章寫于 2010 年 1 月)。 MDC(MDN]) 的資源大概是這其中最詳細(xì)的了,但不幸的是它遺漏了一些有趣的細(xì)節(jié),這些細(xì)節(jié)中就包括了上述 firebug 的奇怪表現(xiàn)。 MSDN 文檔幾乎沒什么用處。

一、理論 | Theory

那么,為什么我們能刪除一個(gè)對(duì)象的屬性:

var x = { a: 1 };
delete x.a; // true
x.a; // undefined

但卻不能刪除一個(gè)變量:

var x = 1;
delete x; // false;
x; // 1

也不能刪除一個(gè)函數(shù):

function x() {};
delete x; // false;
typeof x; // "function"

注意:delete 只有當(dāng)一個(gè)屬性無法被刪除時(shí)才返回 false。

為了理解這一點(diǎn),我們需要首先把握一些概念: 變量實(shí)例化(variable instantiation)和屬性的內(nèi)部屬性(property attributes) (譯者按:關(guān)于 property 和 attributes 的區(qū)別見參考文章,根據(jù)下面涉及到的內(nèi)容,擬譯成內(nèi)部屬性) ——這些很少在 javascript 書中被提到。 在下面幾段中我將試著簡(jiǎn)短地回顧這些內(nèi)容,要理解它們并不難。 如果你并不關(guān)注它們表現(xiàn)背后的原因,可以跳過這一章。

1.1、代碼的類型 | Type of code

ECMAScript 中有三類可執(zhí)行代碼:

全局代碼 Global code

函數(shù)代碼 Function code

Eval code

這幾類的含義大致就像它們命名的那樣,但還是快速地回顧一下:

當(dāng)一個(gè)源文件被看做是一個(gè)程序,它在全局作用域(scope)內(nèi)執(zhí)行,而這就被認(rèn)為是一段全局代碼 Global code。 在瀏覽器環(huán)境下,SCRIPT 元素的內(nèi)容通常都被解析為一個(gè)程序,因而作為全局代碼來執(zhí)行。

當(dāng)然,任何在一段函數(shù)中直接執(zhí)行的代碼就被認(rèn)為是一段函數(shù)代碼 Function code, 在瀏覽器環(huán)境下,事件屬性的內(nèi)容(e.g. )通常都作為函數(shù)代碼來解析和執(zhí)行。

最后,放入內(nèi)建函數(shù) eval 中的代碼就作為 Eval code 來解析。我們將很快看到為什么這一類型是特殊的。

1.2、代碼執(zhí)行的上下文 | Execution Context

當(dāng) ECMAScript 代碼執(zhí)行時(shí),它總是發(fā)生在一個(gè)確定的執(zhí)行上下文(context)中。 執(zhí)行作用域是一個(gè)抽象實(shí)體,它有助于理解作用域和變量實(shí)例化的工作原理。 上面三類可執(zhí)行代碼都有各自的執(zhí)行上下文。 當(dāng)函數(shù)代碼執(zhí)行時(shí),我們說控制端進(jìn)入了函數(shù)代碼的執(zhí)行上下文; 當(dāng)全局代碼執(zhí)行時(shí),我們說控制端進(jìn)入了全局代碼的執(zhí)行上下文,以此類推。

正如你所見,執(zhí)行上下文在邏輯上是一個(gè)棧(stack)。 首先可能有一段全局代碼,它擁有屬于自己的執(zhí)行上下文; 在這段代碼中可能調(diào)用一個(gè)函數(shù),這個(gè)函數(shù)同樣擁有屬于自己的執(zhí)行上下文; 這個(gè)函數(shù)可能調(diào)用另一個(gè)函數(shù),等等。 即使當(dāng)函數(shù)遞歸調(diào)用自己時(shí),在每一步調(diào)用中仍然進(jìn)入了不同的執(zhí)行上下文。

1.3、活化對(duì)象和變量對(duì)象 | Activation object / Variable object

每一個(gè)執(zhí)行上下文都有一個(gè)與之相關(guān)聯(lián)的變量對(duì)象(Variable object)。 和它相似的,變量對(duì)象也是一個(gè)抽象實(shí)體,一種用來描述變量實(shí)例化的機(jī)制。 而有趣的是,在一段源代碼中聲明的變量和函數(shù)事實(shí)上被作為變量對(duì)象(Variable object)的屬性(properties)而添加到變量對(duì)象中

當(dāng)控制進(jìn)入了全局代碼的執(zhí)行上下文時(shí),一個(gè)全局對(duì)象被用作變量對(duì)象。 這恰恰是為什么全局聲明的變量和函數(shù)變成一個(gè)全局對(duì)象的屬性的原因:

var GLOBAL_OBJECT = this;
var foo = 1;
GLOBAL_OBJECT.foo; // 1
function bar() {};
typeof GLOBAL_OBJECT.bar; // "function"
GLOBAL_OBJECT.bar === bar; // true

Ok, 所以全局變量成了全局函數(shù)的屬性,那么局部變量——那些在函數(shù)代碼(Function code)中聲明的變量呢? 事實(shí)上那很簡(jiǎn)單:他們也成了變量對(duì)象的屬性。 唯一的區(qū)別是,在函數(shù)代碼中,變量對(duì)象不是一個(gè)全局對(duì)象, 而是一個(gè)我們稱之為活化對(duì)象(Activation object)。 每次進(jìn)入函數(shù)代碼的執(zhí)行上下文時(shí)都會(huì)創(chuàng)建一個(gè)活化對(duì)象。

并非只有在函數(shù)代碼中聲明的變量和函數(shù)才成為活化對(duì)象的屬性: 函數(shù)的每一個(gè)實(shí)參(arguments,以各自相對(duì)應(yīng)的形參的名字為屬性名), 以及一個(gè)特殊的Arguments對(duì)象(以arguments為屬性名)同樣成為了活化對(duì)象的屬性。 需要注意的是,活化對(duì)象作為一個(gè)內(nèi)部的機(jī)制事實(shí)上不能被程序代碼所訪問。

(function(foo) {
    var bar = 2;
    function baz() {};
    /*
        在抽象的過程中,
        特殊的"arguments"對(duì)象變成了所在函數(shù)的活化對(duì)象的屬性:
        ACTIVATION_OBJECT.arguments = arguments;
        ...參數(shù)"foo‘也是一樣:
        ACTIVATION_OBJECT.foo; // 1
        ...變量"bar"也是一樣:
        ACTIVATION_OBJECT.bar; // 2
        ...函數(shù)"baz"也是一樣:
        typeof ACTIVATION_OBJECT.baz; // "function"
      */
}) (1);

最后,Eval code 中聲明的變量成為了上下文的變量對(duì)象(context"s Variable object)的屬性。 Eval code 簡(jiǎn)單地使用在它調(diào)用中的執(zhí)行上下文的變量對(duì)象。

var GLOBAL_OBJECT = this;
eval("var foo = 1");
GLOBAL_OBJECT.foo; // 1;

(function() {
    eval("var bar = 2");

    /*
        在抽象過程中
        ACTIVATION_OBJECT.bar; // 2
    */
}) ();
1.4、屬性的內(nèi)部屬性 | Property attributes

就要接近主題了。 現(xiàn)在我們明確了變量發(fā)生了什么(它們成了屬性),剩下的需要理解的概念就是屬性的內(nèi)部屬性(property attributes)。 每一個(gè)屬性擁有零至多個(gè)如內(nèi)部屬性——*ReadOnly,DontEnum,DontDelete和Internal**。 你可以把它們想象為標(biāo)簽——一個(gè)屬性可能擁有也可能沒有某個(gè)特殊的內(nèi)部屬性。 在今天的討論中,我們所感興趣的是 DontDelete。

當(dāng)聲明變量和函數(shù)時(shí),它們成為了變量對(duì)象(Variable object)——要么是活化對(duì)象(在函數(shù)代碼中), 要么是全局對(duì)象(在全局代碼中)——的屬性,這些屬性伴隨生成了內(nèi)部屬性 DontDelete。 然而,任何顯式/隱式賦值的屬性不生成 DontDelete。 而這就是本質(zhì)上為什么我們能刪除一些屬性而不能刪除其他的原因。

var GLOBAL_OBJECT = this;

/* "foo"是全局對(duì)象的一個(gè)屬性,
    它通過變量聲明而生成,因此擁有內(nèi)部屬性DontDelete
    這就是為什么它不能被刪除*/
var foo = 1;
delete foo; // false
typeof foo; // "number"

/* "bar"是全局對(duì)象的一個(gè)屬性,
    它通過變量聲明而生成,因此擁有DontDelete子
    這就是為什么它同樣不能被刪除*/
function bar() {};
delete bar; // false
typeof bar; // "function"

/* "baz"也是全局對(duì)象的一個(gè)屬性,
    然而,它通過屬性賦值而生成,因此沒有DontDelete
    這就是為什么它可以被刪除*/
GLOBAL_OBJECT.baz = "baz";
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"
1.5、內(nèi)建和DontDelete | Build-ins and DontDelete

所以這就是所有這一切發(fā)生的原因:屬性的一個(gè)特殊的內(nèi)部屬性控制著該屬性是否可以被刪除。 注意:內(nèi)建對(duì)象的一些屬性擁有內(nèi)部屬性 DontDelete,因此不能被刪除; 特殊的 arguments 變量(如我們所知的,活化對(duì)象的屬性)擁有 DontDelete; 任何函數(shù)實(shí)例的 length (返回形參長(zhǎng)度)屬性也擁有 DontDelete:

(function() {
    //不能刪除"arguments",因?yàn)橛蠨ontDelete
    delete arguments; // false;
    typeof arguments; // "object"

    //也不能刪除函數(shù)的length,因?yàn)橛蠨ontDelete
    function f() {};
    delete f.length; // false;
    typeof f.length; // "number"
}) ();

與函數(shù) arguments 相關(guān)聯(lián)的屬性也擁有 DontDelete,同樣不能被刪除

(function(foo,bar) {
    delete foo; // false
    foo; // 1

    delete bar; // false
    bar; // "bah"
}) (1,"bah");
1.6、未聲明的變量賦值 | Undeclared assignments

你可能記得,未聲明的變量賦值會(huì)成為全局對(duì)象的屬性,除非這一屬性在作用域鏈內(nèi)的其他地方被找到。 而現(xiàn)在我們了解了屬性賦值和變量聲明的區(qū)別——后者生成 DontDelete 而前者不生成——這也就是為什么未聲明的變量賦值可以被刪除的原因了。

var GLOBAL_OBJECT = this;

/* 通過變量聲明生成全局對(duì)象的屬性,擁有DontDelete */
var foo = 1;

/* 通過未聲明的變量賦值生成全局對(duì)象的屬性,沒有DontDelete */
bar = 2;

delete foo; // false
delete bar; // true

注意:內(nèi)部屬性是在屬性生成時(shí)確定的,之后的賦值過程不會(huì)改變已有的屬性的內(nèi)部屬性。 理解這一區(qū)別是重要的。

/* "foo"創(chuàng)建的同時(shí)生成DontDelete */
function foo() {};

/* 之后的賦值過程不改變已有屬性的內(nèi)部屬性,DontDelete仍然存在 */
foo = 1;
delete foo; // false;
typeof foo; // "number"

/* 但賦值一個(gè)不存在的屬性時(shí),創(chuàng)建了一個(gè)沒有內(nèi)部屬性的屬性,因此沒有DontDelete */
this.bar = 1;
delete bar; // true;
typeof bar; // "undefined"
二、Firebug 的混亂 | Firebug confusion

那么, firebug 中發(fā)生了什么? 為什么在控制臺(tái)中聲明的變量能夠被刪除,而不是想我們之前討論的那樣? 我之前說過,Eval code 在它處理變量聲明時(shí)有一個(gè)特殊的行為: 在 Eval code 中聲明的變量事實(shí)上生成一個(gè)沒有 DontDelete 的屬性

eval("var foo = 1;");
foo; // 1
delete foo; // true
typeof foo; // "undefined"

在函數(shù)代碼中也是一樣:

(function() {
    eval("var foo = 1;");
    foo; // 1
    delete foo; // true
    typeof foo; // "undefined"
}) ();

而這就是 Firebug 中異常行為的原因了。 所有在控制臺(tái)中的調(diào)試文本似乎是以 Eval code 來編譯和執(zhí)行的,而不是在全局或函數(shù)代碼中執(zhí)行。 顯然,其中的變量聲明最終都生成了不帶 DontDelete 的屬性,所以可以被刪除。 所以要小心普通的全局代碼和 Firebug 控制臺(tái)中代碼的區(qū)別。

2.1、通過eval刪除變量 | Delete variables via eval

這個(gè)有趣的 eval 行為,結(jié)合 ECMAScript 的另一個(gè)方面可以在技術(shù)上允許我們刪除那些原本不能刪除的屬性。 這個(gè)方面是關(guān)于函數(shù)聲明——在相同的執(zhí)行上下文中它們能覆蓋同名的變量:

function x() { };
var x;
typeof x; // “function”

那么為什么函數(shù)聲明擁有優(yōu)先權(quán)而能覆蓋同名變量(或者換句話說,變量對(duì)象(Variable object)的相同屬性)呢? 這是因?yàn)?strong>函數(shù)聲明的實(shí)例化過程在變量聲明之后,因此可以覆蓋它們。

(譯者按:函數(shù)聲明只能覆蓋聲明而未賦值的同名變量,如果在聲明時(shí)賦值了值(e.g. var x = 1)則賦值值的過程在函數(shù)初始化之后,函數(shù)聲明反而被變量賦值所覆蓋,如下:)

var x = 1;
function x() { };
typeof x; // "number"

函數(shù)聲明不止替換了屬性的值,同時(shí)也替換了它的內(nèi)部屬性。 如果我們通過 eval 來聲明函數(shù),這一函數(shù)也將用它自己的內(nèi)部屬性來替換之前的。 而由于在 eval 中聲明的變量生成的屬性沒有 DontDelete, 實(shí)例化這個(gè)函數(shù)將在“理論上”移除原屬性已有的 DontDelete 內(nèi)部屬性, 而使得這一屬性可以刪除(當(dāng)然,同時(shí)也將值指向了新生成的函數(shù))。

var x = 1;
/*不能刪除,‘x’擁有DontDelete*/
delete x; // false
typeof x; // "number"

eval("function x() { }");
/* 屬性"x"現(xiàn)在指向函數(shù),并且應(yīng)該沒有DontDelete */
typeof x; // "function"
delete x; // 應(yīng)該是‘true’;
typeof x; // 應(yīng)該是"undefined"

不幸的是,這種欺騙技術(shù)在我嘗試的各個(gè)瀏覽器中都沒有成功。 這里我可能錯(cuò)過了什么,或者這個(gè)行為太隱蔽而以至于各個(gè)瀏覽器沒有注意到它。

(譯者按:這里的問題可能在于:函數(shù)聲明和變量聲明之間的覆蓋只是值指向的改變, 而內(nèi)部屬性 DontDelete 則在最初聲明處確定而不再改變,而 eval 中聲明的變量和函數(shù),也只是在其外部上下文中未聲明過的那部分才能被刪除。 關(guān)于執(zhí)行順序,由于 eval 作為函數(shù),它的調(diào)用永遠(yuǎn)在其外部上下文中其他變量和函數(shù)聲明之后, 因此相關(guān)的內(nèi)部屬性也已確定,覆蓋的只是值的指向。如下:)

/*  第一個(gè) alert 返回 “undefined”,因?yàn)橘x值過程在聲明過程和eval執(zhí)行過程之后;
    第二個(gè)alert返回 “false”, 因?yàn)楸M管x聲明的位置在eval之后,
    但是eval的執(zhí)行卻在變量聲明之后,因此已無法刪除 */
eval(" alert( x ); alert(delete x) ");
var x = 1;
三、瀏覽器的遵守情況 | Browsers compliance

了解事物的工作原理是重要的,但實(shí)際的實(shí)現(xiàn)情況更重要。 瀏覽器在創(chuàng)建和刪除變量/屬性時(shí)都遵守這些標(biāo)準(zhǔn)嗎? 對(duì)于大部分來說,是的。

我寫了一個(gè)簡(jiǎn)單的測(cè)試單元來檢查全局代碼、函數(shù)代碼和Eval代碼的遵守情況。 測(cè)試單元同時(shí)檢測(cè)了 delete 操作的返回值和屬性是否像預(yù)期那樣被刪除。 delete 的返回值并不像它的實(shí)際結(jié)果那樣重要,delete 操作返回 true 或 false 并不重要, 重要的是擁有/沒有 DontDelete 的屬性是否被刪除。

現(xiàn)代瀏覽器總的來說還是遵守刪除規(guī)則的,以下瀏覽器全部通過測(cè)試: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+。

Safari 2.x 和 3.0.4 在刪除函數(shù) arguments 時(shí)存在問題,似乎這些屬性在創(chuàng)建時(shí)不帶 DontDelete,因此可以被刪除。 Safari 2.x 還有其他問題——?jiǎng)h除無引用時(shí)(例如delete 1)拋出錯(cuò)誤(譯者按:IE 同樣有); 函數(shù)聲明生成了可刪除的屬性(奇怪的是變量聲明則正常); eval 中的變量聲明變成不可刪除(而 eval 中的函數(shù)聲明則正常)。

與 Safari 類似,Konqueror(3.5,而非4.3)在 delete 無引用和刪除 arguments 是也存在同樣問題。

3.1、Gecko DontDelete bug

Gecko 1.8.x 瀏覽器—— Firefox 2.x, Camino 1.x, Seamonkey 1.x, etc. ——存在一個(gè)有趣的 bug:顯式賦值值給一個(gè)屬性能移除它的 DontDelete,即使該屬性通過變量或函數(shù)聲明而生成。

function foo() { };
delete foo; // false;
typeof foo; // "function"

this.foo = 1;
delete foo; // true
typeof foo; // "undefined"

令人驚訝的是,IE5.5-8 也通過了絕大部分測(cè)試,除了刪除非引用拋出錯(cuò)誤(e.g. delete 1,就像舊的 Safari)。 但是,雖然不能馬上發(fā)現(xiàn),事實(shí)上 IE 存在更嚴(yán)重的 bug,這些 bug 是關(guān)于全局對(duì)象。

四、IE bugs

在 IE 中(至少在 IE6-8 中),下面的表達(dá)式拋出異常(在全局代碼中):

this.x = 1;
delete x; // TypeError: Object doesn"t support this action

而下面則是另一個(gè):

var x =1;
delete this.x; // TypeError: Cannot delete "this.x"
// 譯者按:在IE8下拋出此異常,在IE6,7下拋出的是和上面一樣的異常

這似乎說明,在 IE 中在全局代碼中的變量聲明并沒有生成全局對(duì)象的同名屬性。 通過賦值創(chuàng)建的屬性(this.x = 1)然后通過 delete x 刪除時(shí)拋出異常; 通過變量聲明(var x = 1)創(chuàng)建的屬性然后通過 delete this.x 刪除時(shí)拋出另一個(gè)(譯者按:在 IE6,7 下錯(cuò)誤信息與上面的相同)。

但不只是這樣,事實(shí)上通過顯式賦值創(chuàng)建的屬性在刪除時(shí)總是拋出異常。 這不只是一個(gè)錯(cuò)誤,而是創(chuàng)建的屬性看上去擁有了 DontDelete 內(nèi)部屬性,而按規(guī)則應(yīng)該是沒有的:

this.x = 1;
delete this.x; // TypeError: Object doesn"t support this action
delete x; // TypeError: Object doesn"t support this action

另一方面,未聲明的變量賦值(那些同樣生成全局對(duì)象的屬性)又確實(shí)在IE下能夠正常刪除:

x = 1;
delete x; // true

但如果你試圖通過 this 關(guān)鍵字來進(jìn)行刪除(delete this.x),那么上面的異常又將拋出:

x = 1;
delete this.x; //TypeError: Cannot delete "this.x"

如果歸納一下,我們將發(fā)現(xiàn)在全局代碼中‘delete this.x’永遠(yuǎn)不會(huì)成功。 當(dāng)通過顯式賦值來生成屬性(this.x = 1)時(shí)拋出一個(gè)異常; 當(dāng)通過聲明/非聲明變量的方式(var x = 1 or x = 1)生成屬性時(shí)拋出另一個(gè)異常。 而另一方面,delete x 只有在顯示賦值生成屬性(this.x = 1)時(shí)才拋出異常。

在 9 月我討論了這個(gè)問題,其中 Garrett Smith 認(rèn)為在 IE 中全局變量對(duì)象(Global variable object)實(shí)現(xiàn)為一個(gè) JScript 對(duì)象,而全局對(duì)象則由宿主對(duì)象實(shí)現(xiàn)。

我們能通過幾個(gè)測(cè)試來在某種程度上確認(rèn)這一理論。 注意,this 和 window 似乎引用同一個(gè)對(duì)象(如果 ‘===’運(yùn)算符可以信任的話), 而變量對(duì)象 Variable object (函數(shù)聲明的基礎(chǔ))則與 this 引用的不同。

function getBase() { return this; };

getBase() === this.getBase(); // false
this.getBase() === this.getBase(); // true
window.getBase() === this.getBase(); // true
window.getBase() === getBase(); // false
五、誤解 | Misconceptions

我們不能低估理解事物工作原理的重要性。 我看過網(wǎng)絡(luò)上一些關(guān)于 delete 操作的誤解。 例如,Stackoverflow 上的一個(gè)答案(而且等級(jí)還很高),里面解釋說“delete is supposed to be no-op when target isn’t an object property”。 現(xiàn)在我們了解了 delete 操作的核心,也就清楚了這個(gè)答案是不正確的。 delete 不區(qū)分變量和屬性(事實(shí)上在 delete 操作中這些都是引用),而只關(guān)心 DontDelete(以及屬性是否已經(jīng)存在)。

六、"delete"和宿主對(duì)象 | ’delete‘ and host object

一個(gè) delete 的算法大致像這樣:

1. 如果運(yùn)算元(operand)不是引用,返回 true
2. 如果對(duì)象沒有同名的**直接屬性**,返回 true (如我們所知,對(duì)象可以是全局對(duì)象也可以是活化對(duì)象)
3. 如果屬性已經(jīng)存在但有 DontDelete,返回 false
4. 否則,刪除移除屬性并返回 true

然而,對(duì)于宿主對(duì)象(host object)的 delete 操作的行為卻可能是不可預(yù)料的。 而事實(shí)上這并沒有錯(cuò):宿主對(duì)象(通過一定規(guī)則)允許實(shí)現(xiàn)任何操作, 例如讀(內(nèi)部[[Get]]方法)、寫(內(nèi)部[[Write]]方法)、刪除(內(nèi)部[[Delete]]方法),等等。 這種允許自定義[[Delete]]行為導(dǎo)致了宿主對(duì)象的混亂。

我們已經(jīng)看到了在IE中的一些問題:當(dāng)刪除某些對(duì)象(那些實(shí)現(xiàn)為了宿主對(duì)象)屬性時(shí)拋出異常。 一些版本的 firefox 當(dāng)試圖刪除 window.location 時(shí)拋出異常(譯者按:IE 同樣拋出)。 同樣,在一些宿主對(duì)象中你也不能相信 delete 的返回值, 例如下面發(fā)生在 firefox 中的(譯者按:chrome 中同樣結(jié)果;IE 中拋出異常;opera 和 safari 允許刪除,并且刪除后無法調(diào)用,姑且算’正常‘,盡管,從下面的討論來看似乎卻是不正常的,它們事實(shí)上刪除了不能刪除的屬性,而前面的瀏覽器沒有):

/* "alert"是’window‘的一個(gè)直接屬性(如果我們能夠相信"hasOwnProperty") */
window.hasOwnProperty("alert"); // true

delete window.alert; // true
typeof window.alert; // "function"

delete window.alert 返回 true,盡管這個(gè)屬性沒有任何條件可能產(chǎn)生這個(gè)結(jié)果(按照上面的算法): 它解析為一個(gè)引用,因此不能在第一步返回 true; 它是 window 對(duì)象的直接屬性,因此不能在第二步返回 true; 唯一能返回 true 的是當(dāng)算法達(dá)到最后一步同時(shí)確實(shí)刪除這個(gè)屬性,而事實(shí)上它并沒有被刪除。 (譯者按:不,在 opera 和 safari 中確實(shí)被刪除了...)。

所以這個(gè)故事告訴我們永遠(yuǎn)不要相信宿主對(duì)象

七、ES5 嚴(yán)格模式 | ES5 strict mode

那么 ECMAScript 第 5 版中的嚴(yán)格模式將帶來什么? 目前介紹了其中的一些限制。 當(dāng)刪除操作指向一個(gè)變量/函數(shù)參數(shù)/函數(shù)聲明的直接引用時(shí)拋出 SyntaxError。 此外,如果屬性擁有內(nèi)部屬性[[Configurable]] == false,將拋出 TypeError:

(function(foo) {
    "use strict"; //在函數(shù)中開啟嚴(yán)格模式

    var bar;
    function baz;
    delete foo; // SyntaxError,當(dāng)刪除函數(shù)參數(shù)時(shí)
    delete bar; // SyntaxError,當(dāng)刪除變量時(shí)
    delete baz; // SyntaxError,當(dāng)刪除由函數(shù)聲明創(chuàng)建的變量時(shí)

    /* function實(shí)例的length擁有[[Configurable]] : false */
    delete (function() {}).length; // TypeError
}) ();

而且,在嚴(yán)格模式下,刪除未聲明的變量(換句話說,未解析的引用),同樣拋出 SyntaxError; 與它類似的,相同模式下未聲明的賦值也將拋出異常(ReferenceError)

"use strict";
delete i_dont_exist; // SyntaxError

i_dont_exist_either = 1; // ReferenceError

看了之前給出的變量、函數(shù)聲明和參數(shù)的例子,相信現(xiàn)在你也理解了,所有這些限制都是有其意義的。 嚴(yán)格模式采取了更積極的和描述性的措施,而不只是忽略這些問題。

八、總結(jié) | Summary

由于這篇文章已經(jīng)很長(zhǎng)了,因此我就不再討論另一些內(nèi)容(e.g.通過 delete 刪除數(shù)組項(xiàng)及其影響)。 你可以翻閱 MDC/MDN 上的文章或閱讀規(guī)范然后自己測(cè)試。

下面是關(guān)于 Javascript 中 delete 如何工作的一個(gè)簡(jiǎn)單的總結(jié):

變量和函數(shù)聲明都是活化(Activation)全局(Global)對(duì)象的屬性。

屬性擁有內(nèi)部屬性,其中一個(gè)—— DontDelete 負(fù)責(zé)確定一個(gè)屬性是否能夠被刪除。

全局代碼或函數(shù)代碼中的變量、函數(shù)聲明都生成擁有 DontDelete 的屬性。

函數(shù)參數(shù)同樣是活化對(duì)象的屬性,也擁有 DontDelete。

Eval代碼中的變量和函數(shù)聲明都生成沒有 DontDelete 的屬性。

新的未聲明的屬性在生成時(shí)帶空的內(nèi)部屬性,因此也沒有 DontDelete。

宿主對(duì)象允許以任何它們期望的方式來響應(yīng)刪除過程。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77926.html

相關(guān)文章

  • JavaScript中的delete操作符

    摘要:作用操作符用于刪除對(duì)象的某個(gè)屬性。但和內(nèi)存并無關(guān)聯(lián),內(nèi)存管理并不是操作符可以操作的,而且一點(diǎn)關(guān)系也沒有。 文章同步到github 在JavaScript中,delete操作符用的比較少,但是還是比較重要的,我本人面試的時(shí)候就遇到過關(guān)于delete的問題,下面總結(jié)一下delete的具體用法。 作用: delete 操作符用于刪除對(duì)象的某個(gè)屬性。 語(yǔ)法: 直接使用delete操作符 del...

    gaosboy 評(píng)論0 收藏0
  • JS淬煉: Array進(jìn)階

    摘要:的這種實(shí)現(xiàn)方式導(dǎo)致了一些尷尬問題,比如刪除元素元素遍歷。后面的參數(shù)被忽略掉了,表示并沒有要插入的元素。其實(shí),的本質(zhì)是跟蹤中的,并始終保持值是。這時(shí)候,雖然不大可能,可能會(huì)在中間某個(gè)中被用戶重新定義。但是在上進(jìn)行這種操作是很糟糕的。 在Javascript中,array是一個(gè)類數(shù)組的object。顧名思義,它能夠在一個(gè)變量上存儲(chǔ)多個(gè)值。 數(shù)組是值的有序集合。每個(gè)值叫做一個(gè)元素,而每個(gè)元素...

    jimhs 評(píng)論0 收藏0
  • JavaScript面向?qū)ο?em>中的嚴(yán)格模式

    摘要:開啟嚴(yán)格模式設(shè)置對(duì)象是一個(gè)不可擴(kuò)展的對(duì)象為對(duì)象新增屬性張無忌在非嚴(yán)格模式下為不可擴(kuò)展的對(duì)象添加新屬性,結(jié)果是靜默失敗。 概述 嚴(yán)格模式是什么 嚴(yán)格模式是JavaScript中的一種限制性更強(qiáng)的變種方式。嚴(yán)格模式不是一個(gè)子集:它在語(yǔ)義上與正常代碼有著明顯的差異。不支持嚴(yán)格模式的瀏覽器與支持嚴(yán)格模式的瀏覽器行為上也不一樣,所以不要在未經(jīng)嚴(yán)格模式特性測(cè)試情況下使用嚴(yán)格模式。嚴(yán)格模式可以與非嚴(yán)...

    bang590 評(píng)論0 收藏0
  • 談?wù)?em>Javascript中的delete操作符

    摘要:你覺得下列代碼中,哪些操作能成功人肉判斷一下,不要放進(jìn)瀏覽器里執(zhí)行。故對(duì)于解析而言,得到的為上述所有的屬性在下均為。那么又有什么玄機(jī)呢的操作可理解為對(duì)于,調(diào)用其內(nèi)部的方法。幾乎所有的都是不可刪除的。 你覺得下列代碼中,哪些delete操作能成功?人肉判斷一下,不要放進(jìn)瀏覽器里執(zhí)行。 // #1 a = hello world; delete a; // #2 var b = hel...

    antz 評(píng)論0 收藏0
  • JavaScript面向?qū)ο?em>中的嚴(yán)格模式個(gè)人分享

    摘要:嚴(yán)格模式嚴(yán)格模式的概念所謂嚴(yán)格模式就是對(duì)中的一種限制性更強(qiáng)的方式屬于代碼的一種強(qiáng)制規(guī)則來規(guī)范代碼的格式簡(jiǎn)單的說就是必須按照嚴(yán)格模式的規(guī)則書寫代碼否則就會(huì)報(bào)錯(cuò)嚴(yán)格模式修正了一些引擎難以優(yōu)化的錯(cuò)誤同樣的代碼有些時(shí)候嚴(yán)格模式會(huì)比非嚴(yán)格模式下更加快 嚴(yán)格模式 嚴(yán)格模式的概念 所謂嚴(yán)格模式就是對(duì)JavaScript中的一種限制性更強(qiáng)的方式. 屬于代碼的一種強(qiáng)制規(guī)則,來規(guī)范代碼的格式簡(jiǎn)單的說就是...

    lordharrd 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<