【问题标题】:How does the ~[] construction work in JavaScript?~[] 构造在 JavaScript 中是如何工作的?
【发布时间】:2012-01-04 23:46:58
【问题描述】:

我遇到了无法解释的有效 JavaScript 代码。 例如:

  • +[]===0
  • -[]===0
  • ~[]===-1
  • ~-~[]===-2
  • ~-~-~-~-~[]===-5
  • ~-~-~-~-~[]+~[]===-6
  • ~+~[]===0
  • ~+~+~[]===-1
  • ~+~+~+~[]===0

你能解释一下这些表达的逻辑吗?

【问题讨论】:

  • 如果我遇到这样的代码,我想我会掀桌。
  • 答案是:+[NaN]==!!!!0&&+[{}]+~~[[]]-[]
  • 如果我在任何代码库中看到这一点,我会要求原始开发人员重写它。这是非常糟糕的做法!!!
  • 这些是 JavaScript 的利剑。用它们来伸张正义。

标签: javascript brackets tilde


【解决方案1】:

[] 是一个空数组对象,所以:

+[]:强制空数组为正整数,也就是0,也就是===为0
-[]:强制空数组为负整数,也就是 0,也就是 === 为 0
~[]: 按位非空数组,计算结果为 -1,即 === 到 -1
~-~[]: 取反的 NOTted 空数组的按位非:~-(-1) -> ~1 -> -2

等等……

【讨论】:

  • 应该是:~1 -> -2 在最后一个字符串上
  • -1 +[]: force empty array to be positive integer, aka 0, which is === to 0 没有解释为什么会发生这种情况。它只是重申了结果。显然如果+[] === 0,那么+[]肯定已经转换成0。问题要求解释逻辑。
【解决方案2】:

当您在任何东西上使用+- 运算符时,它会在其上调用NumberNumber([]) 返回0,所以你得到了前两个答案。

~ 运算符是按位非。基本上,它将数字中的所有位反转,将0 更改为-1。更多关于位运算符here

其余的只是这些情况的组合。你几乎可以将这些东西组合起来,得到任何你想要的数字。

【讨论】:

  • 知道了。我错过了[]0 部分的演员表。
【解决方案3】:

我不只是重申您在问题中展示的结果,而是尝试描述为什么您会得到该结果。

说明

仅以第一个例子为例(因为其余的会做类似的事情),我们可以按照规范来看看会发生什么。

11.4.6 Unary + Operator,我们可以看到发生了ToNumber 转换。

Return ToNumber(GetValue(expr)).

9.3 ToNumber 我们看到,如果给定一个对象(如您的数组),则会发生ToPrimitive 转换,然后再尝试ToNumber

对象

应用以下步骤:

  1. 设 primValue 为 ToPrimitive(输入参数,提示编号)。
  2. 返回到数字(primValue)。

9.1 To Primitive,如果ToPrimitive得到一个Object,我们可以看到它的[[DefaultValue]]被获取了:

对象

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

8.12.8 [[DefaultValue]] (hint) 开始,最终将在数组上调用toString() 并返回。如上所述,此字符串被发送到递归 ToNumber

那么当ToNumber 对字符串进行转换时会发生什么?好吧,它在9.3.1 ToNumber Applied to the String Type 中有描述,而且有点冗长。更简单的是直接进行转换,看看会发生什么:

Number("");     // result is 0 on an empty string
Number("    "); // result is 0 on a string with only whitespace
Number("123");  // result is 123 on a numeric string
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces
Number("abc");  // result is NaN (not a number) on non-numeric strings

所以问题是,我们从数组中返回什么字符串。同样,这很容易测试。

[].toString();  // result is "" (empty string)

由于结果是一个空字符串,而空字符串的ToNumber转换为0,如上所示,这意味着我们正在比较0 === 0

就像我们做的一样:

Number( [].toString() ) === 0; // true

或者再画出来一点:

var x = [];
x = x.toString();  // ""
x = Number( x );   // 0
x === 0;  // true

更多toString 结果。

要显示数组的更多toString 转换,请考虑以下事项:

[1].toString();            // "1"
[1,2,3].toString();        // "1,2,3"
["a",1,"b",2].toString();  // "a,1,b,2"

所以要对上述数组进行ToNumber 转换,第一个会给我们一个数字,最后两个会得到NaN

Number([1]);            // 1
Number([1,2,3]);        // NaN
Number(["a",1,"b",2]);  // NaN

一些证据

为了进一步证明这种toString() 转换发生在ToNumber 转换之前,我们实际上可以修改Array.prototype.toString 以提供不同的结果,并且任何ToNumber 转换都将使用修改后的结果。

Array.prototype.toString = function() {
    var n = 0;
    for( var i = 0; i < this.length; i++ ) {
        n += this[i];
    }
    return n;
};

在这里,我将Array.prototype 上的toString 替换为对数组求和的函数。显然您不想这样做,但我们可以展示我们现在将如何获得不同的结果。

Number([1,2,3]);   // 6
+[1,2,3];          // 6

所以现在您可以看到,我们的 Array 的 ToNumber 转换之前会导致 NaN 现在导致 Array 中的项目总和。

【讨论】:

    【解决方案4】:

    我会尽力的:

    []===0 当然是 false,因为 [] 不完全等于 0。但是,[]==0 是 true,因为存在隐式转换。

    +-[] 有效,因为加号或减号将 [] 转换为实数。

    ~0(0 的按位倒数)为 -1。因此~[]===-1 有效。

    其他的只是通过多次减去或添加 -1 来工作。

    【讨论】:

      【解决方案5】:

      我相信,如果我错了,请纠正我,但是添加到数组(例如,向数组添加值而不是向数组添加值)会将其转换为数字。其余的只是使用基本的 +, - 运算符(波浪号 (~) 是按位 NOT)来修改数字,然后是等式。

      So [] == array ([]);
      [] + 1 == number (0);
      +[]===0 (true)
      

      【讨论】:

      • 实际上它将它转换为字符串,而不是数字。 [1] + 1 = "11" 所以+[] = 0 因为这就像在做+""
      猜你喜欢
      • 2012-03-13
      • 1970-01-01
      • 2015-01-17
      • 2011-01-26
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      相关资源
      最近更新 更多