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

时间:2013-10-31 09:34:06

标签: javascript

{}[true][true]![true]应为false

那么为什么!{}[true]评估为true

10 个答案:

答案 0 :(得分:171)

我相信这是因为普通{}[true]被解析为空语句块(不是对象文字),后跟包含true的数组true

另一方面,应用!运算符会使解析器将{}解释为对象文字,因此以下{}[true]成为返回undefined的成员访问, !{}[true]确实true!undefinedtrue)。

答案 1 :(得分:44)

由于{}[true]未返回true,但undefinedundefined被评估为false

http://jsfiddle.net/67GEu/

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

答案 2 :(得分:27)

由于

{}[true]

评估为undefined!undefinedtrue

来自@schlingel:

true用作键,{}用作哈希映射。没有包含密钥true的属性,因此返回undefined。正如预期的那样,undefined不是true

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

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

但是,在Google Chrome控制台中:

> !{}[true]
true

所以,没有不一致。您可能正在使用旧版本的JavaScript VM。对于那些需要进一步证据的人:

Enter image description here

更新

使用Firefox,它还会评估为true

Enter image description here

答案 3 :(得分:23)

混淆的原因在于对你的第一个断言的误解:

{}[true][true]

运行它时所看到的是模棱两可的结果。 Javascript有一套定义的规则来处理如何处理这样的歧义,在这种情况下,它会将你看到的单元语句分解为两个单独的语句。

因此,Javascript将上述代码视为两个单独的语句:首先,有一个{},然后有一个完全独立的[true]。第二个陈述是给你结果的[true]。第一个陈述{}被完全忽略了。

您可以通过尝试以下方式证明这一点:

({}[true])

即将整个事物包装在括号中以强制解释器将其作为单个语句读取。

现在您将看到语句的实际值为undefined。 (这也有助于我们以后了解下一部分)

现在我们知道你问题的最初部分是红鲱鱼,所以让我们转到问题的最后部分:

  

那么为什么!{} [true]评估为真?

在这里,我们有相同的陈述,但前面附有!

在这种情况下,Javascript的规则告诉它将整个事物评估为单个语句。

回顾一下当我们用括号括起前面的陈述时发生的事情;我们得到了undefined。这一次,我们实际上做了同样的事情,但在它前面放了一个!。因此,您的代码可以简化为!undefined,即true

希望能够解释一下。

这是一个复杂的野兽,但这里要学习的教训是在控制台中评估它们时使用括号,以避免像这样的虚假结果。

答案 4 :(得分:14)

{}[true]undefined。要找到这样写:

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

或简单地说:

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

我们知道!undefinedtrue


来自@Benjamin Gruenbaum's answer

  

Chrome dveloper tools does the following

  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;
  }
  

基本上,它使用表达式对对象执行call。表达式为:

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

因此,正如您所看到的,表达式是直接计算的,没有包装括号。

更多信息可在this question中找到。

答案 5 :(得分:10)

这里的答案很好,这里是伪代码的细分:

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

答案 6 :(得分:8)

这是因为你的意思{}不是Object的文字表示,而是空范围(或空代码块):

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

它只是评估范围内的代码,然后显示你的数组。

来自你的

!{}[true]

只需将此范围转换为int并返回相同的数组即可。此代码中没有bool检查。

如果您尝试检查{}[true]的结果,您将获得false

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

由于没有任何范围。

因此,问题!的作用与:

相同
!function() {
   //...
}

答案 7 :(得分:6)

  • {}是一个没有属性的对象。
  • 由于[]紧跟一个对象,因此意味着“访问此名称的属性”而不是“创建一个数组”
  • true是一个布尔值,但是被用作属性名称,因此它被强制转换为字符串("true"
  • 该对象没有名为true的属性(因为它没有属性),因此{}['true']undefined
  • !undefinedundefined强制转换为布尔值(false
  • not运算符将false变为true

答案 8 :(得分:4)

你没有扭转它的价值。

![true] != [!true]

检查出来:Why is !true ? 'false' : 'true' returning 'true'?

答案 9 :(得分:4)

让我们多玩一点!

首先,让我们玩得开心!:

//----------#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

好的,让我们逐一了解这些疯狂的行为:

1)这里,{}被解析为空代码块。如果没有赋值,否定,分组(带括号)或任何语法向解析器指示此{}是一个对象文字,默认的假设是认为它只是一个无用的空块。

这证明了这种行为:

{ alert(123) }[true]

上面的代码会正常显示提醒,并且会以[true]的方式评估{}[true]

没有分号的阻止语句

块类型语句后面不需要分号。

例如:

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

会显示两个警报。

因此,我们可以看到没有分号的空块语句是有效的,并且什么都不做。这样,当您在开发人员工具(或Firebug)控制台中输入{}[true]时,评估的值将是最后expression statement的值。在这种情况下,最后一个表达式语句是[true]

2)在赋值上下文中,解析器将确保{}是对象文字。当您执行var a = {}[true]时,您可以消除任何歧义并向解析器提示{}不是块语句。
所以,在这里,你试图从一个空对象中获取一个带有"true"键的值。显然,这个密钥名称没有键值对。这样,a变量是未定义的。

保留字作为对象键

ECMAScript 5 允许对象键为保留字。因此,以下密钥是合法的:

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

3)示例 1 的相同解释。但... 如果将{ b: 12345 }部分视为块语句,那么b: 12345语句的类型是什么?

...(?????)

这是label statement,你之前已经看过了......它用在循环和switch中。以下是一些有关标签声明的有趣链接:1,(2)[Best way to break from nested loops in Javascript?,(3)[How to break nested loops in javascript?

注意:只是尝试评估一下:

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

comma运算符不能分隔标签语句,您需要用分号分隔它们。所以这是有效的:{a: 1; b: 2}

4)请参阅示例的解释 1 3 ......

5)再一次,我们将{ b: 12345 }视为代码块,并且您尝试使用{{3}来访问代码块的属性很明显,这是不允许的,解析器抛出"Unexpected token :"异常。

6)代码几乎与上面的示例相同,但是通过用dot notation包围{ b: 12345 }语句,解析器将知道这是一个对象。这样,您就可以正常访问"b"属性。

7)请记住示例 2 ,我们在这里有一个分配,解析器知道{ b: 12345 }是一个对象。

8)与上述示例相同,但我们使用的是expression grouping operator,而不是点符号。

9)我已经说过块语句中的这个"identifier: value"语法是一个标签。但是,您还必须知道标签名称不能是保留关键字(与对象属性名称相反)。当我们尝试定义名为"true"的标签时,我们得到了SyntaxError

10)再次,我们正在处理一个对象。这里使用保留字没问题。 =)

11)最后,我们有:!{}[true]

让我们分开这里的事情:

a)通过做出否定,我们告知解析器{} 是一个对象

b)如示例 2 所示,{}对象没有名为true的属性,因此此表达式将评估为undefined

c)最终结果是否定bracket notation值。 Javascript执行undefinedimplicity type conversion

d)因此,false的否定是...... true