代码之家  ›  专栏  ›  技术社区  ›  S.S. Anne

为什么这个表达式的值是10[[副本]

  •  0
  • S.S. Anne  · 技术社区  · 5 年前

    "10" 在JavaScript中( more examples here ):

    console.log(++[[]][+[]]+[+[]])

    为什么?这里发生了什么?

    0 回复  |  直到 6 年前
        1
  •  2153
  •   Sebastian Simon SamB    5 年前

    如果我们把它分开,混乱就等于:

    ++[[]][+[]]
    +
    [+[]]
    

    +[] === 0 . + 把某物转换成一个数字,在这种情况下,它将归结为 +"" 0 (见下文规范细节)。

    因此,我们可以简化它( ++ +

    ++[[]][0]
    +
    [0]
    

    因为 [[]][0] 意思是:从 [[]] ,确实:

    [] ). 由于参考文献的关系,说这个是错误的 [[]][0] === [] ,但是让我们调用内部数组 A 以避免错误的符号。

    ++ ++[[]][0] 相当于 Number(A) + 1 (或 +A + 1 ).

    [] 返回 A

    (+[] + 1)
    +
    [0]
    

    之前 +[] 可以将数组强制为数字 0 ,它需要先强制为一个字符串,即 "" 1 添加,这将导致 .

    • (+[] + 1) === (+"" + 1)
    • (+"" + 1) === (0 + 1)
    • (0 + 1) === 1

    1
    +
    [0]
    

    同样,在JavaScript中也是如此: [0] == "0" ,因为它是用一个元素连接一个数组。连接将连接由分隔的元素 , . 对于一个元素,您可以推断这个逻辑将导致第一个元素本身。

    + 可以看到两个操作数:一个数字和一个数组。它现在正试图将两者强制为同一类型。首先,数组被强制到字符串中 "0" "1" ). 数字 + === 字符串 .

    "1" + "0" === "10" // Yay!
    

    详细规范 +[] :

    这真是一个迷宫,但是 ,首先它被转换成一个字符串,因为 +

    11.4.6一元+运算符

    1. 让expr是对UnaryExpression求值的结果。

    ToNumber() 说:

    对象

    1. 返回字符串(primValue)。

    ToPrimitive() 说:

    返回对象的默认值。通过调用对象的[[DefaultValue]]内部方法并传递可选提示PreferredType,可以检索对象的默认值。[[DefaultValue]]内部方法的行为由本规范为8.12.8中的所有本机ECMAScript对象定义。

    [[DefaultValue]] 说:

    使用提示字符串调用O的[[DefaultValue]]内部方法时,将执行以下步骤:

    1. 让toString作为调用对象O的[[Get]]内部方法(参数为“toString”)的结果。

    2. 如果IsCallable(toString)为真,

    b。如果str是原语值,则返回str。

    这个 .toString

    15.4.4.2 Array.prototype.toString()

    1. 让array作为对this值调用ToObject的结果。

    2. 设func是调用参数为“join”的数组的[[Get]]内部方法的结果。

    3. 如果IsCallable(func)为false,则让func成为标准的内置方法Object.prototype.toString(15.2.4.2)。

    所以呢 +[] +"" ,因为 [].join() === ""

    再说一次 +

    11.4.6一元+运算符

    一元+运算符将其操作数转换为数字类型。

    生产UnaryExpression:+UnaryExpression的计算如下:

    1. Return to编号(GetValue(expr))。

    ToNumber 定义为

    所以呢 +"" === 0 ,因此 +[] === 0 .

        2
  •  127
  •   Shef    13 年前
    ++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
    [+[]] => [0]
    

    然后我们有一个字符串连接

    1+[0].toString() = 10
    
        3
  •  69
  •   Tim Down    13 年前

    以下内容改编自 blog post 回答这个问题,我张贴了这个问题,而这个问题仍然是关闭的。链接到(一个HTML副本)ECMAScript 3规范,它仍然是当今常用web浏览器中JavaScript的基线。

    首先是一条评论:这种表达式永远不会出现在任何(正常的)生产环境中,它只是一种练习,让读者了解JavaScript的肮脏边缘。JavaScript操作符在类型之间隐式转换的一般原则是有用的,一些常见的转换也是有用的,但是本例中的很多细节不是这样的。

    表达式 ++[[]][+[]]+[+[]] 可能一开始看起来相当气势和晦涩,但实际上是相对容易分解成单独的表达。为了清楚起见,我在下面加了括号;我可以向你保证他们什么也没变,但如果你想证实这一点,那就随便读一下 grouping operator . 因此,表达式可以更清楚地写为

    ( ++[[]][+[]] ) + ( [+[]] )
    

    分解这个,我们可以通过观察简化 +[] 计算结果为 0 unary + operator 沿着这条稍微曲折的小径走 ToPrimitive 将空数组转换为空字符串,然后最终转换为 0 ToNumber . 我们现在可以代替 0 对于每个实例 :

    ( ++[[]][0] ) + [0]
    

    ++[[]][0] ,这是 prefix increment operator ++ ),安 array literal 定义一个数组,其中有一个元素本身是空数组( [[]] property accessor [0] )在由数组文字定义的数组上调用。

    所以,我们可以简化 [[]][0] 为了公正 [] 我们有 ++[] ,对吧?事实上,情况并非如此,因为 抛出一个错误,这在一开始看起来可能很混乱。但是,有一点思考的性质 清楚地表明:它用于增加一个变量(例如。 ++i ++obj.count ++[] PutValue

    那么,这是什么呢 你知道吗?好吧,按照和 +[] ,内部数组将转换为 0 这个值加上 1 给我们一个 1 . 财产的价值 在外部数组中更新为 1 1 .

    这给我们留下了

    1 + [0]
    

    addition operator . 两个操作数都是第一个 converted to primitives 如果任一原语值是字符串,则执行字符串串联,否则执行数字加法。 [0] "0" ,因此使用字符串连接,生成 "10" .

    toString() valueOf() 方法 Array.prototype

    Array.prototype.toString = function() {
      return "foo";
    };
    ++[[]][+[]]+[+[]]
    

    ... 生产 "NaNfoo"

        4
  •  28
  •   Community datashaman    9 年前

    让我们简单一点:

    ++[[]][+[]]+[+[]] = "10"
    
    var a = [[]][+[]];
    var b = [+[]];
    
    // so a == [] and b == [0]
    
    ++a;
    
    // then a == 1 and b is still that array [0]
    // when you sum the var a and an array, it will sum b as a string just like that:
    
    1 + "0" = "10"
    
        5
  •  15
  •   John Powell NavinRaj Pandey    10 年前

    这个计算结果是一样的,但有点小

    +!![]+''+(+[])
    
    • []-是一个数组,当您对它进行加法或减法运算时,它被转换为0,因此+[]=0
    • ![] - 计算结果为false,因此!![]计算结果为真
    • +!![] - 将true转换为计算结果为true的数值,因此在本例中为1
    • +“”-将空字符串附加到表达式,从而使数字转换为字符串

    所以是为了

    +(true) + '' + (0)
    1 + '' + 0
    "10"
    

    现在你知道了,试试这个:

    _=$=+[],++_+''+$
    
        6
  •  8
  •   Eskat0n    13 年前

    […]然后将它与anything相加(+运算)将数组内容转换为由逗号连接的元素组成的字符串表示形式。

    任何其他类似于数组索引(比+运算优先级更高)的操作都是有序的,没有什么有趣的。

        7
  •  5
  •   Arman    3 年前

    可能是计算表达式的最短方法 "10" 没有数字的是:

    +!+[] + [+[]] // "10"
    -~[] + [+[]]  // "10"
    

    解释

    • +!+[] :
      • +[] 评估为 0 .
      • !0 评估为 true
      • +true 评估为 1
    • -~[] 与相同 -(-1) 评估为 1
    • [+[]]
      • +[] 计算结果为0
      • [0] 是具有单个元素的数组 0 .

    1 + [0] ,一个 数字 数组 + 运算符通过调用 主语 托斯特林

    一些例子:

    1 + {}            // "1[object Object]"
    1 + []            // "1"
    1 + new Date()    // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"
    [] + []           // ""
    [1] + [2]         // "12"
    {} + {}           // "[object Object][object Object]" ¹
    {a:1} + {b:2}     // "[object Object][object Object]" ¹
    [1, {}] + [2, {}] // "1,[object Object]2,[object Object]"
    

    { } 对象文字 ,而不是语句上下文中的块。在REPL中,您可以看到 {} + {} NaN ,因为大多数repl都是在语句上下文中操作的;这里,第一个 {} 是一个 ,代码等价于 {}; +{}; ,最终表达式语句(其值成为完成记录的结果)为 将对象强制为数字。

        8
  •  4
  •   Alireza    6 年前

    一步一步地, + 将值转换为一个数字,如果您将值添加到一个空数组 +[] …因为它是空的并且等于 0 ,它将

    它们之间有加号

    因此这些 [+[]] 将返回 [0] ,因为它们有一个空数组,该数组在另一个数组中转换为 0

    想象一下,第一个值是一个二维数组,里面有一个数组。。。所以 [[]][+[]] 将等于 [[]][0] ,它将返回 []

    最后把它转换成1

    所以你可以想象, 1 + “0” 将是 “10”

    0 ,它会的

    ++[[]][+[]]+[+[]] ...

    他们之间也有优势 ++[[]][+[]] + [+[]]

    所以这些 会回来的 [0] 0 在另一个数组中。。。

    所以想象一下,第一个值是 二维 内部有一个数组的数组。。。所以 [[]][+[]] 将等于 [[]][0] 它会回来的 [] ...

    ++ 将其转换并增加为 1

    所以你可以想象, + "0" "10"

    Why does return the string “10”?

        9
  •  2
  •   Tom van der Woerdt    13 年前
    1. 一元加给定字符串转换为数字
    2. 给定字符串的递增运算符转换并递增1
    3. +“”或+[]计算0。

      ++[[]][+[]]+[+[]] = 10 
      ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 
      1+0 
      10