一開始我也有疑問,為什么 ++[[]][+[]]+[+[]]='10' ?

不得不信,於是我們要慢慢的分析:
分析基礎符號
[]分析
[]有兩個作用:
1. 數組
2. 訪問屬性和方法
例子:
[1,2,3,4] // 數組 "abc"[0] // 屬性 [1,2]["length"] // 方法
+運算符的作用
1. 創建數字
2. 將兩個值相加
3. 連接字符串
4. 創建字符串
兩個數相加
operand + operand = result
1. 如果操作符數中有一個對象,它將轉換為原始值(string、number或boolean)
2. 如果操作符數中有一個字符串,第二個操作數將轉換成字符串,並且連接在一起轉換成一個字符串
3. 在其它情況之下,兩個操作數轉換為數字並且將執行加法運算
其中,對象轉換的規則:
1. 如果對象類型是一個Date,可以使用toString()方法
2. 在其它情況下使用valueOf()方法,它將返回一個原始值
3. 如果valueOf()方法不能將它返回一個原始值,可以使用toString()方法。而這種情況大部分情況下都會發生
例子:
// 數字和字符串 var result = 1 + "5"; // "15" // 數字和數組 var result = [1,3,5] + 1; // "1,3,51" // 數字和布爾值 var result = 10 + true; // 11 // 數字和對象 var result = 15 + {}; // "15[object Object]" // 數字和null var result = 8 + null; // 8 // 字符串和null var result = "queen" + null; // "queennull" // 數字和undefined var result = 12 + undefined; // NaN
下面這張圖是兩個變量相加的類型結果:

位於操作數之前(+x)
一元正號運算符(unary plus operator)位於其操作數前面,計算其操作數的數值,如果操作數不是一個數值,會嘗試將其轉換成一個數值。它可以將字符串轉換成整數和浮點數形式,也可以轉換非字符串值 true,false 和 null。小數和十六進制格式字符串也可以轉換成數值。負數形式字符串也可以轉換成數值(對於十六進制不適用)。如果它不能解析一個值,則計算結果為 NaN。
例子:
+3 // 3 +"3" // 3 +true // 1 +false // 0 +null // 0 +[] // 0
遞增(++)
遞增運算符(increment operator)為其操作數增加1,返回一個數值。
解析++[[]][+[]]+[+[]]
首先把這個表達式拆分開來,如:
++[[]][+[]] + [+[]]
由上面的基礎分析可知, +[] === 0 是完全正確的,故我們可以簡化如下:
++[[]][0] + [0]
[[]][0] 返回內部數組 ([])。但是由於語言規范, [[]][0] === [] 是不正確的,因此我們暫時用A來代替里面的數組。
++[[]][0] == A + 1, 因為 ++ 的意思是”+1”。
++[[]][0] === +(A + 1);這是一個數值,因為遞增(++)返回的永遠都是一個數值
因此,表達式可以簡化如下:
+([] + 1) + [0]
由上面的基礎符號分析可以簡化表達式如下:
1 // 參考+在操作數前面 + "0" // 參考兩個變量相加的對象轉換規則
故最終結果為'10'。
用途
上面只是一個簡單的例子,其實用這些字符串是可以寫出真正有用的代碼的,例如:
(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]] // alert(1)
可以在此生成想要的代碼:http://www.jsfuck.com/
看着一些字符串可以執行,想必大家都有疑慮,用在哪些地方呢?
由於這樣的代碼屬於混淆代碼,不容易被識別,我們可以用在賬戶的安全校驗上,比如,可以在Web端賬戶登陸之前從后端拿到一段這樣的可執行代碼,將執行結果寫入cookie、token或者ajax請求里,這樣可以防止一部分黑產用工具刷接口來獲取數據。
由於黑產現在采用的工具都是易語言寫的。基於winhttp.dll和winInet.dll的,不具備js引擎,所以如果web端在提交登陸之前獲取並執行后端的一段這樣的代碼,一來可以以混淆的代碼使得黑產不容易看懂,二來如果黑產想破解的話,就需要一個js引擎或者無頭瀏覽器,其成本是很高的。
用於安全上只是其中的一個例子,聰明的你可能還有更好的使用場景,不妨分享出來。
參考資料
Addition (+):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
jsFuck: https://github.com/aemkei/jsfuck
JavaScript addition operator in details: https://rainsoft.io/javascriptss-addition-operator-demystified/
Why does ++[[]][+[]]+[+[]] return the string “10”?:https://stackoverflow.com/questions/7202157/why-does-return-the-string-10
