简体   繁体   English

删除:有人可以解释这种行为

[英]delete: can someone explain this behavior

Compare this code 1 : 比较这段代码1

  somevar = 5;
  delete window.somevar;
  alert(typeof somevar) //=> undefined, so deleted

to this code: 这段代码:

  var somevar = 5;
  delete window.somevar;
  alert(typeof somevar) //=> number, so NOT deleted

See it in action here 在这里看到它

Now in the first block, somevar is deleted, in the second block it's not. 现在在第一个块中, somevar被删除,在第二个块中则没有。 The only difference is using the var keyword in the second block. 唯一的区别是在第二个块中使用var关键字。 Both blocks run in the global scope. 两个块都在全局范围内运行。

Can this be explained? 这可以解释一下吗?

1 the code can't be tested in a chrome-console or firebug, and not in jsfiddle either. 1代码不能在chrome-console或firebug中测试,也不能在jsfiddle中测试。 In those environments all code is evalled , and in evalled code delete works on anything that is the result of eval (see more about that ). 在这些环境中,所有代码都被evalled ,并且在evalled代码中, delete可以处理eval任何结果(请参阅更多信息 )。 In IE < 9 delete window[anything] is not allowed anyway. 在IE <9中,无论如何都不允许delete window[anything]

What you're seeing is an aspect of the fact that the global object ( window , on browsers) is a conflation of two different things which are distinct everywhere except the global execution context. 您所看到的是这样一个方面:全局对象( window ,浏览器)是两个不同事物的混合,除了全局执行上下文之外,它们在任何地方都是不同的。

In the first block, someVar is a normal property of the window object. 在第一个块中, someVarwindow对象的普通属性。 Properties can be removed via delete . 可以通过delete属性。

In the second block, someVar is a property of the binding object of the variable context of the global execution context — which is also window . 在第二个块中, someVar是全局执行上下文的变量上下文绑定对象的属性 - 也是window You cannot delete properties the binding object receives in its role as the binding object (even though you can delete properties it receives in other ways). 您无法删除绑定对象在其作为绑定对象的角色中接收的属性(即使您可以删除以其他方式接收的属性)。 That is, you cannot delete variables declared with var (and a few other things that are added the same way). 也就是说,你不能删除用var声明的变量(以及其他一些以相同方式添加的东西)。

(Sorry, not my terminology; it comes from the spec , which features some very fun language indeed.) (对不起,不是我的术语;它来自规范 ,确实有一些非常有趣的语言。)

It's only the global execution context where we have this conflation of concepts. 它只是全局执行上下文,我们有这种概念的混合。 The variable binding object for other execution contexts (function calls, for instance) is still a very real thing (and crucial to proper functioning of closures), but there's no programmatic way to directly access it. 其他执行上下文(例如函数调用)的变量绑定对象仍然是一个非常真实的东西(对于闭包的正常运行至关重要),但是没有直接访问它的编程方式。 In the global execution context, though, it's the global object, which of course we can access. 但是,在全局执行上下文中,它是全局对象,当然我们可以访问它。

It helps to understand this if we look at functions first, and then look at the global execution context. 如果我们首先查看函数,然后查看全局执行上下文,这有助于理解这一点。 when you call a function, these things happen: 当你调用一个函数时,会发生以下事情:

  1. Set this to point to the object designated by the call (the value of this is usually implicitly set, but there are ways to set it explicitly). 设置this为指向由调用指定对象的值( this通常是隐式设置,但有办法来设置它明确)。
  2. Create an execution context for this call. 为此调用创建执行上下文
  3. Create a variable context for that execution context. 为该执行上下文创建变量上下文。
  4. Create a binding object for that variable context. 为该变量上下文创建绑定对象
  5. Add the function's name, if it has one, to the binding object as a property referring to the function. 将函数的名称(如果有)添加到绑定对象作为引用该函数的属性。
  6. Add the arguments property to the binding object, referring to the pseudo-array of arguments to the function. arguments属性添加到绑定对象,引用函数参数的伪数组。
  7. Add any named arguments declared in the function definition as properties of the binding object, referring to their entries in the arguments. 添加在函数定义中声明的任何命名参数作为绑定对象的属性,引用它们在参数中的条目。
  8. Add the names of of any variables declared via var statements ( anywhere in the function body) as properties of the binding object, initially with the value undefined . 添加通过var语句声明的任何变量的名称(在函数体中的任何位置 )作为绑定对象的属性,最初使用值undefined
  9. If there are named functions declared within the function, add their names as properties of the binding object, referring to those functions. 如果在函数中声明了命名函数,请将它们的名称添加为绑定对象的属性,并引用这些函数。
  10. Put the binding object at the top of the scope chain (more below). 将绑定对象放在作用域链的顶部(更多下方)。

...and then step-by-step execution of the code in the body of the function begins. ...然后开始逐步执​​行函数体中的代码。 Any var statements with initializers (eg, var a = 5; rather than just var a; are treated as assignment statements ( a = 5; ) when the execution point reaches them. 任何带有初始值设定项的var语句(例如, var a = 5;而不仅仅是var a;当执行点到达时,它们被视为赋值语句( a = 5; )。

Throughout the above, whenever a property is added "to the binding object", it's added with a flag indicating that it cannot be deleted. 综上所述,只要将属性添加到“绑定对象”,就会添加一个表示无法删除的标志。 This is why var s (and the names of declared functions, etc.) can't be deleted. 这就是无法删除var s(以及声明的函数的名称等)的原因。

Any unqualified reference is looked up via the scope chain . 通过范围链查找任何不合格的引用。 So when you refer to a in your code, the first place the interpreter looks is the binding object at the top of the scope chain. 因此,当您在代码中引用a时,解释器所看到的第一个位置是作用域链顶部的绑定对象。 If it has a property called a , that's what gets used; 如果它有一个名为a的属性,那就是使用它; if not, we look at the next link down the scope chain and use that property if we find it; 如果没有,我们会查看范围链中的下一个链接,并在找到它时使用该属性; and so on until we run out of links on the scope chain. 等等,直到我们用完范围链上的链接。 The global object is the bottommost link of that chain (which is why global variables work). 全局对象是该链的最底层链接(这就是全局变量起作用的原因)。

So what's different about the global context? 那么全球背景有什么不同呢? Well, very little, actually. 嗯,实际上很少。 Here's the sequence (roughly): 这是序列(大致):

  1. Create an execution context for this call. 为此调用创建执行上下文
  2. Create a variable context for that execution context. 为该执行上下文创建变量上下文。
  3. Create a binding object for that variable context. 为该变量上下文创建绑定对象
  4. Set this to point to the binding object; 设置this指向绑定对象; that makes it the global object. 这使它成为全球对象。
  5. Set some default properties on that object as defined by the environment (in browsers, for instance, the property window is added to the object, referring to itself). 根据环境的定义在该对象上设置一些默认属性(例如,在浏览器中,属性window被添加到对象中,引用自身)。

...and then we basically pick up with step 8 in the function stuff: ...然后我们基本上接受了函数中的第8步:

  • Add the names of of any variables declared via var statements ( anywhere in the global scope) as properties of the binding/global object, initially with the value undefined . 添加通过var语句声明的任何变量的名称(在全局范围内的任何位置 )作为绑定/全局对象的属性,最初使用值undefined
  • If there are named functions declared within the global scope, add their names as properties of the binding/global object, referring to those functions. 如果在全局范围内声明了命名函数,请将它们的名称添加为绑定/全局对象的属性,并引用这些函数。
  • Put the binding/global object at the top of the scope chain (more below). 将绑定/全局对象放在作用域链的顶部(下面更多)。

...and start step-by-step execution of the code (again with var initializers becoming assignments). ...并开始逐步执​​行代码(再次使用var初始化程序成为赋值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM