2012-01-15 15 views
7

में जेरेमी एशकेनास की भयानक Underscore.js लाइब्रेरी में उपयोग और लागू करने के लिए, मैंने स्रोत फ़ाइल के बारे में एक चीज़ को समझने की कोशिश की। मुझे यह समझ नहीं है:अंडरस्कोर.जेएस स्रोत को समझने की कोशिश कर रहा है - लाइब्रेरी

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

ताकि:

args = Array.prototype.slice.call(arguments, 2); 

.call या .apply कार्यों के तरीके हैं। लेकिन यहां, .call पर कौन से फ़ंक्शन हैं? पहला पैरामीटर संदर्भ होना चाहिए, लेकिन arguments संदर्भ है? दूसरे पैरामीटर कार्यों में पास करने के लिए पैरा होना चाहिए। यहां वे संख्या 2 हैं। इसका क्या मतलब है? कभी-कभी लाइब्रेरी में, यह 1 या 0 का उपयोग करता है। क्या वे कार्यों में पारित होने के लिए पैरा की संख्या हैं?

_.bind = function bind(func, context) { 
    var bound, args; 
    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 
    if (!_.isFunction(func)) throw new TypeError; 
    args = slice.call(arguments, 2); 
    return bound = function() { 
     if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 
     ctor.prototype = func.prototype; 
     var self = new ctor; 
     var result = func.apply(self, args.concat(slice.call(arguments))); 
     if (Object(result) === result) return result; 
     return self; 
    }; 
    }; 

प्रश्न 2: मैं काफी इस समारोह के तर्क समझ में नहीं आता। समझने में मदद की ज़रूरत है। एक उदाहरण बहुत उपयोगी होना चाहिए।

// Invoke a method (with arguments) on every item in a collection. 
    _.invoke = function(obj, method) { 
    var args = slice.call(arguments, 2); 
    return _.map(obj, function(value) { 
     return (method.call ? method || value : value[method]).apply(value, args); 
    }); 
    }; 

सहायता के लिए धन्यवाद।

उत्तर

7

ऐरे प्रोटोटाइप पर "स्लाइस" फ़ंक्शन से उम्मीद है कि this उस सरणी को संदर्भित करेगा जिस पर इसे संचालित करना है। दूसरे शब्दों में, आप एक असली सरणी है यदि:

var myArray = [1, 2, 3]; 

और आप slice() फोन:

var sliced = myArray.slice(1); 

फिर slice() करने के लिए कि कॉल में, this सरणी "myArray" को दर्शाता है। Raynos एक टिप्पणी में नोट के रूप में:

myArray.slice(1) 

इस प्रकार जब आप call() का उपयोग समारोह आह्वान, और यह arguments संदर्भ वस्तु के रूप में पारित करने के लिए, slice() कोड arguments पर चल रही है के रूप में

myArray.slice.call(myArray, 1); 

ही है । .call() के माध्यम से पारित अन्य पैरामीटर केवल slice() के लिए पैरामीटर या पैरामीटर हैं। ऊपर दिए गए मेरे उदाहरण में, ध्यान दें कि मैंने फ़ंक्शन में 1 पास किया था।

अब आपके दूसरे प्रश्न के अनुसार, .invoke() फ़ंक्शन पहले दो के बाद पारित तर्कों को अलग करता है। इसका मतलब है कि जब आप _.invoke() का उपयोग करते हैं तो आप इसे दो या अधिक तर्क देते हैं: पहला ऑपरेशन करने की सूची है, दूसरी विधि है, और (वैकल्पिक) बाद के तर्क सूची के प्रत्येक तत्व के लिए विधि को पास किए जाते हैं ।

_.map() पर कॉल करना जटिल है (और वास्तव में मुझे लगता है कि इसमें थोड़ा बकवास है)। यह सूची में फिर से चल रहा है, सूची में प्रत्येक मूल्य के लिए एक समारोह बुला रहा है। यह फ़ंक्शन पहले यह निर्धारित करने के लिए करता है कि "विधि" पैरामीटर वास्तव में एक फ़ंक्शन है या नहीं। यदि ऐसा है, तो यह उस संदर्भ को संदर्भ के रूप में सूची के तत्व के साथ .apply() के माध्यम से कॉल करता है। यदि "विधि" कोई फ़ंक्शन नहीं है, तो यह मानता है कि यह प्रत्येक सूची तत्व की संपत्ति का नाम है, और यह गुण कार्य हैं।

उदाहरण के लिए, एक साधारण सूची के साथ यह बहुत सरल है:

var myList = [1, 2, 3]; 
var result = _.invoke(myList, function(n) { return this * n; }, 2); 

कि परिणाम [2, 4, 6] दे देंगे समारोह मैं पारित कर दिया पैरामीटर पारित कर दिया द्वारा उसके संदर्भ वस्तु (this) गुणा करता है, और मैं 2 से पारित कर दिया है, क्योंकि _.invoke() पर कॉल में।

एक और अधिक जटिल सूची के साथ

, मैं _.invoke() के दूसरे स्वाद का उपयोग करें और सूची में प्रत्येक वस्तु पर एक विधि कॉल कर सकते हैं:

var getName = function(prefix) { return prefix + " " + this.name; }; 
var list = [ 
    { name: "Bob", getName: getName }, 
    { name: "Sam", getName: getName }, 
    { name: "Lou", getName: getName } 
]; 

var result = _.invoke(list, "getName", "Congressman"); 

कि सूची में प्रत्येक वस्तु पर "getName" समारोह कॉल करेंगे और परिणामों से बनाई गई एक सूची वापस करें। प्रभाव ["Congressman Bob", "Congressman Sam", "Congressman Lou"] सूची होगी।

अब उस बकवास के बारे में। _.invoke() के लिए कोड में:

return _.map(obj, function(value) { 
    return (method.call ? method || value : value[method]).apply(value, args); 
}); 

subexpresion method || valueहमेशा "विधि" का मान यही होगा, या कम से कम लगभग हमेशा कुछ विदेशी चाल को छोड़कर। यदि method.call सत्य है, तो method का संदर्भ भी सत्य होना चाहिए। इसके अलावा, अगर यह मेरा कोड था, तो मैं method_.map() कॉलबैक के बाहर निरीक्षण करता हूं ताकि निर्णय बार-बार नहीं किया जा सके। हो सकता है कि कुछ इस तरह:

return _.map(obj, method.call ? 
    function(value) { method.apply(value, args); } : 
    function(value) { value[method].apply(value, args); } 
); 
+2

'myArray.slice (1) === slice.call (myArray, 1)' – Raynos

+0

हाँ कि एक महान, सरल संबंध दिखाने के लिए रास्ता नहीं है। – Pointy

+2

@ रेनोस, यह वास्तव में झूठा है। 'टुकड़ा' दो अलग-अलग सरणी वस्तुएं बनाता है, जो समान नहीं हैं। – katspaugh

संबंधित मुद्दे

 संबंधित मुद्दे