Array.prototype.slice.call () कैसे काम करता है?


474

मुझे पता है कि इसका उपयोग तर्कों को एक वास्तविक सरणी बनाने के लिए किया जाता है, लेकिन मुझे समझ में नहीं आता है कि उपयोग करते समय क्या होता है Array.prototype.slice.call(arguments)


2
^ थोड़ा अलग है क्योंकि वह लिंक DOM नोड्स के बारे में पूछता है और तर्क नहीं। और मुझे लगता है कि 'यह' आंतरिक रूप से क्या है, इसका वर्णन करने से यहाँ उत्तर बहुत बेहतर है।
वर्गम

जवाबों:


870

हुड के नीचे क्या होता है कि जब .slice()सामान्य रूप से कहा जाता है, thisएक ऐरे है, और फिर यह उस एरे पर निर्भर करता है, और अपना काम करता है।

कैसे है thisमें .slice()किसी सरणी समारोह? क्योंकि जब आप करते हैं:

object.method();

... objectस्वतः ही का मूल्य बन जाता thisहै method()। के साथ:

[1,2,3].slice()

... का [1,2,3]मान सेट किया गया thisहै .slice()


लेकिन क्या होगा यदि आप thisमूल्य के रूप में कुछ और स्थानापन्न कर सकते हैं ? जब तक आप जो भी विकल्प देते हैं उसमें एक संख्यात्मक .lengthसंपत्ति होती है, और गुणों का एक गुच्छा जो संख्यात्मक सूचकांक होते हैं, यह काम करना चाहिए। इस प्रकार की वस्तु को अक्सर एक सरणी जैसी वस्तु कहा जाता है ।

.call()और .apply()तरीकों आप जाने मैन्युअल का मान सेट thisएक समारोह में। इसलिए यदि हम किसी सरणी जैसी वस्तुthis में मान सेट करते हैं.slice() , .slice()बस होगा मान यह एक सरणी के साथ काम कर रहा है, और अपने काम करेंगे।

इस सादे वस्तु को उदाहरण के रूप में लें।

var my_object = {
    '0': 'zero',
    '1': 'one',
    '2': 'two',
    '3': 'three',
    '4': 'four',
    length: 5
};

यह स्पष्ट रूप से एक ऐरे नहीं है, लेकिन यदि आप इसे thisमान के रूप में सेट कर सकते हैं .slice(), तो यह सिर्फ काम करेगा, क्योंकि यह एरे के लिए पर्याप्त दिखता है.slice() ठीक से काम करने के ।

var sliced = Array.prototype.slice.call( my_object, 3 );

उदाहरण: http://jsfiddle.net/wSvkv/

जैसा कि आप कंसोल में देख सकते हैं, परिणाम वही है जो हम उम्मीद करते हैं:

['three','four'];

तो यह तब होता है जब आप किसी argumentsवस्तु को thisमान के रूप में सेट करते हैं .slice()। क्योंकि argumentsएक .lengthसंपत्ति और संख्यात्मक सूचकांकों का एक समूह है, .slice()बस अपने काम के बारे में जाता है जैसे कि यह एक वास्तविक ऐरे पर काम कर रहा था।


7
बहुत बढ़िया जवाब! लेकिन दुख की बात है कि आप इस तरह से किसी भी वस्तु को परिवर्तित नहीं कर सकते हैं, अगर आपकी ऑब्जेक्ट कुंजियाँ स्ट्रिंग मान हैं, जैसे कि वास्तविक शब्दों में .. यह विफल हो जाएगा, इसलिए अपनी वस्तुओं को '0' के रूप में रखें: 'मान' और 'स्ट्रिंगनाम' की तरह नहीं : 'मान'।
joopmicroop

6
@ मिचेल: ओपन सोर्स जेएस कार्यान्वयन का स्रोत कोड पढ़ना संभव है, लेकिन "ईसीएमएस्क्रिप्ट" भाषा विनिर्देश को संदर्भित करना सरल है। यहांArray.prototype.slice विधि वर्णन का लिंक दिया गया है ।

1
चूंकि ऑब्जेक्ट कुंजियों का कोई क्रम नहीं है, इसलिए यह विशिष्ट प्रदर्शन अन्य ब्राउज़रों में विफल हो सकता है। सृजन के क्रम से सभी विक्रेता अपनी वस्तुओं की चाबी नहीं छांटते हैं।
vsync

1
@vsync: यह वह for-inकथन है जो आदेश की गारंटी नहीं देता है। एल्गोरिथ्म का उपयोग .slice()एक संख्यात्मक क्रम को दिए गए ऑब्जेक्ट (या एरे या जो भी) के साथ शुरू 0और समाप्त (गैर-समावेशी) को परिभाषित करता है .length। इसलिए आदेश को सभी कार्यान्वयनों के अनुरूप होने की गारंटी है।
कुकी राक्षस

7
@vsync: यह एक धारणा नहीं है। यदि आप इसे लागू करते हैं तो आप किसी भी वस्तु से ऑर्डर प्राप्त कर सकते हैं। मान लीजिए कि मेरे पास है var obj = {2:"two", 0:"zero", 1: "one"}। यदि हम for-inऑब्जेक्ट को एन्यूमरेट करने के लिए उपयोग करते हैं , तो ऑर्डर की कोई गारंटी नहीं है। लेकिन अगर हम उपयोग करते हैं for, तो हम ऑर्डर को मैन्युअल रूप से लागू कर सकते हैं for (var i = 0; i < 3; i++) { console.log(obj[i]); }:। अब हम जानते हैं कि वस्तु के गुणधर्म हमारे forलूप द्वारा परिभाषित आरोही क्रम में पहुंच जाएंगे । वही .slice()करता है। यह परवाह नहीं है अगर यह एक वास्तविक ऐरे है। यह सिर्फ 0आरोही लूप में गुणों को शुरू और एक्सेस करता है।
कुकी राक्षस

88

argumentsवस्तु वास्तव में किसी सरणी का एक उदाहरण नहीं है, और सरणी से किसी भी विधि नहीं है। इसलिए,arguments.slice(...) काम नहीं करेगा क्योंकि तर्क ऑब्जेक्ट में स्लाइस विधि नहीं है।

Arrays में यह विधि है, और क्योंकि argumentsऑब्जेक्ट एक सरणी के समान है, दोनों संगत हैं। इसका मतलब है कि हम तर्कों के साथ सरणी विधियों का उपयोग कर सकते हैं। और चूंकि सरणी विधियां सरणियों को ध्यान में रखते हुए बनाई गई थीं, इसलिए वे अन्य तर्क वस्तुओं के बजाय सरणियां लौटाएंगी।

तो क्यों उपयोग करें? Array.prototype ? Arrayवस्तु जो हम (से नए सरणियों बनाने है new Array()), और इन नए सरणियों पारित कर रहे हैं तरीकों और गुण, टुकड़ा की तरह। इन विधियों को [Class].prototypeऑब्जेक्ट में संग्रहीत किया जाता है। तो, दक्षता के लिए, स्लाइस विधि द्वारा (new Array()).slice.call()या का उपयोग करने के बजाय[].slice.call() , हम इसे सीधे प्रोटोटाइप से प्राप्त करते हैं। ऐसा इसलिए है क्योंकि हमें एक नई सारणी शुरू करने की जरूरत नहीं है।

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


आप यहाँ वर्णित कारणों के लिए एक स्लाइस का उपयोग करना चाह सकते हैं: jspatterns.com/arguments-considered-harmful
KooiInc

44

आम तौर पर, बुला रहा है

var b = a.slice();

सरणी aको कॉपी करेगा b। हालाँकि, हम ऐसा नहीं कर सकते

var a = arguments.slice();

क्योंकि argumentsएक वास्तविक सरणी नहीं है, और sliceएक विधि के रूप में नहीं है । Array.prototype.sliceहै sliceसरणियों के लिए समारोह, और callसाथ समारोह चलाता है thisकरने के लिए सेट arguments


2
thanx लेकिन क्यों का उपयोग करें prototype? sliceएक देशी Arrayविधि नहीं है ?
13

2
ध्यान दें कि Arrayएक कंस्ट्रक्टर फ़ंक्शन है, और संबंधित "क्लास" है Array.prototype। आप यह भी उपयोग कर सकते हैं[].slice
user123444555621

4
IlyaD, sliceप्रत्येक Arrayउदाहरण की एक विधि है , लेकिन Arrayनिर्माण कार्य नहीं है। आप prototypeएक निर्माता के सैद्धांतिक उदाहरणों के तरीकों का उपयोग करने के लिए उपयोग करते हैं।
डेलन अजाबानी

23

सबसे पहले, आपको पढ़ना चाहिए कि जावास्क्रिप्ट में फ़ंक्शन इनवोकेशन कैसे काम करता है । मुझे संदेह है कि अकेले ही आपके प्रश्न का उत्तर देने के लिए पर्याप्त है। लेकिन यहाँ क्या हो रहा है का एक सारांश है:

Array.prototype.sliceअर्क विधि से की प्रोटोटाइप । लेकिन इसे सीधे कॉल करना काम नहीं करेगा, क्योंकि यह एक विधि है (फ़ंक्शन नहीं) और इसलिए इसे एक संदर्भ (कॉलिंग ऑब्जेक्ट ) की आवश्यकता होती है , अन्यथा यह फेंक देगा।slice ArraythisUncaught TypeError: Array.prototype.slice called on null or undefined

call()विधि आप एक विधि के संदर्भ निर्दिष्ट करने के लिए, मूल रूप से इन दो कॉल बराबर बनाने की अनुमति देता है:

someObject.slice(1, 2);
slice.call(someObject, 1, 2);

पूर्व को छोड़कर sliceविधि के someObjectप्रोटोटाइप श्रृंखला में मौजूद होने की आवश्यकता है (जैसा कि यह करता है Array), जबकि उत्तरार्द्ध संदर्भ की अनुमति देता है (someObject ) को मैन्युअल रूप से विधि में पारित करने की ।

इसके अलावा, बाद के लिए कम है:

var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);

जो निम्नानुसार है:

Array.prototype.slice.call(someObject, 1, 2);

22
// We can apply `slice` from  `Array.prototype`:
Array.prototype.slice.call([]); //-> []

// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true

// … we can just invoke it directly:
[].slice(); //-> []

// `arguments` has no `slice` method
'slice' in arguments; //-> false

// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]

// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]

16

Array.prototype.slice.call (तर्क) एक तर्क में एक सरणी में बदलने के लिए पुराने जमाने का तरीका है।

ECMAScript 2015 में, आप Array.from या स्प्रेड ऑपरेटर का उपयोग कर सकते हैं:

let args = Array.from(arguments);

let args = [...arguments];

9

इसका कारण, जैसा कि MDN नोट करता है

तर्कों वस्तु एक सरणी नहीं है। यह एक सरणी के समान है, लेकिन लंबाई को छोड़कर किसी भी सरणी गुण नहीं है। उदाहरण के लिए, यह पॉप विधि नहीं है। हालाँकि इसे वास्तविक सरणी में बदला जा सकता है:

यहां हम sliceमूल वस्तु पर कॉल कर रहे हैं Arrayऔर इसके क्रियान्वयन पर और अतिरिक्त क्यों नहीं.prototype

var args = Array.prototype.slice.call(arguments);

4

मत भूलो, कि इस व्यवहार का एक निम्न-स्तरीय मूल बातें टाइप-कास्टिंग है जो पूरी तरह से जेएस-इंजन में एकीकृत है।

स्लाइस सिर्फ ऑब्जेक्ट लेता है (मौजूदा तर्कों के लिए धन्यवाद। संपत्ति) और उस पर सभी ऑपरेशन करने के बाद डाली गई सरणी-ऑब्जेक्ट लौटाता है।

यदि आप स्ट्रिंग-पद्धति को एक INT-value के साथ व्यवहार करने का प्रयास करते हैं तो वही लॉजिक जिन्हें आप परख सकते हैं:

String.prototype.bold.call(11);  // returns "<b>11</b>"

और वह ऊपर बयान देता है।


1

यह sliceविधि सरणियों का उपयोग करता है और इसे ऑब्जेक्ट thisहोने के साथ कहता है arguments। इसका मतलब यह है कि यह कहते हैं जैसे कि तुमने arguments.slice()ग्रहण कियाarguments इस तरह के एक विधि थी।

बिना किसी तर्क के एक स्लाइस बनाना बस सभी तत्वों को ले जाएगा - इसलिए यह argumentsएक ऐरे से तत्वों को कॉपी करता है ।


1

चलिए मान लेते हैं: function.apply(thisArg, argArray )

लागू विधि एक फ़ंक्शन को आमंत्रित करती है, उस वस्तु में गुजरती है जो इसके लिए बाध्य होगी और तर्कों का एक वैकल्पिक सरणी।

स्लाइस () विधि एक सरणी का एक हिस्सा चुनती है, और नया सरणी लौटाती है।

इसलिए जब आप Array.prototype.slice.apply(arguments, [0])ऐरे को स्लाइस विधि कहते हैं तो तर्कों पर बाध्य किया जाता है।


1

शायद थोड़ी देर हो गई, लेकिन इस गड़बड़ के सभी का जवाब है कि कॉल () का उपयोग जेएस इनहेरिटेंस के लिए किया जाता है। यदि हम इसकी तुलना पायथन या पीएचपी से करते हैं, उदाहरण के लिए, कॉल को सुपर () के रूप में क्रमशः उपयोग किया जाता है। init () या माता-पिता :: _ निर्माण ()।

यह इसके उपयोग का एक उदाहरण है जो सभी को स्पष्ट करता है:

function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}

संदर्भ: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inititance


0

जब .slice () को सामान्य रूप से कहा जाता है, तो यह एक एरे है, और फिर यह उस एरे पर निर्भर करता है, और अपना काम करता है।

 //ARGUMENTS
function func(){
  console.log(arguments);//[1, 2, 3, 4]

  //var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
  var arrArguments = [].slice.call(arguments);//cp array with explicity THIS  
  arrArguments.push('new');
  console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]

-1

मैं सिर्फ यह याद दिलाने के लिए लिख रहा हूं ...

    Array.prototype.slice.call(arguments);
==  Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
==  [ arguments[1], arguments[2], arguments[3], ... ]

या किसी सरणी में अधिकांश चीजों को चालू करने के लिए बस इस आसान फ़ंक्शन $ A का उपयोग करें ।

function hasArrayNature(a) {
    return !!a && (typeof a == "object" || typeof a == "function") && "length" in a && !("setInterval" in a) && (Object.prototype.toString.call(a) === "[object Array]" || "callee" in a || "item" in a);
}

function $A(b) {
    if (!hasArrayNature(b)) return [ b ];
    if (b.item) {
        var a = b.length, c = new Array(a);
        while (a--) c[a] = b[a];
        return c;
    }
    return Array.prototype.slice.call(b);
}

उदाहरण का उपयोग ...

function test() {
    $A( arguments ).forEach( function(arg) {
        console.log("Argument: " + arg);
    });
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.