删除Javascript Object中间的key
这个也不会,回家种田去吧你
deletethisIsObject[key] or deletethisIsObject.key
顺便我们来谈谈delete的用法
几个礼拜前,我有了个机会去翻阅StoyanStefanov的Object-OrientedJavascript一书.这本书在亚马逊上拥有很高的评价(12篇评论,5颗星),所以我很好奇地想看看它到底是不是那么值得推荐的一本书,于是我开始阅读函数的那章.我非常欣赏这本书解释事物的方式,例子们被以一种非常漂亮,渐进的方式被组织起来,看起来即便是初学者也能够轻松掌握这些知识.然而,几乎是立刻,我就发现了一个贯穿整个章节的有趣的误解——删除功能函数.另外还有一些其它错误(例如函数声明与函数表达式的区别),但是我们目前将不去讨论它们.
这本书声称:
"函数被作为像一般变量一样对待-它可以被复制到不同的变量中,甚至被删除".在这个解释后面附加了这样一段示例:
varsum=function(a,b){returna+b;} varadd=sum; deletesum true typeofsum; "undefined"
忽略掉一些漏掉的分号,你能看出这几句代码的错误在哪么?显然,错误在于删除sum这个变量的操作是不会成功的.delete表达式不应该返回true,并且typeofsum也不应该返回"undefined".这一切都因为在JavaScript中删除变量是不可能的.至少,在这种声明方式下是不可能的.
所以,在这个例子中到底发生了什么?它是一个错误么?抑或是一个特殊用法?大概不是这样的.这一段代码事实上是Firebug控制台中的真实输出,Stoyan一定是使用了它作为快速测试的工具.这几乎就好像是Firebug遵守了其它一些delete的规则一样.是Firebug导致了Stoyan误入歧途!所以,这儿到底发生了什么?
在回答这个问题之前,我们首先需要理解delete运算符到底在JavaScript中是如何工作的:到底什么能够被删除,什么不能够被删除?今天,我将尝试着详细解释这个问题.我们将看看Firebug的"奇怪"行为并且意识到它其实并不是那么奇怪.我们将深入了解在声明变量,函数,给属性赋值和删除它们的这些场景背后到底隐藏了什么.我们将看看浏览器的兼容性和一些最臭名昭著的bug.我们还将讨论ES5的严格模式,和它如何改变delete操作符的行为.
我将交换着使用JavaScript和ECMAScript,它们都意味着ECMAScript(除非明显地谈论Mozilla的JavaScript实现)
不出所料,在网络上,对delete的解释是相当稀缺的.MDCarticle大概是最好理解的资源了,但是,不幸的是,它缺失了这个主题的一些有趣的细节.奇怪的是,其中一个被遗忘的东西就是Firebug的奇怪表现的原因.而MSDNreference在这些方面几乎是无用处的.
Theory
那么,为什么我们能够删除对象的属性:
varo={x:1}; deleteo.x;//true o.x;//undefined
却不能删除这样声明的对象:
varx=1; deletex;//false x;//1
或者函数呢:
functionx(){} deletex;//false typeofx;//"function"
注意:当一个属性无法被删除时,delete操作符只会返回false
要理解这个,我们首先需要掌握这些有关变量实例和属性特性的概念——这些概念很不幸地,很少在JavaScript书中被提及.我将试着在接下来的几个段落中简单地复习一下这些概念.这些概念是很难理解的!如果你不在乎"为什么这些东西会以这种方式工作"的话,尽情跳过这一章节好了.
代码的类型:
在ECMAScript中,有3种不同类型的可执行代码:全局代码(Globalcode),函数代码(Functioncode)和Eval代码(Evalcode).这些类型从名称上来说或多或少是有自解释性的,这里有一个简短的概述:
当一段源代码被看成程序(Program)时,它将会在全局环境下被执行,并且被认为是全局代码(Globalcode).在一个浏览器环境中,脚本元素的内容通常被解释为程序,因此被作为全局代码来执行.
任何直接在一个函数中执行的代码显然被认为是函数代码(Functioncode).在浏览器中,事件属性的内容(如<ponclick="....">)通常被解释成函数代码.
最后,被应用到内置函数eval的代码文本被解释成Eval代码(Evalcode).很快我们会发现为什么这种类型是特殊的.
执行上下文(Executioncontext):
当ECMAScript代码执行时,它通常会发生在特定的执行上下文中.执行上下文是一个有些抽象的实体概念,它能帮助理解范围(Scope)和变量实例(Variableinstantiation)是如何工作的.对三种可执行代码的每一种,都有一个执行上下文相对应.当一个函数被执行的时候,我们说"程序控制进入了函数代码的执行上下文";当一段全局代码被执行时,程序控制进入了全局代码的执行上下文,等等.
正如你所见,执行上下文可以在逻辑上构成一个堆栈.首先,可能有一段全局代码和其自己的执行上下文,然后这段代码可能会调用一个函数,并带着它(函数)的执行上下文.这段函数可以调用另外一个函数,等等等等.即使函数是递归调用的,每次调用时被也会进入一个新的执行上下文.
活动对象(Activationobject)/变量对象(VariableObject):
每一个执行上下文都有一个跟其所关联的所谓变量对象(VariableObject).类似于执行上下文,变量对象是一个抽象实体,一种用来描述变量实例的机制.有趣之处在于,在源代码中声明的变量和函数通常会被当做属性(properties)增加到这个变量对象上.
当程序控制进入全局代码的执行上下文时,一个全局对象(Globalobject)被用来作为一个变量对象.这正是为什么声明为全局的函数变量会变成全局对象属性的原因.
/*rememberthat`this`referstoglobalobjectwheninglobalscope*/ varGLOBAL_OBJECT=this;
varfoo=1; GLOBAL_OBJECT.foo;//1 foo===GLOBAL_OBJECT.foo;//true
functionbar(){} typeofGLOBAL_OBJECT.bar;//"function" GLOBAL_OBJECT.bar===bar;//true