简体   繁体   English

为什么!{} [true]在JavaScript中评估为true?

[英]Why does !{}[true] evaluate to true in JavaScript?

{}[true] is [true] and ![true] should be false . {}[true][true]并且![true]应该是false

So why does !{}[true] evaluate to true ? 那么为什么!{}[true]评估为true

I believe that's because plain {}[true] is parsed as an empty statement block (not an object literal) followed by an array containing true , which is true . 我相信这是因为plain {}[true]被解析为一个空语句块(不是对象文字),后跟一个包含true的数组,这是true

On the other hand, applying the ! 另一方面,申请! operator makes the parser interpret {} as an object literal, so the following {}[true] becomes a member access that returns undefined , and !{}[true] is indeed true (as !undefined is true ). 运算符使解析器将{}解释为对象文字,因此以下{}[true]成为返回undefined的成员访问,而!{}[true]确实为true (因为!undefinedtrue )。

Because {}[true] does not return true , but undefined , and undefined is evaluated as false : 因为{}[true]不返回true ,但undefined ,并且undefined被评估为false

http://jsfiddle.net/67GEu/ http://jsfiddle.net/67GEu/

'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true

Because 因为

{}[true]

evaluates to undefined , and !undefined is true . 计算结果为undefined ,并且!undefinedtrue

From @schlingel: 来自@schlingel:

true is used as key and {} as hash map. true用作键, {}用作哈希映射。 There doesn't exist an property with the key true so it returns undefined . 不存在键为true的属性,因此返回undefined Not undefined is true , as expected. 正如预期的那样, undefined是不true

Console session ( Node.js [0.10.17] ): 控制台会话( Node.js [0.10.17] ):

> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>

However, in the Google Chrome console: 但是,在Google Chrome控制台中:

> !{}[true]
true

So, no inconsistencies. 所以,没有不一致。 You're probably using an old version of the JavaScript VM. 您可能正在使用旧版本的JavaScript VM。 For those who need further evidence: 对于那些需要进一步证据的人:

在此输入图像描述

UPDATE UPDATE

With Firefox , it also evaluates to true : 使用Firefox ,它还评估为true

在此输入图像描述

The reason for the confusion is down to a misunderstanding of your first assertion: 造成混淆的原因可归结为对您的第一个断言的误解:

{}[true] is [true] {}[true][true]

What you're seeing when you run it is the result of an ambiguity. 你运行它时所看到的是模棱两可的结果。 Javascript has a defined set of rules as to how to handle ambiguities like this, and in this case, it breaks what you see as a signle statement down into two separate statements. Javascript有一套定义的规则来处理如何处理这样的歧义,在这种情况下,它会将你看到的signle语句分解为两个单独的语句。

So Javascript sees the above code as two separate statements: Firstly, there is a {} , and then there is an entirely separate [true] . 所以Javascript将上面的代码视为两个独立的语句:首先,有一个{} ,然后有一个完全独立的[true] The second statement is what is giving you the result [true] . 第二个陈述是什么给你结果[true] The first statement {} is effetively entirely ignored. 第一个陈述{}被有效地完全忽略了。

You can prove this by trying the following: 您可以通过尝试以下方法来证明这一点:

({}[true])

ie wrapping the whole thing in brackets to force the interpreter to read it as a single statement. 即将整个事物包装在括号中以强制解释器将其作为单个语句读取。

Now you'll see that the actual value of your statement is undefined . 现在您将看到语句的实际值undefined (this will also help us later to understand the next part) (这也有助于我们以后了解下一部分)

Now we know that the initial part of your question is a red herring, so let's move onto the final part of the question: 现在我们知道问题的最初部分是红鲱鱼,所以让我们转到问题的最后部分:

So why does !{}[true] evaluate to true? 那么为什么!{} [true]评估为真?

Here, we have the same statement, but with a ! 在这里,我们有相同的声明,但有一个! appended to the front of it. 附在前面。

In this case, Javascript's rules tell it to evaluates the entire thing as a single statement. 在这种情况下,Javascript的规则告诉它将整个事物评估为单个语句。

Refer back to what happened when we wrapped the earlier statement in brackets; 请回顾一下当我们用括号括起前面的陈述时发生的事情; we got undefined . 我们得到了undefined This time, we are effectively doing the same thing, but putting a ! 这一次,我们有效地做同样的事情,但放一个! in front of it. 在它面前。 So your code can be simplified as !undefined , which is true . 所以你的代码可以简化为!undefined ,这是true

Hopefully that explains it a bit. 希望这能解释一下。

It is a complex beast, but the lesson to learn here is to use brackets around your statements when evaluating them in the console, to avoid spurious results like this. 这是一个复杂的野兽,但这里要学到的教训是在控制台中评估它们时使用括号括起来,以避免这样的虚假结果。

{}[true] is undefined . {}[true] undefined To find that write this: 要找到这样写:

a = {};
a[true] === undefined // true

or simply: 或者干脆:

({})[true] === undefined // true

We know that !undefined is true . 我们知道!undefinedtrue


From @Benjamin Gruenbaum's answer : 来自@Benjamin Gruenbaum的回答

Chrome dveloper tools does the following : Chrome dveloper工具执行以下操作

  try {
      if (injectCommandLineAPI && inspectedWindow.console) {
          inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
          expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
      }
      var result = evalFunction.call(object, expression);
      if (objectGroup === "console")
          this._lastResult = result;
      return result;
  } 
  finally {
      if (injectCommandLineAPI && inspectedWindow.console)
          delete inspectedWindow.console._commandLineAPI;
  }

So basically, it performs a call on the object with the expression. 所以基本上,它使用表达式对对象执行call The expression being: 表达式为:

with ((window && window.console && window.console._commandLineAPI) || {}) {
    {}+{};// <-- This is your code
}

So, as you can see, the expression is being evaluted directly, without the wrapping parenthesis. 因此,正如您所看到的,表达式是直接评估的,没有包装括号。

More information can be found in this question . 可以在此问题中找到更多信息。

The answers here are good, here's a breakdown in pseudo-code: 这里的答案很好,这里是伪代码的细分:

  • {}['whatever'] = empty block, NewArray('whatever') = NewArray('whatever') {}['whatever'] =空块,NewArray('whatever')= NewArray('what')
  • {}[true] = empty block, NewArray(true) = NewArray(true) {}[true] =空块,NewArray(true)= NewArray(true)
  • !{}['whatever'] = LogicalNOT(convertToBool(NewObject.whatever)) = LogicalNOT(convertToBool(undefined)) = LogicalNOT(false) = true !{}['whatever'] = LogicalNOT(convertToBool(NewObject.whatever))= LogicalNOT(convertToBool(undefined))= LogicalNOT(false)= true
  • ({}['whatever']) = Grouping(NewObject.whatever) = Grouping(undefined) = undefined ({}['whatever']) =分组(NewObject.whatever)=分组(未定义)=未定义

This happens because {} in your meaning is not literal presentation of Object , but empty scope ( or empty code block ): 发生这种情况是因为你的意思中的{}不是Object文字表示,而是空范围(或空代码块):

{ var a = 1 }[true] // [true] (do the same thing)

It just evaluates code inside scope and then shows you your array. 它只是评估范围内的代码,然后显示您的数组。

And from your 从你的

!{}[true]

Just converts to int this scope and return same array true. 只需将此范围转换为int并返回相同的数组即可。 There is no bool checks in this code. 此代码中没有bool检查。

And if you will try to check result from {}[true] you will get your false : 如果你试图检查{}[true]结果,你会得到你的false

{}[true] -> [true] -> ![true] -> false

As there is no more any scope. 因为没有任何范围。

So ! 所以! in your question do the same as: 在你的问题中做同样的事情:

!function() {
   //...
}
  • {} is an object with no properties. {}是一个没有属性的对象。
  • Since [] immediately follows an object, it means "Access a property of this name" and not "Create an array" 由于[]紧跟在一个对象之后,它意味着“访问此名称的属性”而不是“创建一个数组”
  • true is a boolean, but is being used as an property name so it is cast to a string ( "true" ) true是一个布尔值,但是被用作属性名称,因此它被强制转换为字符串( "true"
  • The object does not have a property called true (since it has no properties) so {}['true'] is undefined 该对象没有名为true的属性(因为它没有属性)所以{}['true']undefined
  • !undefined casts undefined to a boolean ( false ) !undefined蒙上undefined的布尔( false
  • The not operator turns false into true . not运算符将false变为true

You're not reversing the value of it. 你没有扭转它的价值。

![true] != [!true]

Check this out: Why is !true ? 看看这个: 为什么是真的? 'false' : 'true' returning 'true'? 'false':'true'返回'true'?

Let's Play a Little More! 让我们多玩一点吧!

First, let's have some fun!: 首先,让我们玩得开心!:

//----------#01#-----------
{}[true]; //[true]

//----------#02#-----------
var a = {}[true]; 
      console.log(a); //undefined

//----------#03#-----------
{ b: 12345 }[true]; //[true]

//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?

//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."

//----------#06#-----------
({ b: 12345 }).b; //12345

//----------#07#-----------
var c = { b: 12345 }.b; 
      console.log(c); //12345

//----------#08#-----------
var c = { b: 12345 }["b"];
      console.log(c); //12345

//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "

//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
      console.log(d); //54321

//----------#11#-----------
!{}[true]; // true

Ok, let's try to understand these crazy behaviors, one by one: 好吧,让我们一个接一个地尝试理解这些疯狂的行为:

1) Here, the {} is parsed as an empty code block. 1)这里, {}被解析为空代码块。 Without an assign, negation, grouping (with parentheses) or any syntax which indicates to the parser that this {} is an object literal, the default assumption is to think it is simply a useless empty block. 如果没有赋值,否定,分组(带括号)或任何语法向解析器指示此{}是对象文字,则默认的假设是认为它只是一个无用的空块。

This is a proof of this behavior: 这是此行为的证明:

{ alert(123) }[true]

The code above will show the alert normally, and will be evaluated as [true] , in the same way {}[true] is. 上面的代码将正常显示警报,并将以[true]形式进行评估,其方式与{}[true]相同。

Block Statements Without Semicolons 没有分号的阻止语句

A block-type statement doesn't need a semicolon after it. 块类型语句后面不需要分号。

For instance: 例如:

for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")

Both alerts are shown. 显示两个警报。

So, we can see that an empty block statement, without a semicolon, is valid and simply does nothing. 因此,我们可以看到没有分号的空块语句是有效的,并且什么都不做。 This way, when you enter {}[true] in the Developer Tools (or Firebug) Console, the evaluated value will be the value of the last expression statement . 这样,当您在Developer Tools(或Firebug)控制台中输入{}[true]时,评估的值将是最后一个表达式语句的值。 In this case, the last expression statement is [true] . 在这种情况下,最后一个表达式语句是[true]

2) In an assignment context, the parser will make sure that {} is an object literal. 2)在赋值上下文中,解析器将确保{}是对象文字。 When you do var a = {}[true] , you remove any ambiguity and tip the parser off that {} is not a block statement. 当你执行var a = {}[true] ,你会删除任何歧义并提示解析器{}不是块语句。
So, here, you're trying to get a value with a key "true" from an empty object. 所以,在这里,你试图从空对象中获取一个带有"true"键的值。 Obviously, there's no key-value pair with this key name. 显然,这个密钥名称没有键值对。 This way, the a variable is undefined. 这样,a变量是未定义的。

Reserved words as Object keys 保留字作为对象键

ECMAScript 5 allows object keys to be reserved words. ECMAScript 5允许对象键是保留字。 So, the following keys are legal: 因此,以下密钥是合法的:

var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}

3) The same explanation of example 1 . 3)与例1相同的解释。 But... If the { b: 12345 } part is treated as a block statement, what's the type of the b: 12345 statement?? 但是......如果将{ b: 12345 }部分视为块语句,那么b: 12345语句的类型是什么?

... (?????) ......(?????)

It's a label statement , you already saw it before... It's used in loops and in switch . 这是一个标签声明 ,您之前已经看过它......它用于循环和switch Here are a few interesting links about label statements: 1 , (2)[ Best way to break from nested loops in Javascript? 以下是一些关于标签语句的有趣链接: 1 ,(2)[ 在Javascript中打破嵌套循环的最佳方法? , (3)[ How to break nested loops in javascript? ,(3)[ 如何在javascript中打破嵌套循环? .

NOTE: Just try to evaluate this: 注意:试着评估一下:

{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :

Label statements can't be separeted by the comma operator, you would need to separate them with a semicolon. 标签语句不能由逗号运算符分隔,您需要用分号分隔它们。 So this is valid: {a: 1; b: 2} 所以这是有效的: {a: 1; b: 2} {a: 1; b: 2}

4) See the explanations for the examples 1 and 3 ... 4)参见实施例13的解释......

5) One more time, we have a { b: 12345 } being treated as a code block, and you're trying to access a property of a code block by using the dot notation , and obviously, this is not allowed, and the parser throws an "Unexpected token :" exception. 5)再一次,我们将{ b: 12345 }视为代码块,并且您尝试使用点表示法来访问代码块的属性,显然,这是不允许的,并且解析器抛出"Unexpected token :"异常。

6) The code is almost identical to the above example, but by surrounding the { b: 12345 } statement with the expression grouping operator , the parser will know that is an object. 6)代码几乎与上面的例子相同,但是通过用表达式分组运算符包围{ b: 12345 }语句,解析器将知道它是一个对象。 This way, you'll be able to access the "b" property normally. 这样,您就可以正常访问"b"属性。

7) Remember the example 2 , we have an assignment here, the parser knows that { b: 12345 } is an object. 7)记住示例2 ,我们在这里有一个赋值,解析器知道{ b: 12345 }是一个对象。

8) Identical to the above example, but instead of the dot notation, here we're using the bracket notation . 8)与上面的例子相同,但不是点符号,这里我们使用括号表示法

9) I already said that this "identifier: value" syntax inside a block statement is a label. 9)我已经说过块语句中的这个"identifier: value"语法是一个标签。 But, you also have to know that a label name can't be a reserved keyword (the opposite of object property names). 但是,您还必须知道标签名称不能是保留关键字(与对象属性名称相反)。 When we tried to define a label called "true" , we got a SyntaxError . 当我们尝试定义一个名为"true"的标签时,我们得到了一个SyntaxError

10) Again, we're dealing with an object. 10)同样,我们正在处理一个对象。 No problems using reserved words here. 这里使用保留字没问题。 =) =)

11) Finally, we have this: !{}[true] 11)最后,我们有: !{}[true]

Let's separate the things here: 让我们分开这里的事情:

a) By doing a negation, we're informing to the parser that the {} is an object . a)通过做出否定,我们通知解析器{}一个对象

b) As shown in the example 2 , a {} object doesn't have a property called true , so this expression will evaluate to undefined . b)如示例2所示, {}对象没有名为true的属性,因此该表达式将计算为undefined

c) The final result is the negation of undefined value. c)最终结果是否定undefined值。 Javascript performs implicity type conversion , and undefined value is falsy . Javascript执行隐含类型转换undefined值是伪造的

d) So, the negation of false is... true ! d)所以,对false的否定是...... true

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

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