{}[true]
表示[true]
,而![true]
应该是false
。
那么为什么!{}[true]
会被计算为true
呢?
{}[true]
表示[true]
,而![true]
应该是false
。
那么为什么!{}[true]
会被计算为true
呢?
我认为这是因为纯粹的{}[true]
被解析为一个空语句块(而不是对象文字),其后跟一个包含true
的数组,该数组的值为true
。
另一方面,应用!
运算符会使解析器将{}
解释为一个对象字面量,因此以下{}[true]
变成了一个返回undefined
的成员访问操作,而!{}[true]
确实是true
(因为!undefined
是true
)。
undefined
是假值(我们经常依赖它,如 if (obj.maybeExists) ...
),因此 !undefined
成立在逻辑上也是完全合理的。 - josh3736!undefined
等于undefined
。 然而在JavaScript中不是这种情况。 - Frédéric Hamidi非未定义(!undefined)
的,意义上来讲就表示它被定义了。如果某个东西被定义了,那么通常它被解释为true
。 - OozeMeister因为{}[true]
并不会返回true
,而是返回undefined
,而undefined
会被视为false
:
'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true
{}[true]
,则会得到[true]
,因为{}
被解释为一个空代码块,而不是一个对象。这取决于上下文和{}
的歧义性。 - IMSoP{key:"value"}[1,2,3];
也会得出[1,2,3]
的结果呢? - t.niesekey:
)和字符串字面值("value"
),后跟一个数组。解析器仍未看到对象字面量。 - Frédéric Hamidialert()
或者 console.log()
中,或者将它赋值给一个变量,你就改变了上下文,这就是为什么它在控制台中单独输入时不会表现出相同的行为方式。 - IMSoP由于
{}[true]
求值为undefined
,!undefined
的结果是true
。
来自@schlingel:
true
被用作键,而{}
被用作哈希映射。不存在一个key是true
的属性,因此返回undefined
。预期的结果是,undefined
不是true
。
控制台会话(Node.js [0.10.17]
):
> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>
然而,在 Google Chrome 控制台中:
> !{}[true]
true
因此,没有不一致性。你可能正在使用旧版本的JavaScript VM。需要更多证据的人可以看下方图片:
在Firefox中,它也评估为true
:
!{}[true]
会返回true
,但是{}[true]
会返回[true]
而不是undefined
。 - lastr2d2{}[true]
是 [true]
当你运行它时看到的结果是一种歧义的结果。 Javascript 有一套定义明确的规则来处理这种歧义,而在这种情况下,它将您看到的单个语句分成两个单独的语句。{}
,然后是一个完全独立的 [true]
。第二个语句是给你结果 [true]
的原因,第一个语句 {}
被完全忽略了。({}[true])
将整个语句用括号括起来以强制解释器将其作为单个语句读取。
现在,您会发现语句的实际值为undefined
。(这也有助于我们后面理解下一部分)
现在我们知道你问题的初始部分是一个红鱼,所以让我们转向问题的最后部分:
那么为什么!{}[true]的结果为true?
在这里,我们有同样的语句,但在前面加上了!
。
在这种情况下,JavaScript的规则告诉它将整个语句作为单个语句进行计算。
回顾一下当我们将早期语句包含在括号中时发生了什么;我们得到了undefined
。这次,我们实际上正在做同样的事情,但在前面加上了!
。因此,您的代码可以简化为!undefined
,这是true
。
希望这解释清楚了一些。
它是一个复杂的东西,但在此要学习的教训是在控制台中评估语句时,在语句周围使用括号,以避免出现类似这样的虚假结果。
{}[true]
是无效的,只是模棱两可的。它可以被解释为“空代码块后跟数组文字”或“没有属性的对象文字,其中正在访问属性”。我不知道第一个是否在技术上属于ASI的情况(许多语言都不会在那里放置分号),但上下文敏感的解释是问题的核心。 - IMSoP{}[true]
是 true
",他们说的是 "{}[true]
是 [true]
",这是模棱两可陈述的两种有效解释之一。 - IMSoP{}[true]
是 undefined
。要查找,请写入以下内容:
a = {};
a[true] === undefined // true
或者简单地说:
({})[true] === undefined // true
我们知道 !undefined
是 true
。
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
}
所以,正如你所看到的,表达式是直接被评估的,没有包裹括号。{}['whatever']
= 空块,NewArray('whatever') = NewArray('whatever'){}[true]
= 空块,NewArray(true) = NewArray(true)!{}['whatever']
= 逻辑非(convertToBool(NewObject.whatever)) = 逻辑非(convertToBool(undefined)) = 逻辑非(false) = true({}['whatever'])
= 分组(NewObject.whatever) = 分组(undefined) = undefined这是因为您的意思中的{}
并不是Object
的字面表示,而是空范围(或空代码块):
{ var a = 1 }[true] // [true] (do the same thing)
它只评估范围内的代码,然后显示您的数组。
从你的
!{}[true]
将该范围转换为整数并返回相同的数组即可。此代码中没有布尔检查。
如果您尝试检查{}[true]
的结果,您将得到false
:
{}[true] -> [true] -> ![true] -> false
由于没有任何余地,所以您问题中的感叹号!
具有相同的作用:
!function() {
//...
}
var x = {}; x[true]
,这将更容易看到。 - Chris Hayes!
后,它被解释为空对象,而不是作用域,这就是差异所在。 - IMSoP{}
是一个没有属性的对象。[]
紧跟在一个对象后面,它的意思是“访问这个名称的属性”,而不是“创建一个数组”。true
是一个布尔值,但被用作属性名,因此被转换为字符串 ("true"
)。true
的属性(因为它没有属性),所以 {}['true']
是 undefined
。!undefined
将 undefined
转换为布尔值 (false
)。false
转换为 true
。{}[true]
的情况下(没有其他上下文),{}
不是没有属性的对象,而是一个空代码块。 - IMSoP首先,让我们来玩点有趣的东西:
//----------#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]
时,计算出的值将是最后一个表达式语句的值。在这种情况下,最后一个表达式语句是[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) 参见示例1和3的解释...
5) 再一次,我们有一个{ 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) 因此,false
的否定是……true
!
{}[true] === [true]
,那是因为它将{}
视为一个空代码块,而不是对象。 - azz{}
和({})
(或者比较{}
中的[true]
和({})
中的[true]
)。另外,由于没有人提到,object[true]
会被计算为object["true"]
。 - BiAiB