javascript - आईड - विज्ञान तर्क




++[[]][+[]]+[+[]] स्ट्रिंग "10" क्यों देता है? (6)

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

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

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


  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
    

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

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


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

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

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

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

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

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

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

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

पहले से ही सरल ++[[]][0] , यह bclary.com/2004/11/07/#a-11.4.4 ( ++ ) का संयोजन है, एक सरणी bclary.com/2004/11/07/#a-11.4.4 एक एकल तत्व के साथ एक सरणी को परिभाषित करता है जो स्वयं एक खाली सरणी है ( [[]] ) और एक संपत्ति एक्सेसर ( [0] ) सरणी शाब्दिक द्वारा परिभाषित सरणी पर बुलाया।

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

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

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

1 + [0]

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

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

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

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


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

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

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

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

+!+[] : +[] !0 परिवर्तित हो जाता true !0 परिवर्तित हो जाता true+true कनवर्ट 1 -~[] = -(-1) जो 1 है

[+[]] : +[] [0] जाता है। [0] एक तत्व है जिसमें एक तत्व 0 है।

फिर जेएस 1 + [0] मूल्यांकन करता है, इस प्रकार Number + Array अभिव्यक्ति। फिर ईसीएमए विनिर्देश काम करता है: + ऑपरेटर आधार Object प्रोटोटाइप से toString()/valueOf() फ़ंक्शंस को कॉल करके दोनों ऑपरेटरों को एक स्ट्रिंग में परिवर्तित करता है। यह एक अभिव्यक्ति समारोह के रूप में कार्य करता है यदि अभिव्यक्ति के दोनों संचालन केवल संख्याएं हैं। चाल यह है कि सरणी आसानी से अपने तत्वों को एक समेकित स्ट्रिंग प्रतिनिधित्व में परिवर्तित करते हैं।

कुछ उदाहरण:

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

एक अच्छा अपवाद है कि NaN में दो Objects अतिरिक्त परिणाम:

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

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

फिर हमारे पास एक स्ट्रिंग कॉन्सटेनेशन है

1+[0].toString() = 10




syntax