जावास्क्रिप्ट >>> ऑपरेटर क्या है और आप इसका उपयोग कैसे करते हैं?


150

मैं मोज़िला के कोड को देख रहा था जो कि ऐरे के लिए एक फिल्टर विधि जोड़ता है और इसमें कोड की एक पंक्ति थी जो मुझे भ्रमित करती थी।

var len = this.length >>> 0;

मैंने पहले कभी जावास्क्रिप्ट में उपयोग किए गए >>> को नहीं देखा है।
यह क्या है और यह क्या करता है?


@ सीएमएस सच, यह कोड / सवाल उन लोगों से आता है; हालाँकि, यहाँ की प्रतिक्रिया पहले की तुलना में अधिक विशिष्ट और मूल्यवान है।
जस्टिन जॉनसन

2
या यह एक बग या मोज़िला लोग मान रहे हैं। यह -1 हो सकता है। >>> अहस्ताक्षरित शिफ्ट ऑपरेटर है इसलिए var len हमेशा 0 या अधिक होगा।
user347594

1
ऐश Searle इसके लिए एक प्रयोग में पाया गया - करने के कार्यान्वयन जे एस (डौग Crockford) का स्वामी उथलनेवाला Array.prototype.push/ Array.prototype.pop- hexmen.com/blog/2006/12/push-and-pop (हालांकि वह परीक्षण, haha किया)।
डैन बीम

जवाबों:


211

यह केवल गैर-संख्याओं को संख्या में परिवर्तित नहीं करता है, यह उन्हें संख्याओं में परिवर्तित करता है जिन्हें 32-बिट अहस्ताक्षरित इनट्स के रूप में व्यक्त किया जा सकता है।

हालांकि JavaScript की संख्या डबल परिशुद्धता तैरता (*), बिटवाइज़ ऑपरेटर्स हैं ( <<, >>, &, |और ~) 32-बिट पूर्णांकों पर संचालन के संदर्भ में परिभाषित कर रहे हैं। एक बिटवाइज़ ऑपरेशन करना संख्या को 32-बिट हस्ताक्षरित इंट में परिवर्तित करता है, गणना करने से पहले 32 से किसी भी अंश और उच्च-स्थान के बिट्स को खो देता है और फिर वापस संख्या में परिवर्तित होता है।

तो बिना किसी वास्तविक प्रभाव के एक बिटवाइज़ ऑपरेशन करना, जैसे 0 बिट्स की राइट-शिफ्ट >>0, एक नंबर राउंड करने का एक त्वरित तरीका है और यह सुनिश्चित करना है कि यह 32-बिट इंट रेंज में है। इसके अतिरिक्त, ट्रिपल >>>ऑपरेटर, अपने अहस्ताक्षरित ऑपरेशन को करने के बाद, अपनी गणना के परिणामों को दूसरे के हस्ताक्षरित पूर्णांक के बजाय एक अहस्ताक्षरित पूर्णांक के रूप में परिवर्तित करता है, इसलिए इसका उपयोग नकारात्मक को 32-बिट-टू-सप्लीमेंट में परिवर्तित करने के लिए किया जा सकता है। एक बड़ी संख्या के रूप में संस्करण। का उपयोग करते हुए >>>0यह सुनिश्चित करती है 0 और 0xFFFFFFFF के बीच एक पूर्णांक मिल गया है।

इस मामले में यह उपयोगी है क्योंकि ECMAScript 32 बिट अहस्ताक्षरित ints के संदर्भ में सरणी अनुक्रमित को परिभाषित करता है। तो अगर आप array.filterएक तरह से लागू करने की कोशिश कर रहे हैं जो वास्तव में ECMAScript पांचवें संस्करण के मानक को डुप्लिकेट करता है, तो आप संख्या को इस तरह 32-बिट अहस्ताक्षरित इंट में डाल देंगे।

(वास्तविकता में इसके लिए थोड़ा व्यावहारिक जरूरत है उम्मीद है कि लोगों की स्थापना करने के लिए नहीं जा रहे हैं के रूप में array.lengthकरने के लिए 0.5, -1, 1e21या 'LEMONS'। लेकिन इस जावास्क्रिप्ट लेखकों के बारे में हम बात कर रहे हैं तो आप कभी पता नहीं है, ...)

सारांश:

1>>>0            === 1
-1>>>0           === 0xFFFFFFFF          -1>>0    === -1
1.7>>>0          === 1
0x100000002>>>0  === 2
1e21>>>0         === 0xDEA00000          1e21>>0  === -0x21600000
Infinity>>>0     === 0
NaN>>>0          === 0
null>>>0         === 0
'1'>>>0          === 1
'x'>>>0          === 0
Object>>>0       === 0

(*: ठीक है, वे फ़्लोट्स की तरह व्यवहार करने के रूप में परिभाषित किए गए हैं। यह मुझे आश्चर्यचकित नहीं करेगा अगर कुछ जावास्क्रिप्ट इंजन वास्तव में प्रदर्शन के कारणों के लिए जब यह उपयोग कर सकते हैं, लेकिन यह एक कार्यान्वयन विवरण होगा जिसे आपको लेने की आवश्यकता नहीं होगी। का लाभ।)


2
+2 गहराई विवरण और तालिका में, -1 क्योंकि array.length खुद को मान्य करता है और मनमाने ढंग से ऐसी किसी भी चीज़ के लिए सेट नहीं किया जा सकता है जो पूर्णांक या 0 नहीं है (FF इस त्रुटि को फेंकता है:) RangeError: invalid array length
जस्टिन जॉनसन

4
हालाँकि, युक्ति जानबूझकर कई ऐरे कार्यों को गैर-एरे (उदाहरण के माध्यम से Array.prototype.filter.call) पर बुलाया जा arrayसकता है , इसलिए यह वास्तव में वास्तविक Arrayनहीं हो सकता है: यह कुछ अन्य उपयोगकर्ता-परिभाषित वर्ग हो सकता है। (दुर्भाग्य से, यह मज़बूती से एक नोडलिस्ट नहीं हो सकता है, जो तब है जब आप वास्तव में ऐसा करना चाहेंगे, क्योंकि यह एक मेजबान वस्तु है। यह एकमात्र ऐसी जगह है जो आप वास्तविक रूप से argumentsछद्म-ऐरे के रूप में करेंगे ।)
बॉब

महान व्याख्या और महान उदाहरण! दुर्भाग्य से यह जावास्क्रिप्ट का एक और पागल पहलू है। मुझे यह समझ में नहीं आता है कि जब आप गलत प्रकार प्राप्त करते हैं तो एक त्रुटि को फेंकने के बारे में क्या भयानक है। टाइपिंग कास्टिंग बनाने के लिए हर आकस्मिक गलती की अनुमति के बिना गतिशील टाइपिंग की अनुमति देना संभव है। :(
माइक विलियमसन

">>> 0 का उपयोग करना सुनिश्चित करता है कि आपको 0 और 0xFFFFFFFF के बीच पूर्णांक मिला है।" ifजब मूल्यांकन के बाईं ओर एक इंट नहीं था, तो यह पहचानने की कोशिश करने के लिए कि कथन इस तरह क्या होगा ? 'lemons'>>>0 === 0 && 0 >>>0 === 0सच के रूप में मूल्यांकन करता है? भले ही नींबू स्पष्ट रूप से एक शब्द है ..?
ज़ेज़

58

अहस्ताक्षरित सही शिफ्ट ऑपरेटर का उपयोग मोज़िला के सभी ऐरे अतिरिक्त तरीके के कार्यान्वयन में किया जाता है, यह सुनिश्चित करने के लिए कि lengthसंपत्ति एक अहस्ताक्षरित 32-बिट पूर्णांक है

lengthसरणी ऑब्जेक्ट्स की संपत्ति विनिर्देश में वर्णित है:

प्रत्येक ऐरे ऑब्जेक्ट में एक लंबाई गुण होता है जिसका मान हमेशा एक गैर-पूर्णांक 2 से कम 32 होता है

यह ऑपरेटर इसे प्राप्त करने का सबसे छोटा तरीका है, आंतरिक रूप से सरणी विधियां ToUint32ऑपरेशन का उपयोग करती हैं , लेकिन यह विधि सुलभ नहीं है और कार्यान्वयन उद्देश्यों के लिए विनिर्देश पर मौजूद है।

मोज़िला सरणी एक्स्ट्रा इम्प्लीमेंटेशन ECMAScript 5 के अनुरूप होने की कोशिश करते हैं, के विवरण को देखेंArray.prototype.indexOf इम्प्लीमेंटेशन विधि (4 15.4.4.14):

1. चलो O इस मान को पास करने वाले ToObject को कॉल करने का परिणाम है 
   तर्क के रूप में।
2. चलो lenValue O के साथ [[प्राप्त करें]] आंतरिक विधि को कॉल करने का परिणाम है 
   तर्क "लंबाई"।
3. चलो ToUint32 (lenValue) हो ।
....

जैसा कि आप देख सकते हैं, वे सिर्फ ToUint32ES3 कार्यान्वयन पर ES5 कल्पना के अनुपालन के लिए विधि के व्यवहार को पुन: पेश करना चाहते हैं , और जैसा कि मैंने पहले कहा, अहस्ताक्षरित सही शिफ्ट ऑपरेटर सबसे आसान तरीका है।


हालांकि लिंक किए गए एरे एक्स्ट्रा एक्स्ट्रा इम्प्लीमेंट सही हो सकते हैं (या राइट के करीब) कोड अभी भी एक बुरा कोड उदाहरण है। शायद इरादे स्पष्ट करने के लिए एक टिप्पणी भी इस स्थिति को हल करेगी।
fmark

2
क्या यह संभव है कि किसी सरणी की लंबाई पूर्णांक नहीं है ? मैं इसकी कल्पना नहीं कर सकता, इसलिए इस तरह का ToUint32मुझे थोड़ा अनावश्यक लगता है।
मार्सेल कोर्पल

7
@ मार्सेल: ध्यान रखें कि अधिकांश Array.prototypeविधियां जानबूझकर सामान्य हैं , उनका उपयोग सरणी जैसी वस्तुओं पर किया जा सकता है Array.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;argumentsवस्तु भी एक अच्छा उदाहरण है। के लिए शुद्ध सरणी वस्तुओं, इसके बारे में प्रकार बदलने के लिए असंभव है length, संपत्ति, क्योंकि वे एक विशेष लागू [[Put ]] आंतरिक विधि, और एक काम करने के लिए किया जाता है जब lengthसंपत्ति, फिर से परिवर्तित है ToUint32और अन्य कार्यों के ऊपर अनुक्रमित हटाने जैसे लिया जाता है, नई लंबाई ...
CMS

32

यह अहस्ताक्षरित सही बिट शिफ्ट ऑपरेटर है। इस और हस्ताक्षरित राइट बिट शिफ्ट ऑपरेटर के बीच का अंतर यह है कि अहस्ताक्षरित राइट बिट शिफ्ट ऑपरेटर ( >>> ) बाईं ओर से शून्य से भरता है, और हस्ताक्षरित राइट बिट शिफ्ट ऑपरेटर ( >> ) साइन बिट के साथ भरता है, इस प्रकार स्थानांतरित होने पर संख्यात्मक मान का संकेत संरक्षित करना।


इवान, जो इसे 0 स्थानों पर स्थानांतरित करेगा; वह कथन कुछ भी नहीं बदलेगा।
डीन जे

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

2
@ इवान, नीचे जस्टिन का जवाब देखें। यह वास्तव में यह सुनिश्चित करने का एक तरीका है कि लेन चर में एक संख्या होती है।
ड्रिस

1
इसके अलावा, >>>एक पूर्णांक में परिवर्तित हो जाता है, जो एकात्मक +नहीं करता है।
पुनरावर्ती

this.length >>> 0 एक हस्ताक्षरित पूर्णांक को एक अहस्ताक्षरित में कनवर्ट करता है। व्यक्तिगत रूप से मुझे यह उपयोगी मिला है जब इसमें अहस्ताक्षरित ints के साथ एक बाइनरी फ़ाइल लोड करना।
मैट पार्किंस

29

ओपेरिस ने पर्याप्त रूप से समझाया है कि ऑपरेटर क्या है और यह क्या करता है। यहाँ इसके पीछे का अर्थ है / इसका उपयोग क्यों किया गया था:

द्वारा किसी भी दिशा स्थानांतरण 0रिटर्न मूल संख्या करता है और कच्चा जाएगा nullकरने के लिए 0। ऐसा लगता है कि आप जिस उदाहरण कोड को देख रहे हैं, वह this.length >>> 0सुनिश्चित करने के लिए उपयोग कर रहा है कि lenभले ही वह संख्यात्मक होthis.length परिभाषित नहीं होने पर है।

कई लोगों के लिए, बिटवाइज़ ऑपरेशन अस्पष्ट हैं (और डगलस क्रॉकफोर्ड / जेस्लिंट ऐसी चीजों का उपयोग करने के खिलाफ सुझाव देते हैं)। इसका मतलब यह नहीं है कि ऐसा करना गलत है, लेकिन कोड को अधिक पठनीय बनाने के लिए अधिक अनुकूल और परिचित तरीके मौजूद हैं। यह सुनिश्चित करें कि एक और अधिक स्पष्ट रास्ता lenहै 0निम्न दो किसी भी विधि का है।

// Cast this.length to a number
var len = +this.length;

या

// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0; 

1
हालाँकि, आपका दूसरा समाधान कभी-कभी NaN.. का मूल्यांकन करेगा +{}... जैसे ... यह शायद दो को संयोजित करने के लिए सबसे अच्छा है:+length||0
जेम्स

1
यह। सरणी सरणी ऑब्जेक्ट के संदर्भ में है, जो एक गैर-नकारात्मक पूर्णांक (कम से कम एफएफ) के अलावा कुछ भी नहीं हो सकता है, इसलिए यह यहां एक संभावना नहीं है। इसके अलावा, {} || 1 रिटर्न {} तो आप कोई बेहतर नहीं हैं अगर यह। वस्तु है। पहली विधि में भी कास्टिंग करने का लाभ यह है कि यह उन मामलों को संभालता है जहां यह गति NaN है। यह प्रदर्शित करने के लिए संपादित प्रतिक्रिया।
22 जॉन में जस्टिन जॉनसन

jslint var len = + this.length के बारे में "भ्रामक उपद्रवों" के बारे में शिकायत करेगा। डगलस, तुम बहुत picky!
बेयर्ड रैंडेल

डगलस पिकी है। और जब उसके तर्क समझदार होते हैं और आम तौर पर अच्छी तरह से स्थापित होते हैं, तो वह जो कहता है वह निरपेक्ष नहीं है और न ही सुसमाचार।
जस्टिन जॉनसन

15

>>>है अहस्ताक्षरित सही पारी ऑपरेटर ( पी देखते हैं। जावास्क्रिप्ट 1.5 विनिर्देश के 76 ), के रूप में करने का विरोध किया >>, पर हस्ताक्षर किए सही पारी ऑपरेटर।

>>>नकारात्मक संख्याओं को स्थानांतरित करने के परिणामों को बदलता है क्योंकि यह स्थानांतरण करते समय साइन बिट को संरक्षित नहीं करता है । इसके परिणामों को एक उदाहरण से समझा जा सकता है:

$ 1 >> 0
1
$ 0 >> 0
0
$ -1 >> 0
-1
$ 1 >>> 0
1
$ 0 >>> 0
0
$ -1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
$ "cabbage" >>> 0
0

तो क्या किया जा सकता है, इसका उद्देश्य यहाँ लंबाई प्राप्त करना है, या 0 यदि लंबाई अपरिभाषित है या पूर्णांक नहीं है, तो "cabbage"ऊपर दिए गए उदाहरण के अनुसार। मुझे लगता है कि इस मामले में यह मान लेना सुरक्षित है कि this.lengthयह कभी नहीं होगा < 0। फिर भी, मैं तर्क दूंगा कि यह उदाहरण दो कारणों से एक बुरा हैक है:

  1. <<<नकारात्मक संख्याओं का उपयोग करते समय व्यवहार , एक साइड-इफ़ेक्ट शायद उपरोक्त उदाहरण में इरादा (या होने की संभावना) नहीं है।

  2. कोड का इरादा स्पष्ट नहीं है , क्योंकि इस सवाल का अस्तित्व सत्यापित करता है।

जब तक प्रदर्शन बिल्कुल महत्वपूर्ण न हो, तब तक सर्वोत्तम अभ्यास संभवतः कुछ अधिक पठनीय का उपयोग करना है:

isNaN(parseInt(foo)) ? 0 : parseInt(foo)

सू ... @ जोंकफ़िश सही है? यह सुनिश्चित करना है कि। गैर-ऋणात्मक है?
एंथनी

4
क्या -1 >>> 0कभी ऐसा हो सकता है और यदि ऐसा है, तो क्या इसे 4294967295 पर स्थानांतरित करना वास्तव में वांछनीय है? ऐसा लगता है कि लूप को आवश्यकता से कुछ अधिक बार चलाने का कारण होगा।
deceze

@ डिडेज़: इसके कार्यान्वयन को देखे बिना this.lengthयह जानना असंभव है। किसी भी "साने" कार्यान्वयन के लिए एक स्ट्रिंग की लंबाई कभी भी नकारात्मक नहीं होनी चाहिए, लेकिन फिर एक तर्क हो सकता है कि "साने" वातावरण में हम एक this.lengthसंपत्ति के अस्तित्व को मान सकते हैं जो हमेशा एक अभिन्न संख्या देता है।
fmark

आप कहते हैं कि >>> साइन बिट को संरक्षित नहीं करता है .. ठीक है .. इसलिए, मुझे पूछना होगा, जब हम नकारात्मक संख्याओं से निपटते हैं .. किसी भी >>> या >> रूपांतरण से पहले, क्या वे 2s शिकायत में हैं फ़ॉर्म, या वे पूर्णांक रूप में हस्ताक्षर किए गए हैं, और हमें कैसे पता चलेगा? वैसे, 2s पूरक मुझे लगता है कि शायद एक संकेत बिट के लिए नहीं कहा जाता है .. यह हस्ताक्षरित अंकन का एक विकल्प है, लेकिन पूर्णांक के संकेत को निर्धारित करना संभव है
बार्लोप

10

दो कारण:

  1. >>> का परिणाम एक "अभिन्न" है

  2. अपरिभाषित >>> 0 = 0 (क्योंकि जेएस कोशिश करेगा और एलएफएस को संख्यात्मक संदर्भ के लिए बाध्य करेगा, यह "फू" >>> 0, आदि के लिए भी काम करेगा)

याद रखें कि JS में संख्याओं का आंतरिक-प्रतिनिधित्व दोगुना है। यह लंबाई के लिए बुनियादी इनपुट पवित्रता का सिर्फ एक "त्वरित" तरीका है।

हालांकि , -1 >>> 0 (उफ़, संभवतः वांछित लंबाई नहीं है!)


0

नीचे दिए गए नमूना जावा कोड अच्छी तरह से बताते हैं:

int x = 64;

System.out.println("x >>> 3 = "  + (x >>> 3));
System.out.println("x >> 3 = "  + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));

आउटपुट निम्नलिखित है:

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