• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題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關(guān)鍵字專題關(guān)鍵字專題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
    當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

    刪除JavascriptObject中間的key_基礎(chǔ)知識(shí)

    來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 21:29:11
    文檔

    刪除JavascriptObject中間的key_基礎(chǔ)知識(shí)

    刪除JavascriptObject中間的key_基礎(chǔ)知識(shí):這個(gè)也不會(huì),回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談?wù)刣elete的用法 幾個(gè)禮拜前, 我有了個(gè)機(jī)會(huì)去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在
    推薦度:
    導(dǎo)讀刪除JavascriptObject中間的key_基礎(chǔ)知識(shí):這個(gè)也不會(huì),回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談?wù)刣elete的用法 幾個(gè)禮拜前, 我有了個(gè)機(jī)會(huì)去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在

    這個(gè)也不會(huì),回家種田去吧你

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

    順便我們來談?wù)刣elete的用法

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

    這本書聲稱:

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

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

    忽略掉一些漏掉的分號(hào), 你能看出這幾句代碼的錯(cuò)誤在哪么? 顯然, 錯(cuò)誤在于刪除sum這個(gè)變量的操作是不會(huì)成功的. delete表達(dá)式不應(yīng)該返回true, 并且 typeof sum也不應(yīng)該返回"undefined". 這一切都因?yàn)樵贘avaScript中刪除變量是不可能的. 至少, 在這種聲明方式下是不可能的.

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

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

    我將交換著使用JavaScript和ECMAScript, 它們都意味著ECMAScript(除非明顯地談?wù)揗ozilla的JavaScript實(shí)現(xiàn))

    不出所料, 在網(wǎng)絡(luò)上, 對(duì)delete的解釋是相當(dāng)稀缺的. MDC article大概是最好理解的資源了, 但是, 不幸的是, 它缺失了這個(gè)主題的一些有趣的細(xì)節(jié). 奇怪的是, 其中一個(gè)被遺忘的東西就是Firebug的奇怪表現(xiàn)的原因. 而MSDN reference在這些方面幾乎是無用處的.

    Theory

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

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

    卻不能刪除這樣聲明的對(duì)象:

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

    或者函數(shù)呢:

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

    注意: 當(dāng)一個(gè)屬性無法被刪除時(shí),delete操作符只會(huì)返回false

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

    代碼的類型:

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

    當(dāng)一段源代碼被看成程序(Program)時(shí), 它將會(huì)在全局環(huán)境下被執(zhí)行, 并且被認(rèn)為是全局代碼(Global code). 在一個(gè)瀏覽器環(huán)境中, 腳本元素的內(nèi)容通常被解釋為程序, 因此被作為全局代碼來執(zhí)行.

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

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

    最后, 被應(yīng)用到內(nèi)置函數(shù)eval的代碼文本被解釋成Eval代碼(Eval code). 很快我們會(huì)發(fā)現(xiàn)為什么這種類型是特殊的.

    執(zhí)行上下文(Execution context):

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

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

    活動(dòng)對(duì)象(Activation object) / 變量對(duì)象(Variable Object):

    每一個(gè)執(zhí)行上下文都有一個(gè)跟其所關(guān)聯(lián)的所謂變量對(duì)象(Variable Object). 類似于執(zhí)行上下文, 變量對(duì)象是一個(gè)抽象實(shí)體, 一種用來描述變量實(shí)例的機(jī)制. 有趣之處在于, 在源代碼中聲明的變量和函數(shù)通常會(huì)被當(dāng)做屬性(properties)增加到這個(gè)變量對(duì)象上.

    當(dāng)程序控制進(jìn)入全局代碼的執(zhí)行上下文時(shí), 一個(gè)全局對(duì)象(Global object)被用來作為一個(gè)變量對(duì)象. 這正是為什么聲明為全局的函數(shù)變量會(huì)變成全局對(duì)象屬性的原因.

    代碼如下:
    /* 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

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

    并不是只有在函數(shù)代碼中聲明的變量和函數(shù)會(huì)變成活動(dòng)對(duì)象的屬性; 這也會(huì)在每個(gè)函數(shù)參數(shù)(對(duì)應(yīng)相應(yīng)的形式參數(shù)的名稱)和一個(gè)特殊的Arguments對(duì)象(以arguments為名稱)上發(fā)生. 注意, 活動(dòng)對(duì)象是一個(gè)內(nèi)部描述機(jī)制, 在程序代碼中并不能被訪問.

    代碼如下:
    (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代碼中聲明的變量會(huì)成為調(diào)用者上下文(calling context)的變量對(duì)象的屬性. Eval代碼只是簡單地使用調(diào)用它的代碼的執(zhí)行上下文的變量對(duì)象.

    代碼如下:
    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)

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

    當(dāng)被聲明的變量和函數(shù)成為變量對(duì)象(或者函數(shù)代碼的活動(dòng)對(duì)象, 或全局代碼的全局對(duì)象)的屬性時(shí), 這些屬性在創(chuàng)建時(shí)就帶上了DontDelete的特性. 然而, 任何顯式(或隱式)的屬性賦值所建立的屬性將不會(huì)被帶上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"

    內(nèi)置對(duì)象和DontDelete

    所以, 這就是有關(guān)它(DontDelete)的所有: 屬性的一個(gè)特殊特性, 用來控制這個(gè)屬性是否能夠被刪除. 注意, 有些內(nèi)置對(duì)象的屬性是指定含有DontDelete的, 所以無法被刪除. 如特殊的arguments變量(或者, 正如我們現(xiàn)在所知道的, 一個(gè)活動(dòng)對(duì)象的屬性)擁有DontDelete. 函數(shù)實(shí)例的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"
    })();

    函數(shù)參數(shù)所對(duì)應(yīng)的屬性也是從建立開始就擁有DontDelete特性的, 所以我們也無法刪除它.

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

    未聲明的賦值:

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

    代碼如下:
    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"

    請(qǐng)注意: 特性是在屬性被創(chuàng)建時(shí)被決定的, 之后的賦值不會(huì)修改已存在屬性的特性. 理解這一點(diǎn)區(qū)別非常重要.

    代碼如下:
    /* `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中發(fā)生了什么? 為什么在console中聲明的變量可以被刪除, 這不是違背了我們之前所學(xué)到的知識(shí)么? 嗯, 就像我之前所說的那樣, Eval代碼在面對(duì)變量聲明時(shí)會(huì)有特殊的表現(xiàn). 在Eval中聲明的變量實(shí)際上是作為不帶DontDelete特性的屬性被創(chuàng)建的.

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

    同樣, 類似的, 當(dāng)在函數(shù)代碼中調(diào)用時(shí):

    代碼如下:
    (function(){

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

    })();

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

    通過Eval來刪除變量:

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

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

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

    代碼如下:
    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"

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

    瀏覽器兼容性:

    在理論上了解事物是如何工作的是有用的, 但是實(shí)踐卻是最重要的. 當(dāng)面對(duì)變量/屬性的創(chuàng)建/刪除時(shí), 瀏覽器有遵循標(biāo)準(zhǔn)么? 答案是: 在大多數(shù)情況下, 是的.

    我寫了一個(gè)簡單的測試集來測試瀏覽器對(duì)于delete操作符的兼容性, 包括在全局代碼, 函數(shù)代碼和Eval代碼下的測試. 測試集檢查了delete操作符的返回值和屬性值是否(像它們應(yīng)當(dāng)表現(xiàn)的一樣)真的被刪除了. delete的返回值并不像它的真實(shí)結(jié)果一樣重要. 如果delete返回true而不是false, 這其實(shí)并不重要, 重要的是那些擁有DontDelete特性的屬性沒有被刪除,反之亦然.

    現(xiàn)代瀏覽器大致上來說是相當(dāng)兼容的. 除去了我之前提到的eval特點(diǎn), 如下的瀏覽器通過了全部的測試集: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+.

    Safari 2.x 和 3.0.4在刪除函數(shù)參數(shù)時(shí)有問題; 這些屬性看起來是不帶DontDelete被創(chuàng)建的, 所以可以刪除它們. Safari 2.x有更多的問題——?jiǎng)h除非引用類型變量(如: delete 1)會(huì)拋出異常; 函數(shù)聲明會(huì)創(chuàng)建可刪除的屬性(但是, 奇怪的是, 變量聲明卻不會(huì)); eval中的變量聲明會(huì)變成不可刪除的(但是函數(shù)聲明是可刪除的).

    跟Safari類似, Konqueror(3.5, 不是4.3)會(huì)在刪除非引用類型時(shí)拋出異常(如: delete 1), 并且錯(cuò)誤地讓函數(shù)變量變?yōu)榭蓜h除的.

    譯者注:

    我測試了最新版本的chrome和firefox以及IE, 基本還是保留在除23,24會(huì)fail其它均pass的情況. 同時(shí)測試了UC和一些手機(jī)瀏覽器, 除了諾基亞E72的自帶瀏覽器還會(huì)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等等. —— 表現(xiàn)出了一個(gè)非常有趣的bug, 對(duì)屬性的顯式賦值會(huì)刪除它的DontDelete特性, 即使這個(gè)屬性是通過變量聲明或函數(shù)聲明創(chuàng)造的.

    代碼如下:
    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)會(huì)拋出異常(就像舊的Safari一樣). 但是在IE下有更嚴(yán)重的bugs, 它不是那么明顯. 這些bugs跟Global object有關(guān).

    IE bugs:

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

    在IE中(至少是IE 6-8), 以下表達(dá)式會(huì)拋出異常(當(dāng)在全局代碼中執(zhí)行時(shí)):

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

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

    但這還不是全部. 通過顯式賦值來創(chuàng)建屬性事實(shí)上總會(huì)引起在刪除時(shí)的拋出異常. 這里不止有錯(cuò)誤, 而且所創(chuàng)建的屬性似乎會(huì)擁有DontDelete特性, 而這當(dāng)然是不應(yīng)該具有的.

    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)
    現(xiàn)在, 我們會(huì)認(rèn)為 在IE下, 未聲明的賦值(應(yīng)當(dāng)在全局對(duì)象上創(chuàng)建屬性)確實(shí)會(huì)創(chuàng)建可刪除的屬性.

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

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

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

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

    "全局變量對(duì)象(The global variable object)是實(shí)現(xiàn)為一個(gè)JScript對(duì)象的, 并且全局對(duì)象是由host來實(shí)現(xiàn)的".

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

    我們多多少少可以通過實(shí)施一些測試來確認(rèn)這個(gè)理論. 注意到this和window看起來是應(yīng)當(dāng)指向同一個(gè)對(duì)象的(如果我們能夠信任===操作符的話), 但是變量對(duì)象(函數(shù)聲明所在的那個(gè)對(duì)象)卻與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

    誤解:

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

    "當(dāng)目標(biāo)操作數(shù)不是一個(gè)對(duì)象屬性時(shí), delete應(yīng)當(dāng)是無操作的".

    現(xiàn)在既然我們已經(jīng)理解了delete操作行為的核心, 這個(gè)答案的錯(cuò)誤也就變得顯而易見了. delete并不會(huì)去區(qū)分因?yàn)樽兞亢蛯傩?事實(shí)上, 對(duì)于delete來說, 它們都是引用類型)并且事實(shí)上只關(guān)心DontDelete特性(和屬性本身是否存在).

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

    對(duì)于網(wǎng)絡(luò)上JavaScript的解釋要格外小心, 理想的方法是總?cè)ダ斫鈫栴}的本質(zhì). ;)

    delete和宿主對(duì)象(Host Object):

    delete的算法大概是這樣的:

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

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

    代碼如下:
    /* "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, 即使這個(gè)屬性完全沒有任何應(yīng)該導(dǎo)致這樣的結(jié)果的理由. 它將解析為一個(gè)引用(所以不會(huì)在第一步就返回true). 這是個(gè)window對(duì)象的直接屬性(所以不會(huì)在第二步返回true). 所以delete唯一能夠返回true的情況就是到達(dá)第四步并且真正刪除那個(gè)屬性. 然而, 這個(gè)屬性從未被刪除.

    這個(gè)故事的寓意是: 永遠(yuǎn)不要相信宿主對(duì)象.

    ES5 嚴(yán)格模式:

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

    代碼如下:
    (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
    })();

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

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

    "use strict";
    i_dont_exist = 1; // ReferenceError
    正如你現(xiàn)在所明白的, 所有的限制多多少少是有道理的, 因?yàn)閯h除變量, 函數(shù)聲明和 參數(shù)會(huì)導(dǎo)致這么多混亂. 與其靜默地忽略刪除操作, 嚴(yán)格模式采用了一種更加激進(jìn)和更具描述性的措施.

    總結(jié):

    這篇博文最后變得相當(dāng)?shù)拈L, 所以我不準(zhǔn)備再去談?wù)擃愃朴谟胐elete刪除數(shù)組對(duì)象或它的含義是什么等. 你可以參考MDC文章對(duì)其專門的解釋(或者閱讀標(biāo)準(zhǔn)和自己做實(shí)驗(yàn)).

    這里有一份對(duì)于JavaScript中刪除操作是如何工作的簡短的總結(jié):

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

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

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    刪除JavascriptObject中間的key_基礎(chǔ)知識(shí)

    刪除JavascriptObject中間的key_基礎(chǔ)知識(shí):這個(gè)也不會(huì),回家種田去吧你 代碼如下: delete thisIsObject[key] or delete thisIsObject.key 順便我們來談?wù)刣elete的用法 幾個(gè)禮拜前, 我有了個(gè)機(jī)會(huì)去翻閱Stoyan Stefanov的 Object-Oriented Javascript 一書. 這本書在
    推薦度:
    標(biāo)簽: 刪除 移除 中間的
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 久久青青草原精品影院| 免费精品99久久国产综合精品| 国产亚洲精品无码成人| 精品乱码久久久久久夜夜嗨| 成人国内精品久久久久影院 | 亚洲国产精品无码久久久蜜芽| 国产精品igao视频| 国产高清在线精品一区| 久久精品人人槡人妻人人玩AV| 欧美精品丝袜久久久中文字幕| 四虎精品免费永久在线| 99re久久精品国产首页2020| 久久精品国产网红主播| 亚洲精品成人片在线播放| 四虎成人精品国产永久免费无码| 国产精品99久久精品爆乳| 午夜影视日本亚洲欧洲精品一区| 91精品国产福利在线导航| 久久久久99精品成人片直播| 亚洲精品色午夜无码专区日韩| 四虎国产精品永久在线看| 亚洲A∨午夜成人片精品网站| 久久国产精品成人免费| www.久久精品| 91精品国产综合久久久久久| 精品久久久久久无码专区 | 正在播放酒店精品少妇约| 免费精品国产自产拍在线观看| 国产日韩久久久精品影院首页 | 亚洲av无码精品网站| 野狼精品社区| 亚洲精品无码久久不卡| 亚洲精品WWW久久久久久| 亚洲欧美精品丝袜一区二区| 亚洲精品国产va在线观看蜜芽| 四虎精品影库4HUTV四虎| 欧美成人精品高清视频在线观看| 精品一区二区三区四区在线| 惠民福利中文字幕人妻无码乱精品| 国产精品亚洲二区在线观看| 国产免费久久精品99久久|