जावास्क्रिप्ट में सीमा बनाना - अजीब वाक्यविन्यास


129

मैंने ई-चर्चा मेलिंग सूची में निम्नलिखित कोड में भाग लिया है:

Array.apply(null, { length: 5 }).map(Number.call, Number);

यह पैदा करता है

[0, 1, 2, 3, 4]

यह कोड का परिणाम क्यों है? यहाँ क्या हो रहा है?


2
IMO Array.apply(null, Array(30)).map(Number.call, Number)को पढ़ना आसान है क्योंकि यह दिखावा करने से बचता है कि एक सादा वस्तु एक ऐरे है।
fncomp

10
@fncomp कृपया वास्तव में एक सीमा बनाने के लिए उपयोग न करें । न केवल यह सीधे दृष्टिकोण की तुलना में धीमा है - यह समझने में आसान नहीं है। यहां सिंटैक्स (अच्छी तरह से, वास्तव में एपीआई और सिंटैक्स नहीं) को समझना मुश्किल है जो इसे एक दिलचस्प सवाल बनाता है लेकिन भयानक उत्पादन कोड आईएमओ।
बेंजामिन ग्रुएनबाउम

हां, किसी को सुझाव न देना इसका उपयोग करता है, लेकिन सोचा कि वस्तु शाब्दिक संस्करण के सापेक्ष पढ़ना आसान है।
fncomp

1
मुझे यकीन नहीं है कि कोई भी ऐसा क्यों करना चाहेगा। इस तरह से ऐरे को बनाने में जितना समय लगता है वह थोड़ा कम सेक्सी लेकिन बहुत तेज तरीके से किया जा सकता था: jsperf.com/basic-vs-extreme
Eric Hodonsky

जवाबों:


263

इस "हैक" को समझने के लिए कई चीजों को समझने की आवश्यकता है:

  1. हम ऐसा क्यों नहीं करते Array(5).map(...)
  2. कैसे Function.prototype.applyतर्कों को संभालता है
  3. कैसे Arrayकई तर्कों को संभालता है
  4. कैसे Numberफ़ंक्शन तर्कों को संभालता है
  5. क्या Function.prototype.callकरता है

वे बल्कि जावास्क्रिप्ट में उन्नत विषय हैं, इसलिए यह अधिक-से-अधिक लंबा होगा। हम ऊपर से शुरू करेंगे। सीट बेल्ट लगा लो!

1. सिर्फ क्यों नहीं Array(5).map?

क्या एक सरणी है, वास्तव में? एक नियमित ऑब्जेक्ट, जिसमें पूर्णांक कुंजियाँ होती हैं, जो मानों के लिए मैप करती हैं। उदाहरण के लिए, जादुई lengthचर में इसकी अन्य विशेष विशेषताएं हैं, लेकिन key => valueकिसी भी अन्य वस्तु की तरह , यह एक नियमित मानचित्र है। चलो सरणियों के साथ थोड़ा खेलते हैं, हम करेंगे?

var arr = ['a', 'b', 'c'];
arr.hasOwnProperty(0); //true
arr[0]; //'a'
Object.keys(arr); //['0', '1', '2']
arr.length; //3, implies arr[3] === undefined

//we expand the array by 1 item
arr.length = 4;
arr[3]; //undefined
arr.hasOwnProperty(3); //false
Object.keys(arr); //['0', '1', '2']

हमें सरणी में आइटमों arr.lengthकी संख्या, और key=>valueसरणी की मैपिंग की संख्या के बीच अंतर्निहित अंतर मिलता है, जो इससे भिन्न हो सकता है arr.length

सरणी का विस्तार करके कोई नया मैपिंग arr.length नहीं बनाता है key=>value, इसलिए ऐसा नहीं है कि सरणी में अपरिभाषित मान हैं, लेकिन इसमें कोई कुंजी नहीं है । और जब आप किसी गैर-मौजूद संपत्ति तक पहुँचने की कोशिश करते हैं तो क्या होता है? आपको मिलता है undefined

अब हम अपने सिर को थोड़ा ऊपर उठा सकते हैं, और देख सकते हैं कि arr.mapइन गुणों पर कार्य क्यों नहीं चलते हैं। यदि arr[3]इसे केवल अपरिभाषित किया गया था, और कुंजी मौजूद थी, तो ये सभी सरणी कार्य किसी अन्य मूल्य की तरह ही इस पर चले जाएंगे:

//just to remind you
arr; //['a', 'b', 'c', undefined];
arr.length; //4
arr[4] = 'e';

arr; //['a', 'b', 'c', undefined, 'e'];
arr.length; //5
Object.keys(arr); //['0', '1', '2', '4']

arr.map(function (item) { return item.toUpperCase() });
//["A", "B", "C", undefined, "E"]

मैंने जानबूझकर आगे की बात साबित करने के लिए एक मेथड कॉल का इस्तेमाल किया जो कि खुद ही कभी नहीं था: कॉलिंग undefined.toUpperCaseने एक त्रुटि उठाई होगी, लेकिन यह नहीं हुआ। साबित करने के लिए कि :

arr[5] = undefined;
arr; //["a", "b", "c", undefined, "e", undefined]
arr.hasOwnProperty(5); //true
arr.map(function (item) { return item.toUpperCase() });
//TypeError: Cannot call method 'toUpperCase' of undefined

और अब हम अपनी बात पर आते हैं: Array(N)चीजें कैसी होती हैं। धारा 15.4.2.2 प्रक्रिया का वर्णन करती है। मुम्बो जंबो का एक समूह है जिसकी हम परवाह नहीं करते हैं, लेकिन यदि आप लाइनों के बीच पढ़ने का प्रबंधन करते हैं (या आप सिर्फ इस एक पर मुझ पर भरोसा कर सकते हैं, लेकिन नहीं), यह मूल रूप से इस पर उबलता है:

function Array(len) {
    var ret = [];
    ret.length = len;
    return ret;
}

(इस धारणा के तहत संचालित होता है (जो वास्तविक कल्पना में जांचा जाता है) जो कि lenएक मान्य uint32 है, और न ही किसी भी मूल्य का)

तो अब आप देख सकते हैं कि काम क्यों Array(5).map(...)नहीं करेगा - हम lenसरणी पर आइटम को परिभाषित नहीं करते हैं , हम key => valueमैपिंग नहीं बनाते हैं , हम बस lengthसंपत्ति में परिवर्तन करते हैं।

अब जब कि हमारे पास है, तो दूसरी जादुई चीज़ देखें:

2. कैसे Function.prototype.applyकाम करता है

applyमूल रूप से एक सरणी क्या है, और इसे फ़ंक्शन कॉल के तर्कों के रूप में अनियंत्रित करें। इसका मतलब है कि निम्नलिखित बहुत अधिक समान हैं:

function foo (a, b, c) {
    return a + b + c;
}
foo(0, 1, 2); //3
foo.apply(null, [0, 1, 2]); //3

अब, हम यह देखने की प्रक्रिया को आसान कर सकते हैं कि कैसे विशेष चर को applyलॉग करके काम करता है arguments:

function log () {
    console.log(arguments);
}

log.apply(null, ['mary', 'had', 'a', 'little', 'lamb']);
 //["mary", "had", "a", "little", "lamb"]

//arguments is a pseudo-array itself, so we can use it as well
(function () {
    log.apply(null, arguments);
})('mary', 'had', 'a', 'little', 'lamb');
 //["mary", "had", "a", "little", "lamb"]

//a NodeList, like the one returned from DOM methods, is also a pseudo-array
log.apply(null, document.getElementsByTagName('script'));
 //[script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script]

//carefully look at the following two
log.apply(null, Array(5));
//[undefined, undefined, undefined, undefined, undefined]
//note that the above are not undefined keys - but the value undefined itself!

log.apply(null, {length : 5});
//[undefined, undefined, undefined, undefined, undefined]

दूसरे-से-अंतिम उदाहरण में अपना दावा साबित करना आसान है:

function ahaExclamationMark () {
    console.log(arguments.length);
    console.log(arguments.hasOwnProperty(0));
}

ahaExclamationMark.apply(null, Array(2)); //2, true

(हाँ, इरादा इरादा)। key => valueमानचित्रण सरणी हम करने के लिए पर पारित में ही अस्तित्व में नहीं हो सकता है apply, लेकिन यह निश्चित रूप में मौजूद है argumentsचर। यही कारण है कि अंतिम उदाहरण काम करता है: हम जिस वस्तु से गुजरते हैं, उस पर चाबियाँ मौजूद नहीं हैं, लेकिन वे मौजूद नहीं हैं arguments

ऐसा क्यों है? आइए धारा 15.3.4.3 को देखें , जहां Function.prototype.applyपरिभाषित किया गया है। ज्यादातर चीजें जिनके बारे में हम परवाह नहीं करते हैं, लेकिन यहां दिलचस्प हिस्सा है:

  1. आइए हम तर्क [लंबाई] के साथ argArray की [[प्राप्त करें]] आंतरिक पद्धति को कॉल करने का परिणाम बनें।

जिसका मूल अर्थ है argArray.length:। तब आइटम एक साधारण forलूप को lengthआइटम पर करने के लिए आगे बढ़ता है , listइसी मूल्यों को बनाता है ( listकुछ आंतरिक जादू है, लेकिन यह मूल रूप से एक सरणी है)। बहुत, बहुत ढीले कोड के संदर्भ में:

Function.prototype.apply = function (thisArg, argArray) {
    var len = argArray.length,
        argList = [];

    for (var i = 0; i < len; i += 1) {
        argList[i] = argArray[i];
    }

    //yeah...
    superMagicalFunctionInvocation(this, thisArg, argList);
};

तो argArrayइस मामले में हम सभी की नकल करने की जरूरत है एक lengthसंपत्ति के साथ एक वस्तु है । और अब हम देख सकते हैं कि मान अपरिभाषित क्यों हैं, लेकिन कुंजियाँ नहीं हैं, पर arguments: हम key=>valueमैपिंग बनाते हैं ।

काहे, तो यह पिछले हिस्से से कम नहीं हो सकता है। लेकिन जब हम खत्म करेंगे तो केक होगा, इसलिए धैर्य रखें! हालाँकि, निम्न अनुभाग के बाद (जो छोटा होगा, मैं वादा करता हूँ) हम अभिव्यक्ति को विच्छेदित करना शुरू कर सकते हैं। यदि आप भूल गए हैं, तो सवाल यह है कि निम्नलिखित कार्य कैसे किया गया था:

Array.apply(null, { length: 5 }).map(Number.call, Number);

3. कैसे Arrayकई तर्कों को संभालता है

इसलिए! हमने देखा कि जब आप किसी lengthतर्क को पास करते हैं तो क्या होता है Array, लेकिन अभिव्यक्ति में, हम कई चीजों को तर्क के रूप में पारित करते हैं ( undefinedसटीक होने के लिए 5 की एक सरणी )। धारा 15.4.2.1 हमें बताती है कि क्या करना है। आखिरी पैराग्राफ वह सब है जो हमारे लिए मायने रखता है, और यह वास्तव में अजीब तरह से शब्द है , लेकिन यह इस तरह से उबलता है:

function Array () {
    var ret = [];
    ret.length = arguments.length;

    for (var i = 0; i < arguments.length; i += 1) {
        ret[i] = arguments[i];
    }

    return ret;
}

Array(0, 1, 2); //[0, 1, 2]
Array.apply(null, [0, 1, 2]); //[0, 1, 2]
Array.apply(null, Array(2)); //[undefined, undefined]
Array.apply(null, {length:2}); //[undefined, undefined]

टाडा! हमें कई अपरिभाषित मानों की एक सरणी मिलती है, और हम इन अपरिभाषित मूल्यों की एक सरणी लौटाते हैं।

अभिव्यक्ति का पहला भाग

अंत में, हम निम्नलिखित को समझ सकते हैं:

Array.apply(null, { length: 5 })

हमने देखा कि यह एक सरणी देता है जिसमें 5 अपरिभाषित मान होते हैं, जिसमें सभी अस्तित्व में चाबियाँ होती हैं।

अब, अभिव्यक्ति के दूसरे भाग में:

[undefined, undefined, undefined, undefined, undefined].map(Number.call, Number)

यह आसान, गैर-जटिल हिस्सा होगा, क्योंकि यह अस्पष्ट हैक पर इतना भरोसा नहीं करता है।

4. Numberइनपुट कैसे व्यवहार करता है

डूइंग Number(something)( सेक्शन 15.7.1 ) somethingएक नंबर में कनवर्ट करता है, और वह सब है। यह कैसे होता है कि यह थोड़ा जटिल है, विशेष रूप से स्ट्रिंग्स के मामलों में, लेकिन यह खंड 9.3 में परिभाषित किया गया है , यदि आप रुचि रखते हैं।

5. का खेल Function.prototype.call

callहै apply'भाई, में परिभाषित खंड 15.3.4.4 । तर्कों की एक सरणी लेने के बजाय, यह केवल प्राप्त तर्कों को लेता है, और उन्हें आगे बढ़ाता है।

चीजें दिलचस्प हो जाती हैं जब आप एक से अधिक श्रृंखला बनाते callहैं, तो अजीब को 11 तक क्रैंक करते हैं:

function log () {
    console.log(this, arguments);
}
log.call.call(log, {a:4}, {a:5});
//{a:4}, [{a:5}]
//^---^  ^-----^
// this   arguments

यह काफी wtf योग्य है जब तक आप समझ नहीं लेते कि क्या हो रहा है। log.callकेवल एक फ़ंक्शन है, जो किसी अन्य फ़ंक्शन की callविधि के बराबर है , और जैसे कि, अपने आप में एक callविधि भी है:

log.call === log.call.call; //true
log.call === Function.call; //true

और क्या करता callहै? यह thisArgतर्कों का एक गुच्छा स्वीकार करता है , और इसके मूल कार्य को कहता है। हम इसे apply फिर से परिभाषित कर सकते हैं (फिर से, बहुत ढीला कोड, काम नहीं करेगा):

Function.prototype.call = function (thisArg) {
    var args = arguments.slice(1); //I wish that'd work
    return this.apply(thisArg, args);
};

आइए देखें कि यह कैसे नीचे जाता है:

log.call.call(log, {a:4}, {a:5});
  this = log.call
  thisArg = log
  args = [{a:4}, {a:5}]

  log.call.apply(log, [{a:4}, {a:5}])

    log.call({a:4}, {a:5})
      this = log
      thisArg = {a:4}
      args = [{a:5}]

      log.apply({a:4}, [{a:5}])

बाद का हिस्सा, या .mapयह सब

यह अभी तक खत्म नहीं हुआ है। आइए देखें कि क्या होता है जब आप किसी फ़ंक्शन को अधिकांश सरणी विधियों में आपूर्ति करते हैं:

function log () {
    console.log(this, arguments);
}

var arr = ['a', 'b', 'c'];
arr.forEach(log);
//window, ['a', 0, ['a', 'b', 'c']]
//window, ['b', 1, ['a', 'b', 'c']]
//window, ['c', 2, ['a', 'b', 'c']]
//^----^  ^-----------------------^
// this         arguments

यदि हम thisस्वयं एक तर्क प्रदान नहीं करते हैं, तो यह चूक है window। उस आदेश पर ध्यान दें जिसमें तर्क हमारे कॉलबैक को प्रदान किए गए हैं, और चलो इसे फिर से 11 तक पूरे करने के लिए अजीब है:

arr.forEach(log.call, log);
//'a', [0, ['a', 'b', 'c']]
//'b', [1, ['a', 'b', 'c']]
//'b', [2, ['a', 'b', 'c']]
// ^    ^

वाहा वो कौन… थोडा ऊपर चलो। यहाँ क्या चल रहा है? हम खंड 15.4.4.18 में देख सकते हैं , जहां forEachपरिभाषित किया गया है, निम्नलिखित बहुत कुछ होता है:

var callback = log.call,
    thisArg = log;

for (var i = 0; i < arr.length; i += 1) {
    callback.call(thisArg, arr[i], i, arr);
}

तो, हम इसे प्राप्त करते हैं:

log.call.call(log, arr[i], i, arr);
//After one `.call`, it cascades to:
log.call(arr[i], i, arr);
//Further cascading to:
log(i, arr);

अब हम देख सकते हैं कि कैसे .map(Number.call, Number)काम करता है:

Number.call.call(Number, arr[i], i, arr);
Number.call(arr[i], i, arr);
Number(i, arr);

जो iएक नंबर पर, वर्तमान सूचकांक के परिवर्तन को लौटाता है ।

निष्कर्ष के तौर पर,

भाव

Array.apply(null, { length: 5 }).map(Number.call, Number);

दो भागों में काम करता है:

var arr = Array.apply(null, { length: 5 }); //1
arr.map(Number.call, Number); //2

पहला भाग 5 अपरिभाषित वस्तुओं की एक सरणी बनाता है। दूसरा उस सरणी पर जाता है और उसके सूचकांकों को लेता है, जिसके परिणामस्वरूप तत्व सूचकांकों की एक सरणी होती है:

[0, 1, 2, 3, 4]

@ ज़ीरक कृपया निम्नलिखित को समझने में मेरी मदद करें ahaExclamationMark.apply(null, Array(2)); //2, true। क्यों इसे वापस करता है 2और trueक्रमशः? क्या आप Array(2)यहाँ केवल एक तर्क नहीं दे रहे हैं?
गीक

4
@ गीक हम केवल एक तर्क को पास करते हैं apply, लेकिन यह तर्क फ़ंक्शन में दिए गए दो तर्कों में "चपटा" है। आप पहले applyउदाहरणों में अधिक आसानी से देख सकते हैं । पहला console.logतब दिखाता है कि वास्तव में, हमें दो तर्क (दो सरणी आइटम) प्राप्त हुए, और दूसरा console.logदिखाता है कि सरणी में key=>value1 स्लॉट में मैपिंग है (जैसा कि उत्तर के 1 भाग में समझाया गया है)।
जिराक

4
अनुरोध (कुछ) के कारण , अब आप ऑडियो संस्करण का आनंद ले सकते हैं: dl.dropboxusercontent.com/u/24522528/SO-answer.mp3
Zirak

1
ध्यान दें कि एक NodeList पास करना, जो कि एक मेजबान वस्तु है, एक देशी विधि के रूप में log.apply(null, document.getElementsByTagName('script'));काम करने के लिए आवश्यक नहीं है और कुछ ब्राउज़रों में काम नहीं करता है, और [].slice.call(NodeList)एक नोड में एक नोड में बदलने के लिए या तो उन में काम नहीं करेगा।
रॉब

2
एक सुधार: thisकेवल Windowगैर-सख्त मोड में चूक ।
कॉमफरिक

21

डिस्क्लेमर : यह उपरोक्त कोड का एक बहुत ही औपचारिक विवरण है - यह है कि मैं इसे कैसे समझाऊं। एक सरल उत्तर के लिए - ऊपर जिराक के महान उत्तर की जांच करें। यह आपके चेहरे में गहराई से अधिक विशिष्टता है और कम "अहा" है।


कई चीजें यहां हो रही हैं। चलो इसे थोड़ा तोड़ दें।

var arr = Array.apply(null, { length: 5 }); // Create an array of 5 `undefined` values

arr.map(Number.call, Number); // Calculate and return a number based on the index passed

पहली पंक्ति में, सरणी कंस्ट्रक्टर को एक फ़ंक्शन के साथ कहा जाता हैFunction.prototype.apply

  • thisमूल्य है nullजो सरणी निर्माता (के लिए कोई फर्क नहीं पड़ता thisही है this15.3.4.3.2.a. के अनुसार संदर्भ में
  • फिर new Arrayएक lengthसंपत्ति के साथ एक वस्तु को पारित किया जा रहा है - जो उस वस्तु को एक सरणी होने का कारण बनता है जैसे .applyकि निम्नलिखित बातों के कारण यह सभी के लिए मायने रखता है .apply:
    • आइए हम तर्क [लंबाई] के साथ argArray की [[प्राप्त करें]] आंतरिक पद्धति को कॉल करने का परिणाम बनें।
  • जैसे, 0 से 4 .applyतक के तर्कों को पारित कर रहा है .length, क्योंकि 0 से 4 पैदावार के साथ कॉल करने [[Get]]पर सरणी कंस्ट्रक्टर को पांच तर्कों के साथ बुलाया जाता है, जिसका मूल्य (किसी वस्तु की अघोषित संपत्ति प्राप्त करना) है।{ length: 5 }undefinedundefined
  • व्यूह रचनाकार को 0, 2 या अधिक तर्कों के साथ कहा जाता है । नवनिर्मित सरणी की लंबाई संपत्ति विनिर्देश के अनुसार तर्कों की संख्या और समान मानों के लिए निर्धारित है।
  • इस प्रकार var arr = Array.apply(null, { length: 5 });पाँच अपरिभाषित मूल्यों की एक सूची बनाता है।

नोट : सूचना के बीच का अंतर यहाँ Array.apply(0,{length: 5})और Array(5), पहले बनाने पांच बार आदिम मान प्रकार undefinedऔर बाद, लंबाई 5. विशेष रूप से एक खाली सरणी बनाने की वजह से .mapकी व्यवहार (8.b) और विशेष रूप से [[HasProperty]

तो एक अनुरूप विनिर्देश में उपरोक्त कोड समान है:

var arr = [undefined, undefined, undefined, undefined, undefined];
arr.map(Number.call, Number); // Calculate and return a number based on the index passed

अब दूसरे भाग के लिए रवाना।

  • Array.prototype.mapNumber.callसरणी के प्रत्येक तत्व पर कॉलबैक फ़ंक्शन (इस मामले में ) को कॉल करता है और निर्दिष्ट thisमान का उपयोग करता है (इस मामले में thisमान को `संख्या पर सेट करते हुए )।
  • मानचित्र में कॉलबैक का दूसरा पैरामीटर (इस मामले में Number.call) सूचकांक है, और पहला यह मान है।
  • इसका मतलब यह है कि पैरामीटर के रूप में (सरणी मान) और सूचकांक के Numberसाथ कहा जाता है । तो यह मूल रूप से प्रत्येक को अपने सरणी सूचकांक में मैप करने के समान है (चूंकि कॉलिंग टाइप रूपांतरण करता है, इस मामले में संख्या से संख्या में सूचकांक नहीं बदल रहा है)।thisundefinedundefinedNumber

इस प्रकार, ऊपर दिया गया कोड पांच अपरिभाषित मान लेता है और प्रत्येक को सरणी में इसके सूचकांक में मैप करता है।

जिसके कारण हमें अपने कोड का परिणाम मिलता है।


1
डॉक्स के लिए: मानचित्र कैसे काम करता है इसके लिए विशिष्टता: es5.github.io/#x15.4.4.1.19 , मोज़िला के पास एक नमूना स्क्रिप्ट है जो डेवलपर
पैट्रिक इवांस

1
लेकिन यह केवल उसी के साथ क्यों काम करता है Array.apply(null, { length: 2 })और न Array.apply(null, [2])कि जो लम्बाई मान के रूप में Arrayगुजरने वाले निर्माता को भी बुलाएगा 2? फिडल
एंड्रियास

@Andreas Array.apply(null,[2])ऐसा है Array(2)जो लंबाई 2 की एक खाली सारणी बनाता है और दो बार आदिम मान वाले सरणी नहींundefined है। पहले भाग के बाद नोट में मेरा सबसे हालिया संपादन देखें, मुझे बताएं कि क्या यह पर्याप्त स्पष्ट है और यदि मैं उस पर स्पष्ट नहीं करूंगा।
बेंजामिन ग्रुएनबाम

जिस तरह से यह पहली बार काम करता है मुझे समझ में नहीं आया है ... दूसरे पढ़ने के बाद यह समझ में आता है। {length: 2}एक एरे को दो तत्वों से जोड़ते हैं जिसे Arrayकंस्ट्रक्टर नए बनाए गए एरे में सम्मिलित करेगा। जैसा कि वहाँ मौजूद तत्वों पैदावार नहीं है, undefinedजो तब डाला जाता है तक पहुँचने के लिए कोई वास्तविक सरणी है। अच्छी चाल :)
एंड्रियास

5

जैसा कि आपने कहा, पहला भाग:

var arr = Array.apply(null, { length: 5 }); 

5 undefinedमानों की एक सरणी बनाता है ।

दूसरा भाग mapसरणी के फ़ंक्शन को बुला रहा है जो 2 तर्क लेता है और उसी आकार का एक नया सरणी देता है।

पहला तर्क जो mapवास्तव में सरणी में प्रत्येक तत्व पर लागू करने के लिए एक फ़ंक्शन है, यह एक फ़ंक्शन होने की उम्मीद है जो 3 तर्क लेता है और एक मान लौटाता है। उदाहरण के लिए:

function foo(a,b,c){
    ...
    return ...
}

यदि हम फ़ंक्शन फू को पहले तर्क के रूप में पास करते हैं, तो इसे प्रत्येक तत्व के लिए बुलाया जाएगा

  • वर्तमान पुनरावृत्त तत्व के मूल्य के रूप में
  • b वर्तमान पुनरावृत्त तत्व के सूचकांक के रूप में
  • सी पूरे मूल सरणी के रूप में

दूसरा तर्क जो mapफ़ंक्शन में ले जाया जा रहा है जिसे आप पहले तर्क के रूप में पास करते हैं। लेकिन ऐसा नहीं होगा, न ही, न ही सी के मामले में foo, यह होगा this

दो उदाहरण:

function bar(a,b,c){
    return this
}
var arr2 = [3,4,5]
var newArr2 = arr2.map(bar, 9);
//newArr2 is equal to [9,9,9]

function baz(a,b,c){
    return b
}
var newArr3 = arr2.map(baz,9);
//newArr3 is equal to [0,1,2]

और एक और सिर्फ यह स्पष्ट करने के लिए:

function qux(a,b,c){
    return a
}
var newArr4 = arr2.map(qux,9);
//newArr4 is equal to [3,4,5]

तो Number.call का क्या?

Number.call एक फ़ंक्शन है जो 2 तर्क लेता है, और दूसरे तर्क को एक नंबर पर पार्स करने की कोशिश करता है (मुझे यकीन नहीं है कि यह पहले तर्क के साथ क्या करता है)।

चूंकि दूसरा तर्क जो mapगुजर रहा है वह सूचकांक है, उस सूचकांक में नए सरणी में रखा जाने वाला मान सूचकांक के बराबर होता है। bazऊपर के उदाहरण में फ़ंक्शन की तरह । Number.callसूचकांक को पार्स करने की कोशिश करेगा - यह स्वाभाविक रूप से समान मूल्य लौटाएगा।

mapआपके कोड में फ़ंक्शन के लिए आपके पास गया दूसरा तर्क वास्तव में परिणाम पर प्रभाव नहीं डालता है। कृपया मुझे सुधारें अगर मैं गलत हूं, तो कृपया।


1
Number.callकोई विशेष कार्य नहीं है जो संख्याओं के लिए तर्क देता है। यह सिर्फ है === Function.prototype.call। केवल दूसरा तर्क, समारोह के रूप में पारित हो कि thisकरने के लिए -value call, प्रासंगिक है - .map(eval.call, Number), .map(String.call, Number)और .map(Function.prototype.call, Number)सब बराबर हैं।
बरगी

0

एक सरणी केवल एक वस्तु है जिसमें 'लंबाई' फ़ील्ड और कुछ विधियाँ (जैसे पुश) शामिल हैं। इसलिए var arr = { length: 5}गिरफ्तारी मूल रूप से एक सरणी के समान है जहां फ़ील्ड 0..4 में डिफ़ॉल्ट मान है जो अपरिभाषित है (यानी arr[0] === undefinedपैदावार सच है)।
दूसरे भाग के लिए, मानचित्र, जैसा कि नाम से पता चलता है, एक सरणी से नए एक तक के नक्शे। यह मूल सरणी के माध्यम से ट्रैवर्सिंग और प्रत्येक आइटम पर मैपिंग-फ़ंक्शन को लागू करने के द्वारा करता है।

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

अंतिम लेकिन कम से कम, जिस विधि को लागू किया जाता है वह नंबर "क्लास" है, और जैसा कि हम जेएस में जानते हैं, एक "क्लास" बस एक फ़ंक्शन है, और यह एक (नंबर) पहले परम को मूल्य होने की उम्मीद करता है।

(*) फंक्शन के प्रोटोटाइप (और नंबर एक फंक्शन) में पाया जाता है।

मशाल


1
वहाँ के बीच एक बड़ा अंतर है [undefined, undefined, undefined, …]और new Array(n)या {length: n}- बाद वाले हैं विरल , यानी वे कोई तत्व है। यह बहुत ही प्रासंगिक है map, और इसीलिए Array.applyइसका उपयोग किया गया था।
बरगी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.