131

{}[true][true]而且![true]应该是false

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

4

10 回答 10

173

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

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

于 2013-10-31T09:43:23.680 回答
44

因为{}[true]不返回true, 但是undefined, 并且undefined被评估为false:

http://jsfiddle.net/67GEu/

'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true
于 2013-10-31T09:41:20.197 回答
27

因为

{}[true]

计算为undefined,并且!undefinedtrue

来自@schlingel:

true用作键和{}哈希映射。不存在带有键的属性,true因此它返回undefined。不是,正如预期的那样undefinedtrue

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

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

但是,在Google Chrome控制台中:

> !{}[true]
true

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

在此处输入图像描述

更新

使用Firefox时,它还评估为true

在此处输入图像描述

于 2013-10-31T09:41:36.990 回答
23

混淆的原因归结为对您的第一个断言的误解:

{}[true][true]

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

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

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

({}[true])

即把整个内容放在括号中以强制解释器将其作为单个语句来阅读。

现在您将看到您的语句的实际值是undefined. (这也有助于我们后面理解下一部分)

现在我们知道您问题的最初部分是一个红鲱鱼,所以让我们进入问题的最后部分:

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

在这里,我们有相同的语句,但在!它的前面附加了一个。

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

回顾一下当我们将前面的语句括在括号中时发生的事情;我们得到了undefined。这一次,我们实际上是在做同样的事情,但!在它前面放了一个。所以你的代码可以简化为!undefined,即true

希望这能解释一下。

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

于 2013-10-31T09:51:53.150 回答
14

{}[true]undefined。要找到它,请写下:

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

或者简单地说:

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

我们知道那!undefinedtrue


来自@Benjamin Gruenbaum 的回答

Chrome 开发者工具执行以下操作

  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使用表达式对对象执行 a 。表达式为:

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

因此,如您所见,表达式是直接计算的,没有括号。

更多信息可以在这个问题中找到。

于 2013-10-31T09:55:50.600 回答
10

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

  • {}['whatever']= 空块,NewArray('whatever') = NewArray('whatever')
  • {}[true]= 空块,NewArray(true) = NewArray(true)
  • !{}['whatever']= LogicalNOT(convertToBool(NewObject.whatever)) = LogicalNOT(convertToBool(undefined)) = LogicalNOT(false) = true
  • ({}['whatever'])=分组(NewObject.whatever)=分组(未定义)=未定义
于 2013-10-31T13:47:39.557 回答
8

发生这种情况是因为{}您的意思不是字面表示Object,而是空范围(或空代码块):

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

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

从你的

!{}[true]

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

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

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

因为没有更多的范围。

所以!在你的问题中做同样的事情:

!function() {
   //...
}
于 2013-10-31T09:42:27.557 回答
6
  • {}是一个没有属性的对象。
  • 由于[]紧跟在一个对象之后,它意味着“访问该名称的属性”而不是“创建一个数组”
  • true是一个布尔值,但被用作属性名称,因此它被转换为字符串 ( "true")
  • 该对象没有称为的属性true(因为它没有属性)所以{}['true']undefined
  • !undefined转换undefined为布尔值 ( false)
  • not 运算符false变成true.
于 2013-10-31T09:42:18.587 回答
4

你没有颠倒它的价值。

![true] != [!true]

看看这个:为什么是 !t​​rue ?“假”:“真”返回“真”?

于 2013-10-31T09:41:41.100 回答
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!")

显示两个警报。

因此,我们可以看到没有分号的空块语句是有效的,并且什么也不做。这样,当您进入{}[true]开发者工具(或 Firebug)控制台时,评估值将是最后一个表达式语句的值。在这种情况下,最后一个表达式语句是[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

……(??????)

这是一个标签语句,你之前已经看过了……它用于循环和switch. 以下是一些关于标签语句的有趣链接:1 , (2)[打破 Javascript 中嵌套循环的最佳方法?, (3)[如何打破 javascript 中的嵌套循环?.

注意:试着评估一下:

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

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

4)参见示例13的解释...

5)再一次,我们将 a{ b: 12345 }视为一个代码块,而您试图通过使用点符号来访问代码块的属性,显然这是不允许的,并且解析器会抛出"Unexpected token :"异常。

6)代码与上面的例子几乎相同,但是通过用表达式分组运算符{ b: 12345 }包围语句,解析器将知道这是一个对象。这样,您将能够正常访问该属性。"b"

7)记住例子2,我们这里有一个赋值,解析器知道它{ b: 12345 }是一个对象。

8)与上面的示例相同,但这里我们使用括号表示法而不是点表示法。

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

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

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

让我们把这里的东西分开:

a)通过否定,我们通知解析器这{}一个对象

b) 如示例2所示,{}对象没有名为 的属性true,因此该表达式的计算结果为undefined

c) 最终的结果是undefined价值的否定。Javascript执行隐式类型转换undefined值是假的

d) 所以,is 的否定false是... true

于 2014-01-18T03:33:09.373 回答