क्यों ++ [[]] [+ []] + [+ []] स्ट्रिंग "१०" लौटाते हैं?


1657

यह मान्य है और स्ट्रिंग "10"को जावास्क्रिप्ट में लौटाता है ( अधिक उदाहरण यहां ):

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

क्यों? यहां क्या हो रहा है?


446
यह समझकर शुरू करें कि +[]एक खाली सरणी को 0... फिर एक दोपहर बर्बाद ...;)
छल


10
Wtfjs.com पर एक नजर डालें - इसमें काफी कुछ चीजें ऐसी हैं जैसे कि एक्सप्लेनटिनोस
ThiefMaster

3
@ डेज़, आप उस तरह का सामान कहाँ से सीखते हैं? कौन सी किताबें? मैं
एमडीएन

6
@SiddharthThevaril जिस तरह से आपने अभी किया: किसी ने इसके बारे में कहीं पोस्ट किया और मैं इसे पढ़ने के लिए हुआ।
deceze

जवाबों:


2070

यदि हम इसे विभाजित करते हैं, तो गड़बड़ इसके बराबर होती है:

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

जावास्क्रिप्ट में, यह सच है कि +[] === 0+किसी चीज़ को संख्या में परिवर्तित करता है, और इस स्थिति में यह नीचे आएगा +""या 0(नीचे विनिर्देश विवरण देखें)।

इसलिए, हम इसे सरल बना सकते हैं (इस पर ++पहले से निर्भरता है +):

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

क्योंकि [[]][0]इसका अर्थ है: पहले तत्व को प्राप्त करें [[]], यह सच है कि:

[[]][0]आंतरिक सरणी ( []) लौटाता है । संदर्भों के कारण यह कहना गलत है [[]][0] === [], लेकिन चलो Aगलत नोटेशन से बचने के लिए आंतरिक सरणी को कॉल करें ।

++इससे पहले कि इसके ऑपरेंड का अर्थ है "एक के बाद एक वेतन वृद्धि और बढ़ा हुआ परिणाम लौटाएं"। तो (या ) के ++[[]][0]बराबर है ।Number(A) + 1+A + 1

फिर, हम गंदगी को और अधिक सुपाच्य बनाने में मदद कर सकते हैं। के []लिए वापस स्थानापन्न करें A:

(+[] + 1)
+
[0]

+[]सरणी को संख्या में समेटने से पहले 0, इसे पहले एक स्ट्रिंग में ले जाने की आवश्यकता होती है, जो कि ""फिर से है। अंत में, 1जोड़ा जाता है, जिसके परिणामस्वरूप 1

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

आइए इसे और भी सरल करें:

1
+
[0]

इसके अलावा, यह जावास्क्रिप्ट में सच है: [0] == "0"क्योंकि यह एक तत्व के साथ एक सरणी में शामिल हो रहा है। जुड़ने से अलग हुए तत्वों का संघटन होगा ,। एक तत्व के साथ, आप यह तर्क दे सकते हैं कि इस तर्क का परिणाम पहले तत्व में ही होगा।

इस मामले में, +दो ऑपरेंड देखता है: एक संख्या और एक सरणी। अब यह दोनों को एक ही प्रकार में ले जाने की कोशिश कर रहा है। सबसे पहले, सरणी को स्ट्रिंग में ले जाया जाता है "0", अगले, संख्या को एक स्ट्रिंग ( "1") में coerced किया जाता है । नंबर +स्ट्रिंग ===स्ट्रिंग

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

के लिए विशिष्टता विवरण +[]:

यह काफी भूलभुलैया है, लेकिन ऐसा करने के लिए +[], पहले इसे स्ट्रिंग में परिवर्तित किया जा रहा है क्योंकि यही +कहता है:

11.4.6 यूनरी + संचालक

Unary + ऑपरेटर अपने ऑपरेंड को संख्या प्रकार में परिवर्तित करता है।

उत्पादन UnaryExpression: + UnaryExpression का मूल्यांकन निम्नानुसार किया जाता है:

  1. UnrExpression के मूल्यांकन का परिणाम होने दें।

  2. ToNumber (GetValue (expr)) पर लौटें।

ToNumber() कहते हैं:

वस्तु

निम्नलिखित चरण लागू करें:

  1. PrimValue को ToPrimitive (इनपुट तर्क, संकेत स्ट्रिंग) होने दें।

  2. ToString (primValue) पर लौटें।

ToPrimitive() कहते हैं:

वस्तु

ऑब्जेक्ट के लिए एक डिफ़ॉल्ट मान लौटाएं। किसी वस्तु का डिफ़ॉल्ट मान [[DefaultValue]] आंतरिक विधि को कॉल करके प्राप्त किया जाता है, जो वैकल्पिक संकेत PreferredType से गुजरता है। [[DefaultValue]] आंतरिक पद्धति के व्यवहार को इस विनिर्देश द्वारा परिभाषित किया गया है जो M.१२. 8.1 में सभी देशी ECMAScript वस्तुओं के लिए है।

[[DefaultValue]] कहते हैं:

8.12.8 [[DefaultValue]] (संकेत)

जब [[DefaultValue]] O का आंतरिक तरीका संकेत स्ट्रिंग के साथ कहा जाता है, तो निम्नलिखित कदम उठाए जाते हैं:

  1. आज्ञा देना पुख्ता करने का परिणाम है [[जाओ]] तर्क के साथ ऑब्जेक्ट O की आंतरिक विधि "स्ट्रींग"।

  2. यदि IsCallable (inString) सत्य है, तो

ए। चलो [[कॉल]] toString की आंतरिक विधि को कॉल करने का परिणाम है, ओ के साथ यह मान और एक खाली तर्क सूची है।

ख। यदि str एक आदिम मान है, तो str वापस लौटें।

.toStringएक सरणी के का कहना है:

15.4.4.2 Array.prototype.toString ()

जब स्ट्रिंग विधि को कहा जाता है, तो निम्नलिखित कदम उठाए जाते हैं:

  1. इस मान पर ToObject को कॉल करने का परिणाम होने दें।

  2. चलिए फंक को [[शामिल हों] तर्क के साथ सरणी की आंतरिक विधि "जॉइन" कहते हैं।

  3. यदि IsCallable (func) गलत है, तो फंक को मानक निर्मित विधि Object.prototyp.toString (15.2.4.2) होने दें।

  4. कॉल करने के परिणाम को लौटाएँ [[कॉल]] इस मूल्य और खाली तर्क सूची के रूप में एफ़सीआर प्रदान करने की आंतरिक विधि।

तो +[]नीचे आता है +"", क्योंकि [].join() === ""

फिर से, इस +रूप में परिभाषित किया गया है:

11.4.6 यूनरी + संचालक

Unary + ऑपरेटर अपने ऑपरेंड को संख्या प्रकार में परिवर्तित करता है।

उत्पादन UnaryExpression: + UnaryExpression का मूल्यांकन निम्नानुसार किया जाता है:

  1. UnrExpression के मूल्यांकन का परिणाम होने दें।

  2. ToNumber (GetValue (expr)) पर लौटें।

ToNumberके रूप में परिभाषित किया ""गया है:

StringNumericLiteral का एमवी ::: [खाली] 0 है।

तो +"" === 0, और इस प्रकार +[] === 0


8
@ हार्पर: यह सख्त समानता चेकर है, अर्थात यह केवल तभी लौटता है trueजब मूल्य और प्रकार दोनों समान हों। 0 == ""रिटर्न true(एक ही प्रकार के रूपांतरण के बाद), लेकिन 0 === ""यह false(समान प्रकार नहीं)।
pimvdb

41
इसका हिस्सा सही नहीं है। अभिव्यक्ति को फोड़ा जाता है 1 + [0], नहीं "1" + [0], क्योंकि उपसर्ग ( ++) ऑपरेटर हमेशा एक नंबर देता है। Bclary.com/2004/11/07/#a-11.4.4
टिम डाउन

6
@ समय नीचे: आप पूरी तरह से सही हैं। मैं इसे ठीक करने की कोशिश कर रहा हूं, लेकिन जब मैं ऐसा करने की कोशिश कर रहा था तो मुझे कुछ और मिला। मुझे यकीन नहीं है कि यह कैसे संभव है। ++[[]][0]वास्तव में देता है 1, लेकिन ++[]एक त्रुटि फेंकता है। यह उल्लेखनीय है क्योंकि ऐसा लगता है कि ++[[]][0]नीचे उबाल आता है ++[]। क्या आपको शायद इस बात का कोई अंदाजा है कि ++[]कोई त्रुटि क्यों होती ++[[]][0]है जबकि ऐसा नहीं है?
pimvdb

11
@pimvdb: मुझे पूरा यकीन PutValueहै कि प्रीफ़िक्स ऑपरेशन में कॉल (ES3 शब्दावली में, 8.7.2) में समस्या है । PutValueएक संदर्भ की आवश्यकता है जबकि []एक अभिव्यक्ति अपने आप में एक संदर्भ का उत्पादन नहीं करती है। एक चर संदर्भ युक्त एक अभिव्यक्ति (कहते हैं कि हम पहले परिभाषित किया गया था var a = []तो ++aकाम करता है) या एक वस्तु (जैसे [[]][0]) की संपत्ति का उपयोग एक संदर्भ पैदा करता है। सरल शब्दों में, उपसर्ग ऑपरेटर न केवल एक मूल्य पैदा करता है, उसे उस मूल्य को डालने के लिए कहीं न कहीं आवश्यकता भी होती है।
टिम डाउन

13
@pimvdb: इसलिए निष्पादित करने के बाद var a = []; ++a, a1. निष्पादित करने के बाद ++[[]][0], [[]]एक्सप्रेशन द्वारा बनाई गई सरणी में अब इंडेक्स 0. में सिर्फ नंबर 1 होता है, ++ऐसा करने के लिए एक संदर्भ की आवश्यकता होती है।
टिम डाउन

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

फिर हमारे पास एक स्ट्रिंग समवर्ती है

1+[0].toString() = 10

7
इसके ===बजाय लिखने के लिए स्पष्ट नहीं होगा =>?
मतीन उलहाक

61

निम्नलिखित इस प्रश्न का उत्तर देने वाले ब्लॉग पोस्ट से अनुकूलित है जिसे मैंने पोस्ट किया था जबकि यह प्रश्न अभी भी बंद था। लिंक ECMAScript 3 युक्ति के (HTML प्रति) हैं, फिर भी आज के आमतौर पर उपयोग किए जाने वाले वेब ब्राउज़रों में जावास्क्रिप्ट के लिए आधार रेखा है।

सबसे पहले, एक टिप्पणी: इस तरह की अभिव्यक्ति किसी भी (साने) उत्पादन वातावरण में कभी नहीं दिखाई देने वाली है और यह केवल एक अभ्यास के रूप में किसी भी उपयोग के लिए है कि पाठक कितनी अच्छी तरह से जावास्क्रिप्ट के गंदे किनारों को जानता है। सामान्य सिद्धांत जो जावास्क्रिप्ट ऑपरेटरों को स्पष्ट रूप से प्रकारों के बीच परिवर्तित करते हैं, उपयोगी है, क्योंकि कुछ सामान्य रूपांतरण हैं, लेकिन इस मामले में बहुत विस्तार नहीं है।

अभिव्यक्ति ++[[]][+[]]+[+[]]शुरू में थोपने और अस्पष्ट लग सकती है, लेकिन वास्तव में अलग-अलग अभिव्यक्तियों में अपेक्षाकृत आसान है। नीचे मैंने स्पष्टता के लिए केवल कोष्ठक जोड़ा है; मैं आपको विश्वास दिलाता हूं कि वे कुछ भी नहीं बदल सकते हैं, लेकिन अगर आप यह सत्यापित करना चाहते हैं कि तब समूह ऑपरेटर के बारे में पढ़ने के लिए स्वतंत्र महसूस करें । इसलिए, अभिव्यक्ति को अधिक स्पष्ट रूप से लिखा जा सकता है

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

इसे तोड़कर, हम इसका +[]मूल्यांकन करके इसे सरल बना सकते हैं 0। अपने आप को संतुष्ट करने के लिए कि यह सच क्यों है, एकरी + संचालक की जाँच करें और थोड़े यातना भरे मार्ग का अनुसरण करें जो कि समाप्त होने वाले तमोप्रधान को खाली स्ट्रिंग में परिवर्तित कर देता है, जिसे बाद में ToNumber0 द्वारा बदल दिया जाता है । अब हम प्रत्येक उदाहरण के लिए स्थानापन्न कर सकते हैं :0+[]

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

पहले से ही सरल। जैसा ++[[]][0]कि, उपसर्ग वृद्धि वेतन संचालक ( ++) का एक संयोजन है , जो एकल तत्व के साथ एक सरणी को परिभाषित करने वाला एक सरणी शाब्दिक है जो स्वयं एक खाली सरणी है ( [[]]) और एक संपत्ति अभिगमक ( [0]) सरणी शाब्दिक द्वारा परिभाषित सरणी पर कहा जाता है।

तो, हम [[]][0]बस []और हम ++[], सही कर सकते हैं? वास्तव में, यह मामला नहीं है क्योंकि मूल्यांकन ++[]एक त्रुटि फेंकता है, जो शुरू में भ्रामक लग सकता है। हालाँकि, इस बारे में थोड़ा ++स्पष्ट हो जाता है कि प्रकृति स्पष्ट है: इसका उपयोग एक चर (जैसे ++i) या एक वस्तु संपत्ति (जैसे ++obj.count) बढ़ाने के लिए किया जाता है । न केवल यह एक मूल्य का मूल्यांकन करता है, यह कहीं न कहीं उस मूल्य को संग्रहीत भी करता है। के मामले में ++[], यह नए मूल्य (जो भी हो सकता है) को रखने के लिए कहीं नहीं है क्योंकि अद्यतन करने के लिए एक वस्तु संपत्ति या चर का कोई संदर्भ नहीं है। विशिष्ट शब्दों में, यह आंतरिक पुटवेल ऑपरेशन द्वारा कवर किया गया है , जिसे उपसर्ग वृद्धि वेतन संचालक द्वारा कहा जाता है।

तो फिर, क्या करता ++[[]][0]है? खैर, इसी तरह के तर्क से +[], आंतरिक सरणी में परिवर्तित हो जाता है 0और यह मान 1हमें अंतिम मूल्य देने के लिए बढ़ जाता है 10बाहरी सरणी में गुण का मान अद्यतन किया जाता है 1और संपूर्ण अभिव्यक्ति इसका मूल्यांकन करती है 1

यह हमें छोड़ देता है

1 + [0]

... जो अतिरिक्त ऑपरेटर का एक सरल उपयोग है । दोनों ऑपरेंड को पहले आदिम में परिवर्तित किया जाता है और यदि या तो आदिम मान एक स्ट्रिंग है, तो स्ट्रिंग संयोजन का प्रदर्शन किया जाता है, अन्यथा संख्यात्मक जोड़ किया जाता है। [0]धर्मान्तरित "0", इसलिए स्ट्रिंग संघनन का उपयोग किया जाता है, उत्पादन "10"

एक अंतिम एक तरफ के रूप में, कुछ है कि तुरंत स्पष्ट नहीं हो सकता है कि दोनों में से किसी एक अधिभावी है toString()या valueOf()करने के तरीकों Array.prototypeअभिव्यक्ति का परिणाम बदल जाएगा, क्योंकि दोनों की जाँच की और जब एक आदिम मूल्य में एक वस्तु परिवर्तित मौजूद होने पर किया जाता है। उदाहरण के लिए, निम्नलिखित

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

... का उत्पादन करता है "NaNfoo"। ऐसा क्यों होता है पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है ...


24

आइए इसे सरल बनाएं:

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

13

यह एक ही लेकिन थोड़ा छोटा मूल्यांकन करता है

+!![]+''+(+[])
  • [] - एक सरणी को परिवर्तित किया जाता है जिसे 0 में तब परिवर्तित किया जाता है जब आप इसे जोड़ते या घटाते हैं, इसलिए + [] = 0
  • [!] - असत्य का मूल्यांकन करता है, इसलिए इसलिए !! [] सत्य का मूल्यांकन करता है
  • + !! [] - सही को एक संख्यात्मक मान में परिवर्तित करता है जो सत्य का मूल्यांकन करता है, इसलिए इस मामले में 1
  • + '' - संख्या को स्ट्रिंग में बदलने के लिए अभिव्यक्ति के लिए एक खाली स्ट्रिंग जोड़ता है
  • + [] - 0 का मूल्यांकन करता है

इसलिए इसका मूल्यांकन किया जाता है

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

तो अब तुम मिल गया है, यह एक कोशिश:

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

खैर नहीं यह अभी भी "10" का मूल्यांकन करता है। हालाँकि यह इसे एक अलग तरीके से कर रहा है। क्रोम या किसी चीज़ जैसे जावास्क्रिप्ट इंस्पेक्टर में इसका मूल्यांकन करने की कोशिश करें।
व्लाद शोल्बर्ग

_ = $ = + [], ++ _ + '' + $ -> _ = $ = 0, ++ _ + '' + $ -> _ = 0, $ = 0, ++ _ + '' + $ -> ++ 0 + '' + 0 -> 1 + '' + 0 -> '10' // Yei: v
LeagueOfJava

एक ही करने के लिए यह एक मूल्यांकन करता है, लेकिन यह तुम्हारा से भी छोटा होता है:"10"
ADJenks

7

+ [] ० का मूल्यांकन करता है ... [...] फिर समन (+ ऑपरेशन) कुछ भी इसके साथ सरणी सामग्री को उसके स्ट्रिंग प्रतिनिधित्व में परिवर्तित करता है जिसमें अल्पविराम से जुड़े तत्व शामिल होते हैं।

ऐरे के इंडेक्स लेने जैसे कुछ भी (ऑपरेशन की तुलना में ग्रेटर प्राथमिकता है) क्रमिक है और कुछ भी दिलचस्प नहीं है।


4

शायद अंकों के बिना "10" में किसी अभिव्यक्ति का मूल्यांकन करने के सबसे कम संभव तरीके हैं:

+!+[] + [+[]] // "10"

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

// ========== स्पष्टीकरण ========== \\

+!+[]: +[]0. में !0रूपांतरित करता है true+true1. में परिवर्तित होता है -~[]= -(-1)जो 1 है

[+[]]: +[]0. [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]"

1
  1. यूनरी प्लस दिया गया स्ट्रिंग संख्या में परिवर्तित होता है
  2. वेतन वृद्धि संचालक द्वारा दिए गए स्ट्रिंग अभिसरण और वेतन वृद्धि 1
  3. [] == ''। खाली स्ट्रिंग
  4. + '' या + [] 0 का मूल्यांकन करता है।

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

1
उत्तर भ्रमित / भ्रमित है, IOW गलत है। []के बराबर नहीं है ""। पहले तत्व को निकाला जाता है, फिर उसके द्वारा परिवर्तित किया जाता है ++
प्वाइंटएयर्स

1

उस के कदम से कदम, +एक संख्या के लिए मूल्य और यदि आप एक खाली सरणी में जोड़ते हैं +[]... जैसा कि यह खाली है और इसके बराबर है 0, यह होगा

तो वहाँ से, अब अपने कोड में देखो, यह है ++[[]][+[]]+[+[]]...

और उनके बीच प्लस ++[[]][+[]]+ है[+[]]

तो ये [+[]]वापस आ जाएंगे [0]क्योंकि उनके पास एक खाली सरणी है जो 0दूसरे सरणी के अंदर परिवर्तित हो जाती है ...

तो जैसा कि कल्पना है, पहला मान 2-आयामी सरणी है जिसमें एक सरणी अंदर है ... इसलिए [[]][+[]]समान [[]][0]होगा जो वापस आ जाएगी []...

और अंत में ++इसे रूपांतरित करें और इसे बढ़ाएं 1...

तो आप कल्पना कर सकते हैं, 1+ "0"होगा "10"...

स्ट्रिंग "10" क्यों लौटाता है?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.