क्यों 0 [0] वाक्यात्मक रूप से मान्य है?


119

यह रेखा जावास्क्रिप्ट में क्यों मान्य है?

var a = 0[0];

उसके बाद, aहै undefined


4
as true[0]या ""[0]
हैकेटो

24
@CodeAngry निष्पक्ष होने के लिए जावास्क्रिप्ट एचटीएमएल के भीतर पैदा हुआ था, और यह एचटीएमएल है जिसने पूरे "कुछ भी आप मुझ पर फेंकना शुरू कर दिया है और मैं इसे समझने की कोशिश करूंगा"।
नीट द डार्क एबसोल

8
@NiettheDarkAbsol निष्पक्ष बनाने के लिए आप बस गलत रूप में वाक्य रचना कर रहे हैं करता है मेकअप भावना (अभी तक इतना नहीं)। यह सिर्फ "0"एक new Number(0)वस्तु के नाम संपत्ति है ।
मेन्ड्रे

यह एक गलत धारणा है कि हमेशा अपरिभाषित रहेगा। 0[0]एक मूल्य वापस करना पूरी तरह से संभव है
रुण एफएस

@meandre 0["toString"]यह कमाल है, इसे इंगित करने के लिए धन्यवाद।
जोनाथन

जवाबों:


169

जब आप करते हैं 0[0], तो जेएस दुभाषिया पहले वस्तु 0में बदल जाएगा Numberऔर फिर [0]उस वस्तु की संपत्ति तक पहुंचने का प्रयास करेगा undefined

कोई सिंटैक्स त्रुटि नहीं है क्योंकि 0[0]इस संदर्भ में भाषा व्याकरण द्वारा संपत्ति एक्सेस सिंटैक्स की अनुमति है। यह संरचना (जावास्क्रिप्ट व्याकरण में शर्तों का उपयोग) हैNumericLiteral[NumericLiteral]

ES5 ECMAScript युक्ति के खंड A.3 से भाषा व्याकरण का प्रासंगिक भाग यह है:

Literal ::
    NullLiteral
    BooleanLiteral
    NumericLiteral
    StringLiteral
    RegularExpressionLiteral

PrimaryExpression :
    this
    Identifier
    Literal
    ArrayLiteral
    ObjectLiteral
    ( Expression )

MemberExpression :
    PrimaryExpression
    FunctionExpression
    MemberExpression [ Expression ]
    MemberExpression . IdentifierName
    new MemberExpression Arguments    

तो, एक व्यक्ति इस प्रगति के माध्यम से व्याकरण का पालन कर सकता है:

MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]

और, इसी तरह Expressionअंतत: NumericLiteralव्याकरण का पालन करने के बाद भी हम ऐसा कर सकते हैं , हम देखते हैं कि इसकी अनुमति है:

NumericLiteral [ NumericLiteral ]

जिसका अर्थ है कि 0[0]यह व्याकरण का एक स्वीकृत हिस्सा है और इस प्रकार कोई वाक्यविन्यास नहीं है।


फिर, रन-टाइम में आपको एक ऐसी संपत्ति को पढ़ने की अनुमति होती है जो मौजूद नहीं होती है (इसे बस के रूप में पढ़ा जाएगा undefined ) जब तक आप जिस स्रोत से पढ़ रहे हैं वह एक वस्तु है या किसी वस्तु का अंतर्निहित रूपांतरण है। और, एक संख्यात्मक शाब्दिक वास्तव में एक वस्तु (एक संख्या वस्तु) के लिए एक अंतर्निहित रूपांतरण है।

यह जावास्क्रिप्ट की उन अज्ञात विशेषताओं में से एक है। प्रकार Number, BooleanऔरStringजावास्क्रिप्ट में आमतौर पर आंतरिक रूप से संग्रहीत होते हैं (पूर्ण-विकसित वस्तुएं नहीं)। ये एक कॉम्पैक्ट, अपरिवर्तनीय भंडारण प्रतिनिधित्व हैं (शायद कार्यान्वयन दक्षता के लिए इस तरह से किया गया है)। लेकिन, जावास्क्रिप्ट चाहता है कि आप इन प्राथमिकताओं का इलाज करने में सक्षम हों जैसे कि गुणों और विधियों के साथ। इसलिए, यदि आप किसी ऐसी संपत्ति या विधि का उपयोग करने की कोशिश करते हैं जो सीधे आदिम पर समर्थित नहीं है, तो जावास्क्रिप्ट अस्थायी रूप से आदिम के मूल्य के लिए निर्धारित मूल्य के साथ एक उपयुक्त प्रकार की वस्तु में आदिम को ले जाएगा।

जब आप किसी ऑब्जेक्ट को सिंटेक्स पर किसी प्राइमरी जैसे सिंटैक्स का उपयोग करते हैं 0[0], तो दुभाषिया एक प्राइमेट पर प्रॉपर्टी एक्सेस के रूप में इसे पहचानता है। इसके लिए इसकी प्रतिक्रिया पहले 0संख्यात्मक आदिम को लेना है और इसे एक पूर्ण विकसित Numberवस्तु में तब्दील करना है, जिस पर वह [0]संपत्ति का उपयोग कर सकता है । इस विशिष्ट मामले में, [0]एक संख्या वस्तु पर संपत्ति undefinedहै यही कारण है कि आप जिस मूल्य से प्राप्त करते हैं 0[0]

गुणों से निपटने के प्रयोजनों के लिए एक वस्तु के लिए एक आदिम के ऑटो-रूपांतरण पर यहां एक लेख है:

जावास्क्रिप्ट प्रिमिटिव्स का सीक्रेट लाइफ


यहाँ ECMAScript 5.1 विनिर्देशन के प्रासंगिक अंश दिए गए हैं:

9.10 CheckObjectCoercible

यदि मान है undefinedया नहीं null, तो TypeError फेंकता है , अन्यथा वापस लौटता है true

यहाँ छवि विवरण दर्ज करें

11.2.1 प्रॉपर्टी ऐक्सेसर्स

  1. बता दें कि BaseReference सदस्यExpression के मूल्यांकन का परिणाम है।
  2. BaseValue GetValue (BaseReference) होने दें।
  3. बता दें कि प्रॉपर्टीनामेप्रेशन एक्सप्रेशन के मूल्यांकन का परिणाम है।
  4. चलिए PropertyNameValue GetValue (संपत्तिनामप्रदर्शन) करें।
  5. CheckObjectCoercible (baseValue) को कॉल करें।
  6. चलिए PropertyNameString ToString (propertyNameValue) है।
  7. यदि वाक्य-रचना के उत्पादन का मूल्यांकन किया जा रहा है, तो वह सख्त मोड कोड में समाहित है, सख्त को सही होने दें, अन्यथा सख्त को गलत होने दें।
  8. प्रकार का संदर्भ लौटाएं जिसका आधार मान baseValue है और जिसका संदर्भित नाम गुणनाम है, और जिसका सख्त मोड ध्वज सख्त है।

इस प्रश्न के लिए एक ऑपरेटिव भाग ऊपर चरण # 5 है।

8.7.1 गेटवैल्यू (वी)

यह बताता है कि जब मूल्य का उपयोग किया जा रहा है तो यह एक संपत्ति संदर्भ है, यह ToObject(base)किसी भी आदिम का ऑब्जेक्ट संस्करण प्राप्त करने के लिए कहता है।

9.9 ToObject

यह वर्णन करता है कि कैसे Boolean, Numberऔर Stringआदिम वस्तु को [[PrimitiveValue]] आंतरिक संपत्ति के अनुसार वस्तु रूप में परिवर्तित किया जाता है।


एक दिलचस्प परीक्षण के रूप में, यदि कोड इस तरह था:

var x = null;
var a = x[0];

यह तकनीकी रूप से कानूनी वाक्यविन्यास के रूप में पार्स समय पर एक सिंटेक्सएयर को फेंक नहीं सकता है, लेकिन जब आप कोड चलाते हैं, तो यह रनटाइम पर एक टाइपऑर्डर को फेंक देगा क्योंकि जब उपरोक्त संपत्ति एक्सेसर्स लॉजिक मान पर लागू होता है x, तो यह कॉल CheckObjectCoercible(x)या कॉल करेगा ToObject(x)जो दोनों एक टाइपError फेंक देंगे अगर xहै nullया undefined


0[1,2]भी मान्य है, इसका क्या मतलब है? (मैं सवाल को अद्यतन करता हूं)
माइकल एम।

और यह एक सिंटैक्स त्रुटि नहीं बढ़ाता है, क्योंकि किसी भी चीज़ पर संपत्तियों तक पहुंचना nullया undefinedपूरी तरह से ठीक नहीं है, भले ही वे गुण मौजूद न हों।
user4642212

6
@Michael को अपडेट करने की आवश्यकता नहीं यही कारण है कि एक अल्पविराम ऑपरेटर है, तो यह सिर्फ है0[2]
अमित Joki

1
कोमा ऑपरेटर: 1 और 2 दोनों का मूल्यांकन करता है 1,2लेकिन रिटर्न 2.
user4642212

2
यह एक सवाल की बारीकियों के लिए इतना जबरदस्त जवाब है।
tbh__

20

अधिकांश प्रोग्रामिंग भाषाओं की तरह, जेएस आपके कोड को पार्स करने के लिए एक व्याकरण का उपयोग करता है और इसे एक निष्पादन योग्य रूप में परिवर्तित करता है। यदि व्याकरण में कोई नियम नहीं है जो कोड के किसी विशेष भाग पर लागू किया जा सकता है, तो यह एक सिंटैक्सएर्रोर फेंकता है। अन्यथा, कोड को वैध माना जाता है, भले ही यह समझ में आता हो या नहीं।

जेएस व्याकरण के प्रासंगिक भाग हैं

Literal :: 
   NumericLiteral
   ...

PrimaryExpression :
   Literal
   ...

MemberExpression :
   PrimaryExpression
   MemberExpression [ Expression ]
   ...

चूंकि 0[0]इन नियमों के अनुरूप है, इसलिए इसे एक वैध अभिव्यक्ति माना जाता है । क्या यह सही है (जैसे कि रन टाइम में कोई त्रुटि नहीं है) एक और कहानी है, लेकिन हाँ यह है। इस तरह से JS भावों का मूल्यांकन करता है someLiteral[someExpression]:

  1. मूल्यांकन someExpression(जो मनमाना जटिल हो सकता है)
  2. शाब्दिक को संबंधित वस्तु प्रकार में परिवर्तित करें (संख्यात्मक शाब्दिक => Number, तार => Stringआदि)
  3. get propertyसंपत्ति के नाम परिणाम (1) के साथ परिणाम (2) पर ऑपरेशन को बुलाओ
  4. परिणाम छोड़ें (2)

तो के 0[0]रूप में व्याख्या की है

index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result

यहाँ एक मान्य , लेकिन गलत अभिव्यक्ति का उदाहरण दिया गया है :

null[0]

यह ठीक है, लेकिन रन समय में, दुभाषिया चरण 2 पर विफल रहता है (क्योंकि nullकिसी ऑब्जेक्ट में परिवर्तित नहीं किया जा सकता है) और रन टाइम त्रुटि फेंकता है।


1
इसके अलावा और भी बहुत कुछ है। var x = null; var a = x[0];एक सिंटैक्स त्रुटि उत्पन्न नहीं करता है, लेकिन रनटाइम पर टाइपError फेंक देता है।
jfriend00

@ jfriend00: ऐसा नहीं है कि सवाल क्या था, लेकिन जोड़ा गया।
जॉर्ज

परिणाम अपरिभाषित नहीं है। 0[0]अपरिभाषित के बजाय एक मूल्य वापस करने के लिए संभव है
Rune FS

9

ऐसी स्थितियाँ हैं जहाँ आप जावास्क्रिप्ट में किसी संख्या को वैध रूप से कम कर सकते हैं:

-> 0['toString']
function toString() { [native code] }

हालांकि तुरंत स्पष्ट नहीं है कि आप ऐसा क्यों करना चाहते हैं, जावास्क्रिप्ट में सबस्क्रिप्टिंग बिंदीदार संकेतन का उपयोग करने के बराबर है (यद्यपि डॉट नोटेशन आपको पहचानकर्ताओं को कुंजी के रूप में उपयोग करने के लिए सीमित करता है)।


@AmitJoki यह (0).toString(फ़ंक्शन को कॉल किए बिना) के समान है। यह संख्या प्रकार की एक संपत्ति है।
user4642212

@AmitJoki क्योंकि यह सवाल का जवाब देता है कि 'यह लाइन वैध क्यों है'।
डंकन

@ डंकन, लेकिन यह "क्या ब्रैकेट नोटेशन" है और मुझे लगता है कि ओपी इसे जानता है। तथ्य यह है कि इसे नंबर ऑब्जेक्ट के रूप में व्याख्या की जाती है और फिर इसकी 0संपत्ति तक पहुंच होती है और चूंकि यह मौजूद नहीं है, इसलिए undefinedयह अधिक सही है जैसा कि jfriend00 में बताया गया है।
अमित जोकी

@AmitJoki यह एक गलत धारणा है जो 0[0]अपरिभाषित वापस आ जाएगी। यह संभावना है कि यह होगा, लेकिन यह मामला होना जरूरी नहीं है
रूण FS

9

मैं यह नोट करना चाहूंगा कि यह वैध सिंटैक्स किसी भी तरह से जावास्क्रिप्ट के लिए अद्वितीय नहीं है। अधिकांश भाषाओं में एक रनटाइम त्रुटि या एक प्रकार की त्रुटि होगी, लेकिन यह सिंटैक्स त्रुटि के समान नहीं है। जावास्क्रिप्ट कई स्थितियों में अपरिभाषित लौटने का विकल्प चुनता है जहां एक अन्य भाषा एक अपवाद को शामिल कर सकती है, जिसमें एक वस्तु को सब्मिट करना शामिल है जिसमें दिए गए नाम की संपत्ति नहीं है।

वाक्यविन्यास एक अभिव्यक्ति के प्रकार (एक संख्यात्मक शाब्दिक की तरह एक सरल अभिव्यक्ति) को भी नहीं जानता है, और आपको किसी भी ऑपरेटर को किसी भी अभिव्यक्ति पर लागू करने की अनुमति देगा। उदाहरण के लिए, जावास्क्रिप्ट में सबस्क्रिप्ट undefinedया nullकारणों का प्रयास TypeError। यह एक सिंटैक्स त्रुटि नहीं है - यदि इसे कभी भी निष्पादित नहीं किया जाता है (अगर-स्टेटमेंट के गलत पक्ष पर), तो यह किसी भी समस्या का कारण नहीं होगा, जबकि एक सिंटैक्स त्रुटि हमेशा संकलन समय (निष्कासन, कार्य, आदि) में पकड़ी गई है। , सभी संकलन के रूप में)।


8

क्योंकि यह मान्य वाक्यविन्यास है, और यहां तक ​​कि मान्य कोड की व्याख्या भी की जा सकती है। आप किसी भी वस्तु की किसी भी संपत्ति का उपयोग करने का प्रयास कर सकते हैं (और इस स्थिति में 0 को एक संख्या-वस्तु पर डाल दिया जाएगा), और यह आपको मूल्य देगा यदि यह मौजूद है, अन्यथा अपरिभाषित। अपरिभाषित की एक संपत्ति तक पहुँचने की कोशिश हालांकि काम नहीं करती है, इसलिए 0 [0] [0] एक परिणामी त्रुटि होगी। यह अभी भी मान्य सिंटैक्स के रूप में वर्गीकृत किया जाएगा। मान्य सिंटैक्स क्या है और क्या रनटाइम / कंपाइलटाइम त्रुटियों का कारण नहीं होगा इसका अंतर है।


3

न केवल वाक्यविन्यास मान्य है, परिणाम undefinedहालांकि ज्यादातर में नहीं होता है, अगर सभी लेन मामले नहीं होंगे। जेएस सबसे शुद्ध वस्तु उन्मुख भाषाओं में से एक है। अधिकांश तथाकथित OO भाषाएं क्लास ओरिएंटेड होती हैं, इस अर्थ में कि आप एक बार बनाए गए ऑब्जेक्ट का फॉर्म (यह क्लास से बंधा हुआ) नहीं बदल सकते हैं, केवल ऑब्जेक्ट की स्थिति। जेएस में आप वस्तु के रूप के साथ-साथ राज्य को बदल सकते हैं और यह आप जितना सोचते हैं उससे अधिक बार करते हैं। यदि आप इसका दुरुपयोग करते हैं, तो यह क्षमता कुछ अस्पष्ट कोड के लिए बनाती है। अंक अपरिवर्तनीय हैं, इसलिए आप ऑब्जेक्ट को स्वयं नहीं बदल सकते हैं, न ही यह स्थिति है और न ही यह ऐसा रूप है जिससे आप कर सकते हैं

0[0] = 1;

जो एक मान्य असाइनमेंट अभिव्यक्ति है जो 1 देता है लेकिन वास्तव में कुछ भी असाइन नहीं करता है, अंक 0अपरिवर्तनीय है। जो अपने आप में कुछ विषम है। आपके पास एक मान्य और सही (निष्पादन योग्य) वर्गीकरण अभिव्यक्ति हो सकती है, जो कुछ भी (*) असाइन नहीं करती है। हालाँकि अंक का प्रकार एक उत्परिवर्तित वस्तु है, ताकि आप इस प्रकार को उत्परिवर्तित कर सकें, और परिवर्तन प्रोटोटाइप श्रृंखला को नीचे ले जाएंगे।

Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]); 

बेशक यह उपयोग की श्रेणी से बहुत दूर रो रहा है लेकिन भाषा इसके लिए अनुमति देने के लिए निर्दिष्ट है क्योंकि अन्य परिदृश्यों में, वास्तव में वस्तुओं की क्षमताओं का विस्तार करना बहुत मायने रखता है। उदाहरण के लिए यह jQuery प्लग-इन jQuery ऑब्जेक्ट में हुक कैसे है।

(*) यह वास्तव में किसी वस्तु की संपत्ति के लिए मूल्य 1 प्रदान करता है, हालाँकि ऐसा कोई तरीका नहीं है जिससे आप उस (ट्रांसजेंडर) वस्तु को संदर्भित कर सकें और इसे इस प्रकार से इकट्ठा किया जाएगा


3

जावास्क्रिप्ट में, सब कुछ वस्तु है, इसलिए जब दुभाषिया इसे पार्स करता है, तो यह 0 को एक वस्तु के रूप में मानता है और 0 को संपत्ति के रूप में वापस करने की कोशिश करता है। जब आप सच्चे या "" (रिक्त स्ट्रिंग) के 0 वें तत्व तक पहुँचने का प्रयास करते हैं तो वही बात होती है।

यहां तक ​​कि अगर आप 0 [0] = 1 सेट करते हैं, तो यह संपत्ति और उसके मूल्य को मेमोरी में सेट करेगा, लेकिन जब आप 0 तक पहुंचते हैं तो यह एक नंबर के रूप में व्यवहार करता है (यहां ऑब्जेक्ट और नंबर के रूप में इलाज के बीच भ्रमित न हों।)

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