++ [[]] [+ []] + [+ []]가 문자열 “10”을 반환하는 이유는 무엇입니까? 예제는 여기 ). console.log(++[[]][+[]]+[+[]]) 코드 스 니펫 실행결과

이것은 유효하며 "10"JavaScript로 문자열 을 반환합니다 ( 더 많은 예제는 여기 ).

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

왜? 여기서 무슨 일이 일어나고 있습니까?



답변

우리가 나누면 혼란은 다음과 같습니다.

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

JavaScript에서는 사실입니다 +[] === 0. +무언가를 숫자로 변환하면이 경우 +""또는 로 내려갑니다 0(아래 사양 세부 사항 참조).

따라서 우리는 그것을 단순화 할 수 있습니다 ( ++우선 순위보다 +).

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

때문에 [[]][0]수단 : 첫 번째 요소를에서 얻을 [[]], 그것은 사실이다 :

[[]][0]내부 배열 ( [])을 반환합니다 . 참조로 인해 잘못 말하지만 잘못된 표기법을 피하기 위해 [[]][0] === []내부 배열 A을 호출합시다 .

++피연산자 앞에는 “1 씩 증가하고 증가 된 결과를 반환”을 의미합니다. 따라서 (또는 ) ++[[]][0]와 같습니다 .Number(A) + 1+A + 1

다시, 우리는 혼란을 좀 더 읽기 쉬운 것으로 단순화 할 수 있습니다. []다시 대체하자 A:

(+[] + 1)
+
[0]

전에 +[]숫자로 배열을 강요 할 수 있습니다 0, 그것은이다, 먼저 문자열로 강제 할 필요가 ""다시. 마지막으로 1가 추가됩니다 1.

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

더 단순화하자 :

1
+
[0]

또한 이것은 JavaScript :에서도 마찬가지입니다 [0] == "0". 하나의 요소로 배열을 결합하기 때문입니다. 결합하면로 구분 된 요소가 연결됩니다 ,. 하나의 요소를 사용하면이 논리가 첫 번째 요소 자체가된다고 추론 할 수 있습니다.

이 경우 +숫자와 배열의 두 피연산자가 나타납니다. 이제 두 가지를 같은 유형으로 강제하려고합니다. 먼저 배열이 string으로 강제 변환되고 그 "0"다음 숫자가 문자열 ( "1") 로 강제 변환됩니다 . 숫자 +문자열 ===문자열 .

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

에 대한 사양 세부 정보 +[]:

이것은 미로이지만, 할 일은 +[]먼저 문자열로 변환되고 있기 때문입니다 +.

11.4.6 단항 + 연산자

단항 + 연산자는 피연산자를 숫자 유형으로 변환합니다.

UnaryExpression : + UnaryExpression 프로덕션은 다음과 같이 평가됩니다.

  1. expary는 UnaryExpression을 평가 한 결과입니다.

  2. ToNumber (GetValue (expr))를 반환합니다.

ToNumber() 말한다 :

목적

다음 단계를 적용하십시오.

  1. primValue를 ToPrimitive (입력 인수, 힌트 문자열)로 둡니다.

  2. ToString (primValue)을 반환합니다.

ToPrimitive() 말한다 :

목적

Object의 기본값을 반환합니다. 개체의 기본값은 개체의 [[DefaultValue]] 내부 메서드를 호출하여 선택적 힌트 PreferredType을 전달하여 검색됩니다. [[DefaultValue]] 내부 메소드의 동작은 8.12.8의 모든 기본 ECMAScript 객체에 대해이 사양으로 정의됩니다.

[[DefaultValue]] 말한다 :

8.12.8 [[기본값]] (힌트)

힌트 문자열과 함께 [[DefaultValue]] 내부 메소드를 호출하면 다음 단계가 수행됩니다.

  1. toString은 “toString”인수를 사용하여 객체 O의 [[Get]] 내부 메소드를 호출 한 결과입니다.

  2. IsCallable (toString)이 true이면

ㅏ. str은 toString의 [[Call]] 내부 메소드를 호출 한 결과이며,이 값은 O이고 빈 인수 목록입니다.

비. str이 기본 값이면 str을 반환합니다.

.toString배열의 말한다 :

15.4.4.2 Array.prototype.toString ()

toString 메소드가 호출되면 다음 단계가 수행됩니다.

  1. 이 값에 대해 ToObject를 호출 한 결과로 array를 사용합니다.

  2. func는 인수 “join”을 가진 배열의 [[Get]] 내부 메소드를 호출 한 결과입니다.

  3. IsCallable (func)이 false이면 func를 표준 내장 메소드 Object.prototype.toString (15.2.4.2)으로 설정하십시오.

  4. 배열을 제공하는 함수의 [[Call]] 내부 메소드를 this 값과 빈 인수 목록으로 호출 한 결과를 리턴하십시오.

그래서 +[]내려 온다 +""때문에 [].join() === "".

다시, +는 다음과 같이 정의됩니다.

11.4.6 단항 + 연산자

단항 + 연산자는 피연산자를 숫자 유형으로 변환합니다.

UnaryExpression : + UnaryExpression 프로덕션은 다음과 같이 평가됩니다.

  1. expary는 UnaryExpression을 평가 한 결과입니다.

  2. ToNumber (GetValue (expr))를 반환합니다.

ToNumber다음과 ""같이 정의 됩니다.

StringNumericLiteral :::의 MV는 0입니다.

그래서 +"" === 0, 이렇게 +[] === 0.


답변

++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]

그런 다음 문자열 연결이 있습니다

1+[0].toString() = 10

답변

다음은 이 질문이 여전히 닫혀있는 동안 게시 한이 질문에 대답 하는 블로그 게시물 에서 수정 되었습니다. ECMAScript 3 사양의 링크 (HTML 사본)는 오늘날 일반적으로 사용되는 웹 브라우저의 JavaScript 기준입니다.

첫째, 의견 : 이런 종류의 표현은 (정확한) 프로덕션 환경에서 절대로 나타나지 않을 것이며 독자가 JavaScript의 더티 에지를 얼마나 잘 알고 있는지에 대한 연습으로 만 사용됩니다. JavaScript 연산자가 형식간에 암시 적으로 변환하는 일반적인 원칙은 일부 일반적인 변환과 마찬가지로 유용하지만이 경우의 세부 사항은 그다지 유용하지 않습니다.

표현 ++[[]][+[]]+[+[]]은 처음에는 다소 강렬하고 모호한 것처럼 보일 수 있지만 실제로는 별도의 표현으로 비교적 쉽게 분류 할 수 있습니다. 아래에는 명확성을 위해 괄호를 추가했습니다. 나는 그들이 아무것도 바꾸지 않을 것을 확신 할 수 있지만, 그것을 확인하고 싶다면 그룹화 연산자 에 대해 자유롭게 읽으십시오 . 따라서 표현을보다 명확하게 작성할 수 있습니다.

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

이를 분석하면 다음으로 +[]평가 되는 것을 관찰하여 단순화 할 수 있습니다 0. 왜 이것이 사실인지 스스로 만족시키기 위해 단항 + 연산자를 확인 하고 약간 비참한 흔적을 따라 가면 ToPrimitive 가 빈 배열을 빈 문자열로 변환 한 다음 ToNumber0의해 변환됩니다 . 이제 각 인스턴스를 대체 할 수 있습니다 .0+[]

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

이미 간단합니다. 에 관해서는 ++[[]][0], 그것은 접두어 증가 연산자 ( ++), 그 자체가 빈 배열 ( ) 및 배열 리터럴에 의해 정의 된 배열에서 호출 되는 속성 접근 자 ( ) 인 단일 요소로 배열을 정의 하는 배열 리터럴 인 접두사 증가 연산자 ( ) 의 조합입니다 .[[]][0]

그래서, 우리는 간단하게 할 수 [[]][0]만에 []우리는이 ++[], 오른쪽? 실제로, 평가 ++[]하면 오류가 발생하여 처음에는 혼란스러워 보일 수 있기 때문에 그렇지 않습니다 . 그러나 특성의 특성에 대해 조금만 생각 ++하면 명확 해집니다. 변수 (예 🙂 ++i또는 객체 속성 (예 :)을 증가시키는 데 사용됩니다 ++obj.count. 값으로 평가 될뿐만 아니라 해당 값을 어딘가에 저장합니다. 의 경우 ++[]업데이트 할 객체 속성 또는 변수에 대한 참조가 없으므로 새 값을 입력 할 위치가 없습니다. 스펙 측면에서 이는 내부 PutValue 오퍼레이션에 의해 다루어지며 두부 증가 연산자에 의해 호출됩니다.

그렇다면 어떻게 ++[[]][0]해야합니까? 와 비슷한 논리에 의해 +[]내부 배열이 변환 0되고이 값이 증가 1하여 최종 값을 제공 1합니다. 0외부 배열 의 속성 값 이로 업데이트되고 1전체식이로 평가됩니다 1.

이것은 우리를 떠나

1 + [0]

더하기 연산자를 간단하게 사용합니다 . 두 피연산자는 먼저 프리미티브로 변환되고 프리미티브 값이 문자열이면 문자열 연결이 수행되고 그렇지 않으면 숫자 추가가 수행됩니다. [0]로 변환 "0"하므로 문자열 연결이 사용되어을 생성 "10"합니다.

마지막으로, 즉각적으로 명백하지 않을 수있는 것은 toString()또는의 valueOf()메소드 중 하나를 재정의 Array.prototype하면 표현식의 결과가 변경된다는 것입니다. 오브젝트를 프리미티브 값으로 변환 할 때 둘 다 확인되고 사용되기 때문입니다. 예를 들면 다음과 같습니다.

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

… 생산합니다 "NaNfoo". 왜 이런 일이 독자를위한 연습으로 남게됩니까?


답변

간단하게하자 :

++[[]][+[]]+[+[]] = "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"

답변

이것은 동일하지만 조금 작게 평가됩니다.

+!![]+''+(+[])
  • []-배열을 더하거나 빼면 0으로 변환되어 변환되므로 + [] = 0
  • ! []-false로 평가되므로 !! []는 true로 평가됩니다.
  • + !! []-true를 true로 평가되는 숫자 값으로 변환하므로이 경우 1
  • + ”-표현식에 빈 문자열을 추가하여 숫자를 문자열로 변환합니다.
  • + []-0으로 평가

그래서 평가

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

이제 당신은 그것을 가지고, 이것을 시도하십시오 :

_=$=+[],++_+''+$

답변

+ []는 0 […]으로 평가 한 다음 어떤 것으로 그것을 합산 (+ 연산)하여 배열 내용을 쉼표로 연결된 요소로 구성된 문자열 표현으로 변환합니다.

배열 인덱스를 가져 오는 것과 같은 다른 것 (+ 연산보다 우선 순위가 높음)은 서수이며 흥미로운 것은 아닙니다.


답변

숫자없이 “10”으로 식을 평가하는 가장 짧은 방법은 다음과 같습니다.

+!+[] + [+[]] // “10”

-~[] + [+[]] // “10”

// ========== 설명 ========== \\

+!+[]: +[]0으로 !0변환합니다 true. 로 변환합니다 . +true1로 변환합니다.
-~[]= -(-1)1

[+[]]: +[]0 [0]으로 변환합니다 . 단일 요소가 0 인 배열입니다.

이어서 JS는 평가 1 + [0], 따라서 Number + Array표현. 그런 다음 ECMA 사양이 작동합니다. +연산자는 toString()/valueOf()기본 Object프로토 타입 에서 함수를 호출하여 두 피연산자를 문자열로 변환합니다 . 표현식의 두 피연산자가 모두 숫자 인 경우 덧셈 함수로 작동합니다. 요령은 배열이 요소를 연결된 문자열 표현으로 쉽게 변환한다는 것입니다.

몇 가지 예 :

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

두 가지 Objects추가로 인한 예외는 다음과 NaN같습니다.

[] + []   //    ""
[1] + [2] //    "12"
{} + {}   //    NaN
{a:1} + {b:2}     //    NaN
[1, {}] + [2, {}] //    "1,[object Object]2,[object Object]"