<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        刪除JavascriptObject中間的key_基礎知識

        來源:懂視網 責編:小采 時間:2020-11-27 21:29:11
        文檔

        刪除JavascriptObject中間的key_基礎知識

        刪除JavascriptObject中間的key_基礎知識:這個也不會,回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談談delete的用法 幾個禮拜前, 我有了個機會去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在
        推薦度:
        導讀刪除JavascriptObject中間的key_基礎知識:這個也不會,回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談談delete的用法 幾個禮拜前, 我有了個機會去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在

        這個也不會,回家種田去吧你

        代碼如下:
        delete thisIsObject[key]
        or
        delete thisIsObject.key

        順便我們來談談delete的用法

        幾個禮拜前, 我有了個機會去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在亞馬遜上擁有很高的評價(12篇評論, 5顆星), 所以我很好奇地想看看它到底是不是那么值得推薦的一本書, 于是我開始閱讀函數的那章. 我非常欣賞這本書解釋事物的方式, 例子們被以一種非常漂亮, 漸進的方式被組織起來, 看起來即便是初學者也能夠輕松掌握這些知識. 然而, 幾乎是立刻, 我就發現了一個貫穿整個章節的有趣的誤解——刪除功能函數. 另外還有一些其它錯誤(例如函數聲明與函數表達式的區別), 但是我們目前將不去討論它們.

        這本書聲稱:

        "函數被作為像一般變量一樣對待-它可以被復制到不同的變量中, 甚至被刪除". 在這個解釋后面附加了這樣一段示例:

        代碼如下:
        var sum = function(a, b) {return a + b;}
        var add = sum;
        delete sum
        true
        typeof sum;
        "undefined"

        忽略掉一些漏掉的分號, 你能看出這幾句代碼的錯誤在哪么? 顯然, 錯誤在于刪除sum這個變量的操作是不會成功的. delete表達式不應該返回true, 并且 typeof sum也不應該返回"undefined". 這一切都因為在JavaScript中刪除變量是不可能的. 至少, 在這種聲明方式下是不可能的.

        所以, 在這個例子中到底發生了什么? 它是一個錯誤么? 抑或是一個特殊用法? 大概不是這樣的. 這一段代碼事實上是Firebug控制臺中的真實輸出, Stoyan一定是使用了它作為快速測試的工具. 這幾乎就好像是Firebug遵守了其它一些delete的規則一樣. 是Firebug導致了Stoyan誤入歧途! 所以, 這兒到底發生了什么?

        在回答這個問題之前, 我們首先需要理解delete運算符到底在JavaScript中是如何工作的: 到底什么能夠被刪除, 什么不能夠被刪除? 今天, 我將嘗試著詳細解釋這個問題. 我們將看看Firebug的"奇怪"行為并且意識到它其實并不是那么奇怪. 我們將深入了解在聲明變量, 函數, 給屬性賦值和刪除它們的這些場景背后到底隱藏了什么. 我們將看看瀏覽器的兼容性和一些最臭名昭著的bug. 我們還將討論ES5的嚴格模式, 和它如何改變delete操作符的行為.

        我將交換著使用JavaScript和ECMAScript, 它們都意味著ECMAScript(除非明顯地談論Mozilla的JavaScript實現)

        不出所料, 在網絡上, 對delete的解釋是相當稀缺的. MDC article大概是最好理解的資源了, 但是, 不幸的是, 它缺失了這個主題的一些有趣的細節. 奇怪的是, 其中一個被遺忘的東西就是Firebug的奇怪表現的原因. 而MSDN reference在這些方面幾乎是無用處的.

        Theory

        那么, 為什么我們能夠刪除對象的屬性:

        代碼如下:
        var o = { x: 1 };
        delete o.x; // true
        o.x; // undefined

        卻不能刪除這樣聲明的對象:

        代碼如下:
        var x = 1;
        delete x; // false
        x; // 1

        或者函數呢:

        代碼如下:
        function x(){}
        delete x; // false
        typeof x; // "function"

        注意: 當一個屬性無法被刪除時,delete操作符只會返回false

        要理解這個, 我們首先需要掌握這些有關變量實例和屬性特性的概念——這些概念很不幸地, 很少在JavaScript書中被提及. 我將試著在接下來的幾個段落中簡單地復習一下這些概念. 這些概念是很難理解的!如果你不在乎"為什么這些東西會以這種方式工作"的話,盡情跳過這一章節好了.

        代碼的類型:

        在ECMAScript中, 有3種不同類型的可執行代碼: 全局代碼(Global code), 函數代碼(Function code)和 Eval代碼(Eval code). 這些類型從名稱上來說或多或少是有自解釋性的, 這里有一個簡短的概述:

        當一段源代碼被看成程序(Program)時, 它將會在全局環境下被執行, 并且被認為是全局代碼(Global code). 在一個瀏覽器環境中, 腳本元素的內容通常被解釋為程序, 因此被作為全局代碼來執行.

        任何直接在一個函數中執行的代碼顯然被認為是函數代碼(Function code). 在瀏覽器中, 事件屬性的內容(如

        )通常被解釋成函數代碼.

        最后, 被應用到內置函數eval的代碼文本被解釋成Eval代碼(Eval code). 很快我們會發現為什么這種類型是特殊的.

        執行上下文(Execution context):

        當ECMAScript代碼執行時, 它通常會發生在特定的執行上下文中.執行上下文是一個有些抽象的實體概念, 它能幫助理解范圍(Scope)和變量實例(Variable instantiation)是如何工作的. 對三種可執行代碼的每一種, 都有一個執行上下文相對應. 當一個函數被執行的時候, 我們說"程序控制進入了函數代碼的執行上下文"; 當一段全局代碼被執行時, 程序控制進入了全局代碼的執行上下文, 等等.

        正如你所見, 執行上下文可以在邏輯上構成一個堆棧. 首先, 可能有一段全局代碼和其自己的執行上下文, 然后這段代碼可能會調用一個函數, 并帶著它(函數)的執行上下文. 這段函數可以調用另外一個函數, 等等等等. 即使函數是遞歸調用的, 每次調用時被也會進入一個新的執行上下文.

        活動對象(Activation object) / 變量對象(Variable Object):

        每一個執行上下文都有一個跟其所關聯的所謂變量對象(Variable Object). 類似于執行上下文, 變量對象是一個抽象實體, 一種用來描述變量實例的機制. 有趣之處在于, 在源代碼中聲明的變量和函數通常會被當做屬性(properties)增加到這個變量對象上.

        當程序控制進入全局代碼的執行上下文時, 一個全局對象(Global object)被用來作為一個變量對象. 這正是為什么聲明為全局的函數變量會變成全局對象屬性的原因.

        代碼如下:
        /* remember that `this` refers to global object when in global scope */
        var GLOBAL_OBJECT = this;

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

        function bar(){}
        typeof GLOBAL_OBJECT.bar; // "function"
        GLOBAL_OBJECT.bar === bar; // true

        好, 所以全局變量會變成全局對象的屬性, 但是局部變量(那些在函數代碼中定義的變量)會發生什么呢? 其實它們的行為也非常類似: 它們會變成變量對象(Variable object)的屬性. 唯一的不同在于, 當在函數代碼中時, 一個變量對象并不是全局對象, 而是所謂的活動對象(Activation object). 活動對象在會每次進入函數代碼的執行上下文時被創建.

        并不是只有在函數代碼中聲明的變量和函數會變成活動對象的屬性; 這也會在每個函數參數(對應相應的形式參數的名稱)和一個特殊的Arguments對象(以arguments為名稱)上發生. 注意, 活動對象是一個內部描述機制, 在程序代碼中并不能被訪問.

        代碼如下:
        (function(foo){
        var bar = 2;
        function baz(){}
        /*
        In abstract terms,
        Special `arguments` object becomes a property of containing function's Activation object:
        ACTIVATION_OBJECT.arguments; // Arguments object
        ...as well as argument `foo`:
        ACTIVATION_OBJECT.foo; // 1
        ...as well as variable `bar`:
        ACTIVATION_OBJECT.bar; // 2
        ...as well as function declared locally:
        typeof ACTIVATION_OBJECT.baz; // "function"
        */
        })(1);

        最后, 在Eval代碼中聲明的變量會成為調用者上下文(calling context)的變量對象的屬性. Eval代碼只是簡單地使用調用它的代碼的執行上下文的變量對象.

        代碼如下:
        var GLOBAL_OBJECT = this;
        /* `foo` is created as a property of calling context Variable object,
        which in this case is a Global object */
        eval('var foo = 1;');
        GLOBAL_OBJECT.foo; // 1
        (function(){
        /* `bar` is created as a property of calling context Variable object,
        which in this case is an Activation object of containing function */
        eval('var bar = 1;');
        /*
        In abstract terms,
        ACTIVATION_OBJECT.bar; // 1
        */
        })();

        屬性的特性(property attributes)

        我們幾乎是已經在這了. 既然我們已經很清楚在變量上發生了什么(它們變成了屬性), 唯一剩下的需要理解的概念就是屬性的特性(property attributes)了. 每一個屬性可以擁有0個或多個特性, 它們從以下集合中選取: ReadOnly, DontEnum, DontDelete和 Internal. 你可以把它們認為是flags —— 一種特性可以在屬性中存在, 也可以不存在. 對于我們今天的討論來說, 我們只對DontDelete感興趣.

        當被聲明的變量和函數成為變量對象(或者函數代碼的活動對象, 或全局代碼的全局對象)的屬性時, 這些屬性在創建時就帶上了DontDelete的特性. 然而, 任何顯式(或隱式)的屬性賦值所建立的屬性將不會被帶上DontDelete特性. 這就是為什么我們能夠刪除一些屬性, 但刪除不了其它的.

        代碼如下:
        var GLOBAL_OBJECT = this;
        /* `foo` is a property of a Global object.
        It is created via variable declaration and so has DontDelete attribute.
        This is why it can not be deleted. */
        var foo = 1;
        delete foo; // false
        typeof foo; // "number"
        /* `bar` is a property of a Global object.
        It is created via function declaration and so has DontDelete attribute.
        This is why it can not be deleted either. */
        function bar(){}
        delete bar; // false
        typeof bar; // "function"
        /* `baz` is also a property of a Global object.
        However, it is created via property assignment and so has no DontDelete attribute.
        This is why it can be deleted. */
        GLOBAL_OBJECT.baz = 'blah';
        delete GLOBAL_OBJECT.baz; // true
        typeof GLOBAL_OBJECT.baz; // "undefined"

        內置對象和DontDelete

        所以, 這就是有關它(DontDelete)的所有: 屬性的一個特殊特性, 用來控制這個屬性是否能夠被刪除. 注意, 有些內置對象的屬性是指定含有DontDelete的, 所以無法被刪除. 如特殊的arguments變量(或者, 正如我們現在所知道的, 一個活動對象的屬性)擁有DontDelete. 函數實例的length屬性也具有DontDelete屬性.

        代碼如下:
        (function(){
        /* can't delete `arguments`, since it has DontDelete */
        delete arguments; // false
        typeof arguments; // "object"
        /* can't delete function's `length`; it also has DontDelete */
        function f(){}
        delete f.length; // false
        typeof f.length; // "number"
        })();

        函數參數所對應的屬性也是從建立開始就擁有DontDelete特性的, 所以我們也無法刪除它.

        代碼如下:
        (function(foo, bar){
        delete foo; // false
        foo; // 1
        delete bar; // false
        bar; // 'blah'
        })(1, 'blah');

        未聲明的賦值:

        你可能還記著, 未聲明的賦值會在全局對象上建立一個屬性, 除非這個屬性已經在這個作用域鏈中全局對象之前的其它地方被找到. 并且, 現在我們知道屬性賦值和變量聲明的不同之處——后者會設置DontDelete屬性, 但前者不會. 我們必須清楚, 為什么未聲明的賦值會建立一個可刪除的屬性.

        代碼如下:
        var GLOBAL_OBJECT = this;
        /* create global property via variable declaration; property has DontDelete */
        var foo = 1;
        /* create global property via undeclared assignment; property has no DontDelete */
        bar = 2;
        delete foo; // false
        typeof foo; // "number"
        delete bar; // true
        typeof bar; // "undefined"

        請注意: 特性是在屬性被創建時被決定的, 之后的賦值不會修改已存在屬性的特性. 理解這一點區別非常重要.

        代碼如下:
        /* `foo` is created as a property with DontDelete */
        function foo(){}
        /* Later assignments do not modify attributes. DontDelete is still there! */
        foo = 1;
        delete foo; // false
        typeof foo; // "number"
        /* But assigning to a property that doesn't exist,
        creates that property with empty attributes (and so without DontDelete) */
        this.bar = 1;
        delete bar; // true
        typeof bar; // "undefined"

        Firebug的困惑:

        在Firebug中發生了什么? 為什么在console中聲明的變量可以被刪除, 這不是違背了我們之前所學到的知識么? 嗯, 就像我之前所說的那樣, Eval代碼在面對變量聲明時會有特殊的表現. 在Eval中聲明的變量實際上是作為不帶DontDelete特性的屬性被創建的.

        代碼如下:
        eval('var foo = 1;');
        foo; // 1
        delete foo; // true
        typeof foo; // "undefined"

        同樣, 類似的, 當在函數代碼中調用時:

        代碼如下:
        (function(){

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

        })();

        這就是Firebug反常行為的依據. 在console中的所有文本都會被當做Eval代碼來解析和執行, 而不是全局或函數代碼. 顯然, 這里聲明的所有變量最后都會成為不帶DontDelete特性的屬性, 所以它們都能被輕松刪除. 我們需要了解這個在全局代碼和Firebug控制臺之間的差異.

        通過Eval來刪除變量:

        這個有趣的eval行為, 再加上ECMAScript的另一個方面, 可以在技術上允許我們刪除"non-deletable"的屬性. 有關函數聲明的一點是, 它們能夠覆蓋相同執行上下文中同名的變量.

        代碼如下:
        function x(){ }
        var x;
        typeof x; // "function"

        注意函數聲明是如何獲得優先權并且覆蓋同名變量(或者, 換句話說, 在變量對象中的相同屬性)的. 這是因為函數聲明是在變量聲明之后被實例化的, 并且被允許覆蓋它們(變量聲明). 函數聲明不僅會替換掉一個屬性的值, 它還會替換掉那個屬性的特性. 如果我們通過eval來聲明一個函數, 那個函數就應該會用它自己的特性來替換掉原有的(被替換的)屬性的特性. 并且, 由于通過eval聲明的變量會創建不帶DontDelete特性的屬性, 實例化這個新函數將會實際上從屬性中刪除已存在的DontDelete特性, 從而使得一個屬性能夠被刪除(并且, 顯然會將其值指向新創建的函數).

        代碼如下:
        var x = 1;
        /* Can't delete, `x` has DontDelete */
        delete x; // false
        typeof x; // "number"
        eval('function x(){}');
        /* `x` property now references function, and should have no DontDelete */
        typeof x; // "function"
        delete x; // should be `true`
        typeof x; // should be "undefined"

        不幸的是, 這種"欺騙"在目前的任何實現中都不起作用. 也許我在這漏掉了什么, 或者是這種行為只是太晦澀了以至于實現者都沒有注意到它.

        瀏覽器兼容性:

        在理論上了解事物是如何工作的是有用的, 但是實踐卻是最重要的. 當面對變量/屬性的創建/刪除時, 瀏覽器有遵循標準么? 答案是: 在大多數情況下, 是的.

        我寫了一個簡單的測試集來測試瀏覽器對于delete操作符的兼容性, 包括在全局代碼, 函數代碼和Eval代碼下的測試. 測試集檢查了delete操作符的返回值和屬性值是否(像它們應當表現的一樣)真的被刪除了. delete的返回值并不像它的真實結果一樣重要. 如果delete返回true而不是false, 這其實并不重要, 重要的是那些擁有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(3.5, 不是4.3)會在刪除非引用類型時拋出異常(如: delete 1), 并且錯誤地讓函數變量變為可刪除的.

        譯者注:

        我測試了最新版本的chrome和firefox以及IE, 基本還是保留在除23,24會fail其它均pass的情況. 同時測試了UC和一些手機瀏覽器, 除了諾基亞E72的自帶瀏覽器還會Fail 15,16之外, 其余的自帶瀏覽器大都與桌面瀏覽器效果一樣. 但值得一提的是, Blackberry Curve 8310/8900的自帶瀏覽器可以pass測試23, 令我很驚訝.

        Gecko DontDelete bug:

        Gecko 1.8.x 瀏覽器 —— Firefox 2.x, Camino 1.x, Seamonkey 1.x等等. —— 表現出了一個非常有趣的bug, 對屬性的顯式賦值會刪除它的DontDelete特性, 即使這個屬性是通過變量聲明或函數聲明創造的.

        代碼如下:
        function foo(){}
        delete foo; // false (as expected)
        typeof foo; // "function" (as expected)
        /* now assign to a property explicitly */
        this.foo = 1; // erroneously clears DontDelete attribute
        delete foo; // true
        typeof foo; // "undefined"
        /* note that this doesn't happen when assigning property implicitly */
        function bar(){}
        bar = 1;
        delete bar; // false
        typeof bar; // "number" (although assignment replaced property)

        令人吃驚的是, Internet Explorer 5.5 - 8 通過了完整的測試集, 除了刪除非引用類型(如: delete 1)會拋出異常(就像舊的Safari一樣). 但是在IE下有更嚴重的bugs, 它不是那么明顯. 這些bugs跟Global object有關.

        IE bugs:

        這整章都在說Internet Explorer的bugs? 哇! 真是令人吃驚!

        在IE中(至少是IE 6-8), 以下表達式會拋出異常(當在全局代碼中執行時):

        this.x = 1;
        delete x; // TypeError: Object doesn't support this action
        這一個也會, 但是會拋出不同的異常, 這使得事情更有趣了:

        var x = 1;
        delete this.x; // TypeError: Cannot delete 'this.x'
        這看上去好像是在IE中, 全局代碼中的變量聲明沒有在全局對象上創建屬性. 通過賦值來創建屬性(this.x = 1)和之后通過delete x來刪除它會拋出錯誤. 通過聲明來創建屬性(var x = 1)并且在之后通過delete this.x來刪除它會拋出另一個錯誤.

        但這還不是全部. 通過顯式賦值來創建屬性事實上總會引起在刪除時的拋出異常. 這里不止有錯誤, 而且所創建的屬性似乎會擁有DontDelete特性, 而這當然是不應該具有的.

        this.x = 1;

        delete this.x; // TypeError: Object doesn't support this action
        typeof x; // "number" (still exists, wasn't deleted as it should have been!)

        delete x; // TypeError: Object doesn't support this action
        typeof x; // "number" (wasn't deleted again)
        現在, 我們會認為 在IE下, 未聲明的賦值(應當在全局對象上創建屬性)確實會創建可刪除的屬性.

        x = 1;
        delete x; // true
        typeof x; // "undefined"
        但是, 如果你是同通過全局代碼中的this引用來刪除這個屬性的話(delete this.x), 就會彈出一個類似的錯誤.

        x = 1;
        delete this.x; // TypeError: Cannot delete 'this.x'
        如果我們想要歸納一下這種行為的話, 看起來是從全局代碼中使用delete this.x來刪除變量從來不可能成功. 當問題中的屬性通過顯式的賦值(this.x = 1)來創建時,delete拋出了一個錯誤; 當屬性是通過未聲明的賦值(x = 1)或通過聲明(var x = 1)來創建時, delete拋出另外一個錯誤.

        delete x, 另一方面來說, 應當只在屬性是通過顯式賦值來創建時拋出錯誤 ——this.x = 1.如果一個屬性是通過聲明來創建的(var x = 1), 刪除操作從來不會發生, 并且刪除操作會正確地返回false. 如果一個屬性是通過未聲明的賦值來創建的(x = 1), 刪除操作會像期望地一樣工作.

        我這9月份又思考了一下這個問題, Garrett Smith建議說在IE下,

        "全局變量對象(The global variable object)是實現為一個JScript對象的, 并且全局對象是由host來實現的".

        Garrett使用了Eric Lippert's blog entry作為參考.

        我們多多少少可以通過實施一些測試來確認這個理論. 注意到this和window看起來是應當指向同一個對象的(如果我們能夠信任===操作符的話), 但是變量對象(函數聲明所在的那個對象)卻與this所指向的不同.

        代碼如下:
        /* in Global code */
        function getBase(){ return this; }

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

        誤解:

        理解事物為何以那種方式工作的美是不可低估的. 我在網絡上見過一些有關delete操作符的誤解. 例如, 這個Stackoverflow上的答案(擁有令人吃驚的高rating), 自信地解釋道

        "當目標操作數不是一個對象屬性時, delete應當是無操作的".

        現在既然我們已經理解了delete操作行為的核心, 這個答案的錯誤也就變得顯而易見了. delete并不會去區分因為變量和屬性(事實上, 對于delete來說, 它們都是引用類型)并且事實上只關心DontDelete特性(和屬性本身是否存在).

        看到各種誤解互相反駁也是非常有趣的, 在一個相同的話題中一個人首先建議只delete變量(這將不會有效果, 除非它是在eval中聲明的), 而另一個人提供了一個錯誤的糾正說明delete是如何在全局代碼中用于刪除變量, 而在函數代碼中卻不行.

        對于網絡上JavaScript的解釋要格外小心, 理想的方法是總去理解問題的本質. ;)

        delete和宿主對象(Host Object):

        delete的算法大概是這樣的:

        如果操作數不是引用類型, 則返回true
        如果對象沒有這個名字的直接屬性, 返回true(正如我們所知, 對象可以是活動對象或者全局對象)
        如果屬性存在但是有DontDelete特性, 返回false
        其它情況, 刪除屬性并且返回true
        然而, delete操作符在宿主對象上的行為是難以預測的. 并且這種行為實際上并沒有錯: (根據標準), 宿主對象是被允許對于像read(內部[[Get]]方法), write(內部[[Put]]方法)和delete(內部[[Delete]]方法)其中幾個操作符實現任何行為的. 這種對自定義[[Delete]]行為的寬限就是將宿主對象變得如此混亂的原因.

        我們已經見過了一些IE的怪癖, 刪除特定的對象(顯然是指被實現為宿主對象的)會拋出錯誤. Firefox的一些版本在刪除window.location的時候會拋出. 當操作數是宿主對象時, 你不可以信任delete的返回值. 讓我們來看看在Firefox中發生了什么:

        代碼如下:
        /* "alert" is a direct property of `window` (if we were to believe `hasOwnProperty`) */
        window.hasOwnProperty('alert'); // true

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

        刪除window.alert返回true, 即使這個屬性完全沒有任何應該導致這樣的結果的理由. 它將解析為一個引用(所以不會在第一步就返回true). 這是個window對象的直接屬性(所以不會在第二步返回true). 所以delete唯一能夠返回true的情況就是到達第四步并且真正刪除那個屬性. 然而, 這個屬性從未被刪除.

        這個故事的寓意是: 永遠不要相信宿主對象.

        ES5 嚴格模式:

        所以, 嚴格模式的ECMAScript5給我們帶來了什么呢? 它介紹了很少的一些限制. 當delete操作符的表達式是一個變量的直接引用, 函數參數或者函數標示符時, 語法錯誤將會被拋出. 另外, 如果屬性具有內部特性[[Configurable]] == false, 則一個類型錯誤將會被拋出.

        代碼如下:
        (function(foo){
        "use strict"; // enable strict mode within this function
        var bar;
        function baz(){}
        delete foo; // SyntaxError (when deleting argument)
        delete bar; // SyntaxError (when deleting variable)
        delete baz; // SyntaxError (when deleting variable created with function declaration)
        /* `length` of function instances has { [[Configurable]] : false } */
        delete (function(){}).length; // TypeError
        })();

        另外, 刪除未聲明的變量(或者說未解析的引用)將也會拋出語法錯誤:

        "use strict";
        delete i_dont_exist; // SyntaxError
        未聲明的賦值跟嚴格模式下未聲明的變量所表現的行為類似(除了這次是引發引用錯誤而不是語法錯誤):

        "use strict";
        i_dont_exist = 1; // ReferenceError
        正如你現在所明白的, 所有的限制多多少少是有道理的, 因為刪除變量, 函數聲明和 參數會導致這么多混亂. 與其靜默地忽略刪除操作, 嚴格模式采用了一種更加激進和更具描述性的措施.

        總結:

        這篇博文最后變得相當的長, 所以我不準備再去談論類似于用delete刪除數組對象或它的含義是什么等. 你可以參考MDC文章對其專門的解釋(或者閱讀標準和自己做實驗).

        這里有一份對于JavaScript中刪除操作是如何工作的簡短的總結:

        變量和函數聲明是活動對象或者全局對象的屬性
        屬性擁有一些特性, 這其中的DontDelete是決定這個屬性能否被刪除的那個特性.
        在全局或者函數代碼中的變量和函數聲明總是創建帶有DontDelete特性的屬性.
        函數參數總是活動對象的屬性, 并且帶有DontDelete.
        在Eval代碼中聲明的變量和函數總是創建不帶DontDelete的屬性.
        新的屬性在建立時是沒有特性的(當然也沒有DontDelete).
        宿主對象被允許自己決定如何對delete操作做出反應.
        如果你想要對這里所描述的東西更加熟悉的話, 請參閱 ECMA-262 3rd edition specification.

        我希望你能夠享受這篇文章, 并且學到一些新的東西. 歡迎提出任何問題, 建議或者糾正.

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        刪除JavascriptObject中間的key_基礎知識

        刪除JavascriptObject中間的key_基礎知識:這個也不會,回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談談delete的用法 幾個禮拜前, 我有了個機會去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在
        推薦度:
        標簽: 刪除 移除 中間的
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: a在线视频免费观看在线视频三区| 亚洲欧美日韩久久精品| 国产无遮挡色视频免费观看性色| 国产成人免费手机在线观看视频| 亚洲精品动漫免费二区| 曰曰鲁夜夜免费播放视频| 亚洲一区在线视频| 久久久久国产精品免费免费搜索| 成人免费毛片内射美女APP| 亚洲国产成人精品青青草原| 免费a级毛片无码a∨蜜芽试看| 亚洲伊人精品综合在合线| 无码人妻一区二区三区免费| jlzzjlzz亚洲乱熟在线播放| 九九全国免费视频| 亚洲va久久久噜噜噜久久 | 日韩久久无码免费毛片软件| www.亚洲色图| 99在线热播精品免费99热| 亚洲AV无码不卡无码| 动漫黄网站免费永久在线观看| 亚洲欧洲无码一区二区三区| 亚洲国产综合久久天堂| 男女午夜24式免费视频| 亚洲人成综合在线播放| 国产成人精品高清免费| 国产一级婬片A视频免费观看| 亚洲美女视频网站| 国产成人免费a在线视频app| 天堂在线免费观看| 亚洲国产高清视频在线观看| 狼友av永久网站免费观看| 亚洲avav天堂av在线网毛片| 中文亚洲AV片在线观看不卡| 9420免费高清在线视频| 亚洲AV无码成人精品区日韩| 国产精品亚洲成在人线| 在线a人片天堂免费观看高清| 国产成人精品免费大全| 亚洲人成免费网站| 亚洲人成人无码网www电影首页 |