इसे बिना बंधन के फ़ंक्शन तर्क को कैसे बांधें?


115

जावास्क्रिप्ट में, मैं thisपैरामीटर को बाध्य किए बिना किसी फ़ंक्शन के लिए तर्क कैसे बांध सकता हूं ?

उदाहरण के लिए:

//Example function.
var c = function(a, b, c, callback) {};

//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?

मैं फ़ंक्शन के दायरे (जैसे सेटिंग this= अशक्त) को बाँधने के दुष्प्रभाव से कैसे बच सकता हूँ ?

संपादित करें:

गलतफहमी के लिए खेद है। मैं तर्कों को बांधना चाहता हूं, फिर बाद में बाध्य फ़ंक्शन को कॉल करने में सक्षम हो सकता हूं और यह बिल्कुल ऐसा व्यवहार करता है जैसे कि मैंने मूल फ़ंक्शन को कॉल किया और इसे बाध्य तर्क दिए:

var x = 'outside object';

var obj = {
  x: 'inside object',
  c: function(a, b, c, callback) {
    console.log(this.x);
  }
};

var b = obj.c.bind(null, 1, 2, 3);

//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});

//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?

मैं अभी भी इस पर नया हूँ, भ्रम के लिए खेद है।

धन्यवाद!


1
क्या यह सिर्फ फिर से बाँधने के लिए अपर्याप्त होगा this? var b = c.bind(this, 1,2,3);
कोजिरो

पहले मूल्य का bind()होना समस्याग्रस्त क्यों है null? एफएफ में ठीक काम करने लगता है।
रस

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

1
मैं वास्तव में अस्पष्ट हूं कि आप क्या करने की कोशिश कर रहे हैं। आप thisजावास्क्रिप्ट में पूरी तरह से अनबाउंड नहीं हो सकते । इसका हमेशा कुछ मतलब होता है । तो एनक्लोजिंग फ़ंक्शन के thisलिए बाध्य करना thisबहुत मायने रखता है।
कोजीरो

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

जवाबों:


32

आप ऐसा कर सकते हैं, लेकिन इसे "बाध्यकारी" के रूप में सोचने से बचने के लिए सबसे अच्छा है क्योंकि यह शब्द "यह" मान सेट करने के लिए उपयोग किया जाता है। शायद एक समारोह में तर्कों को "लपेटकर" के रूप में लगता है?

आप जो कार्य करते हैं, वह एक ऐसा फ़ंक्शन है जिसमें वांछित तर्क हैं जो इसे क्लोजर के माध्यम से बनाया गया है:

var withWrappedArguments = function(arg1, arg2)
    {
        return function() { ... do your stuff with arg1 and arg2 ... };
    }(actualArg1Value, actualArg2Value);

आशा है कि मुझे वाक्यविन्यास वहीं मिलेगा। यह क्या करता है एक फ़ंक्शन बनाया जाता है जिसे wwrappedArguments () कहा जाता है (पांडित्य होने के लिए यह एक अनाम फ़ंक्शन है जिसे वेरिएबल को असाइन किया गया है) जिसे आप किसी भी समय कॉल कर सकते हैं और हमेशा वास्तविकArg1Value और वास्तविक -rg2Value के साथ कार्य करेंगे, और कुछ भी जिसे आप रखना चाहते हैं। वहाँ। आप यह भी कर सकते हैं कि यदि आप चाहें तो कॉल के समय और तर्क स्वीकार करें। अंतिम समापन ब्रेस के बाद रहस्य कोष्ठक है। ये बाहरी फ़ंक्शन को तुरंत पारित किए गए मानों के साथ निष्पादित करते हैं, और आंतरिक फ़ंक्शन उत्पन्न करने के लिए जिसे बाद में कहा जा सकता है। पारित मान तब उत्पन्न होता है जब फ़ंक्शन उत्पन्न होता है।

यह प्रभावी रूप से बाँध करता है, लेकिन इस तरह यह स्पष्ट है कि लिपटे हुए तर्क बस स्थानीय चर पर बंद हो रहे हैं, और इस के व्यवहार को बदलने की कोई आवश्यकता नहीं है।


16
ध्यान दें कि इसे आमतौर पर "करी" कहा जाता है।
M3D

@ M3D कैपिटलाइज़िंग जो इसे इतना अजीब बनाता है।
एंड्रयू

यह एक बहुत उपयोगी होगा यदि एक उदाहरण प्रदान किया गया कि इसका उपयोग कैसे किया जाए।
एंड्रयू

en.wikipedia.org/wiki/Currying जो कोई रुचि रखता है के लिए लिंक है, हालांकि TLDR संस्करण है "इसके बजाय f(x,y)हम चाहते हैं f(x)(y)या g=f(x); g(y)। तो हम बदल जाएगा f=(x,y)=>x+yकरने के लिए f=(x)=>(y)=>x+y।"
एम

26

ईएस 6 में, यह आसानी से प्रसार ऑपरेटर के साथ संयोजन में बाकी मापदंडों का उपयोग करके किया जाता है ।

तो हम एक फ़ंक्शन को परिभाषित कर सकते हैं bindArgsजो काम करता है bind, सिवाय इसके कि केवल तर्क बाध्य हैं, लेकिन संदर्भ ( this) नहीं।

Function.prototype.bindArgs =
    function (...boundArgs)
    {
        const targetFunction = this;
        return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
    };

फिर, एक निर्दिष्ट फ़ंक्शन fooऔर ऑब्जेक्ट के लिए obj, स्टेटमेंट

return foo.call(obj, 1, 2, 3, 4);

के बराबर है

let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);

जहां केवल पहली और दूसरी दलीलें दी जाती हैं bar, जबकि objआह्वान में निर्दिष्ट संदर्भ का उपयोग किया जाता है और बाध्य तर्कों के बाद अतिरिक्त तर्क दिए जाते हैं। वापसी मूल्य बस अग्रेषित किया जाता है।


11
तालिका में es6 लाता है, अभी भी var का उपयोग करता है :(
डैनियल कोबे

7
@DanielKobe धन्यवाद! फैले हुए ऑपरेटरों और रेस्ट परमेस को फ़ायरफ़ॉक्स में बहुत पहले लागू किया गया था letऔर constजो अभी तक मैंने पहली बार पोस्ट किए थे तब तक उपलब्ध नहीं थे। अब इसे अपडेट किया गया है।
गोटो 0

यह बहुत अच्छा है और कॉलबैक कार्यों के लिए काम करता है! उन्हें प्रीपेन्ड करने के बजाय आर्ग्स अपेंड करने के लिए भी बदला जा सकता है।
डेनिसएम

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

17

देशी में bindविधिthis परिणाम समारोह में मूल्य खो दिया है। हालाँकि, आप आसानी से संदर्भ के लिए एक तर्क का उपयोग नहीं करने के लिए सामान्य शिम को फिर से याद कर सकते हैं:

Function.prototype.arg = function() {
    if (typeof this !== "function")
        throw new TypeError("Function.prototype.arg needs to be called on a function");
    var slice = Array.prototype.slice,
        args = slice.call(arguments), 
        fn = this, 
        partial = function() {
            return fn.apply(this, args.concat(slice.call(arguments)));
//                          ^^^^
        };
    partial.prototype = Object.create(this.prototype);
    return partial;
};

4
इस तथ्य को पसंद न करें कि आपको प्रोटोटाइप के साथ खेलना है Functionलेकिन इसने मुझे बहुत समय और कुछ बदसूरत वर्कअराउंड से बचाया। धन्यवाद
jackdbernier

3
@jackdbernier: आपके पास नहीं है, लेकिन मुझे यह एक विधि की तरह अधिक सहज लगता है bind। आप इसे आसानी से एकfunction bindArgs(fn){ …, args = slice.call(arguments, 1); …}
Bergi

@ Qantas94Heavy: जब आप thisहोने के बारे में परवाह करते हैं तो आपको हमेशा ऐसा करना पड़ता है a। आप bindइसके बजाय, का उपयोग कर सकते हैं । फिर भी, ओपी स्पष्ट रूप से मूल्य के बारे में परवाह नहीं करता है thisऔर एक अनबाउंड आंशिक फ़ंक्शन चाहता था।
बरगी

@Bergi: मैं मान रहा था कि सेटिंग thisका उद्देश्य यह नहीं है कि फ़ंक्शन उपयोग करता है this, लेकिन वे उस पल से इसे बांधना नहीं चाहते थे। इसके अलावा, ओपी के सवाल में बिट इसके //These should both have exact same output.अन्य भागों के विरोधाभासी है।
कंतस 94 हेवी

1
@ क्यूबाविकॉस्टेक: हाँ, यह आंशिक निर्माण कार्य करने के लिए है, उपवर्ग की तरह थोड़े (ऐसा नहीं है कि मैं यह सलाह देता हूँ, यद्यपि)। एक वास्तविक bindनिर्माणकर्ताओं के साथ बिल्कुल भी काम नहीं करता है, बाध्य कार्यों के पास नहीं है .prototype। नहीं,Function.prototype !== mymethod.prototype
बर्गी

7

केवल मनोरंजन के लिए एक और छोटा कार्यान्वयन:

function bindWithoutThis(cb) {
    var bindArgs = Array.prototype.slice.call(arguments, 1);

    return function () {
        var internalArgs = Array.prototype.slice.call(arguments, 0);
        var args = Array.prototype.concat(bindArgs, internalArgs);
        return cb.apply(this, args);
    };
}

कैसे इस्तेमाल करे:

function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");

ऐसा लगता है कि लागू होने पर इसके लिए "अशक्त" पास करना अधिक सही होगा ()
eddiewould

6
var b = function() {
    return c(1,2,3);
};

3
इन सभी शोर और अस्पष्ट जवाबों में यह एक सटीक और सहायक उत्तर है। इसके बाद +1। हो सकता है कि आप उत्तर की शैली को परिष्कृत कर सकें, क्योंकि यह जंगल के बाकी फैंसी शोर में नग्न आंखों को और अधिक आकर्षक बना सकता है। const curry = (fn, ...curryArgs) => (...args) => fn(...curryArgs, args)
जोहान्स

2

यह बताना थोड़ा मुश्किल है कि आप आखिरकार क्या करना चाहते हैं क्योंकि उदाहरण मनमाना है, लेकिन आप भाग-दौड़ (या करी) में देखना चाहते हैं: http://jsbin.com/ifoqoj/1/edit

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

var c = function(a, b, c, callback) {
  console.log( a, b, c, callback )
};

var b = c.partial(1, 2, 3, undefined);

b(function(){})

जॉन रेसिग के लेख का लिंक: http://ejohn.org/blog/partial-functions-in-javascript/


यह फ़ंक्शन काम नहीं करता है, आप एक से अधिक बार आंशिक रूप से लागू फ़ंक्शन को कॉल नहीं कर सकते।
बरगी

निश्चित नहीं कि मैं अनुसरण करूं। क्या आप उस पर थोड़ा विस्तार कर सकते हैं या एक jsbin उदाहरण पोस्ट कर सकते हैं?
केविन एननिस

इस उदाहरण को देखें । इसके अलावा, आपकी partialआवश्यकताओं को undefinedकाम करने के लिए तर्कों के साथ बुलाया जाना चाहिए - न कि कोई क्या उम्मीद करेगा, और उन कार्यों पर टूट जाएगा जो मापदंडों की एक मनमानी संख्या लेते हैं।
बरगी

केविन, आपके उत्तर के लिए धन्यवाद। यह वही है जो मैं चाहता हूं, लेकिन मुझे लगता है कि thisवस्तु अभी भी गड़बड़ है। एक नज़र डालें: jsbin.com/ifoqoj/4/edit
Imbue

ओह्ह, गच्चा। वह उदाहरण यह बहुत स्पष्ट करता है कि आप क्या देख रहे हैं।
केविन एननिस

2

हो सकता है आप में से संदर्भ बाध्य करने के लिए चाहते हैं यह पिछले लेकिन अपने कोड में: -

var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3); 

पहले से ही इस उदाहरण के लिए बाध्यकारी लागू किया गया है और बाद में आप इसे बदल नहीं सकते हैं। मैं सुझाव दूंगा कि संदर्भ को इस तरह एक पैरामीटर के रूप में भी उपयोग करें: -

var c = function(a, b, c, callback, ref) {  
    var self = this ? this : ref; 
    // Now you can use self just like this in your code 
};
var b = c.bind(null, 1, 2, 3),
    newRef = this, // or ref whatever you want to apply inside function c()
    d = c.bind(callback, newRef);

1

एक का उपयोग करें protagonist!

var geoOpts = {...};

function geoSuccess(user){  // protagonizes for 'user'
  return function Success(pos){
    if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }

    var data = {pos.coords: pos.coords, ...};

    // now we have a callback we can turn into an object. implementation can use 'this' inside callback
    if(user){
      user.prototype = data;
      user.prototype.watch = watchUser;
      thus.User = (new user(data));
      console.log('thus.User', thus, thus.User);
    }
  }
}

function geoError(errorCallback){  // protagonizes for 'errorCallback'
  return function(err){
    console.log('@DECLINED', err);
    errorCallback && errorCallback(err);
  }
}

function getUserPos(user, error, opts){
  nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}

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

उम्मीद है की यह मदद करेगा!


1

एक अनाम उपयोगकर्ता ने यह अतिरिक्त जानकारी पोस्ट की:

इस पोस्ट में जो पहले से ही प्रदान किया गया है, उस पर निर्माण - मैंने देखा है कि आपकी दलीलें और संदर्भ करी है:

function Class(a, b, c, d){
    console.log('@Class #this', this, a, b, c, d);
}

function Context(name){
    console.log('@Context', this, name);
    this.name = name;
}

var context1 = new Context('One');
var context2 = new Context('Two');

function curryArguments(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function bindContext() {
      var additional = Array.prototype.slice.call(arguments, 0);
      return fn.apply(this, args.concat(additional));
    };
}

var bindContext = curryArguments(Class, 'A', 'B');

bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);

1

खैर आपने जो छूट दी, उसके लिए यह करेंगे

var b= function(callback){
        return obj.c(1,2,3, callback);
};

यदि आप मापदंडों के बाड़े का अनुमान लगाना चाहते हैं:

var b= (function(p1,p2,p3, obj){
        var c=obj.c;
        return function(callback){
                return c.call(obj,p1,p2,p3, callback);
        }
})(1,2,3,obj)

लेकिन अगर ऐसा है तो आपको सिर्फ अपने समाधान के लिए रहना चाहिए:

var b = obj.c.bind(obj, 1, 2, 3);

यह बेहतर तरीका है।


1

सरल जैसे की वह?

var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object

अधिक सामान्य समाधान:

function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)

original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5


1

LoDash का उपयोग करके आप _.partialफ़ंक्शन का उपयोग कर सकते हैं ।

const f  = function (a, b, c, callback) {}

const pf = _.partial(f, 1, 2, 3)  // f has first 3 arguments bound.

pf(function () {})                // callback.

0

मिथक के रूप में इसे बचाने के लिए फ़ंक्शन के चारों ओर एक आवरण का उपयोग क्यों न करें?

function mythis() {
  this.name = "mythis";
  mythis = this;
  function c(a, b) {
    this.name = "original";
    alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
    return "ok";
  }    
  return {
    c: c
  }
};

var retval = mythis().c(0, 1);

-1

jQuery 1.9 प्रॉक्सी फ़ंक्शन के साथ वास्तव में उस सुविधा को लाया।

JQuery 1.9 के रूप में, जब संदर्भ अशक्त या अपरिभाषित है, तो प्रॉक्सी फ़ंक्शन को उसी ऑब्जेक्ट के साथ बुलाया जाएगा, जिस तरह प्रॉक्सी को बुलाया गया था। यह $ .proxy () को संदर्भ को बदले बिना किसी फ़ंक्शन के तर्कों को आंशिक रूप से लागू करने के लिए उपयोग करने की अनुमति देता है।

उदाहरण:

$.proxy(this.myFunction, 
        undefined /* leaving the context empty */, 
        [precededArg1, precededArg2]);

-5

Jquery उपयोग मामला:

बजाय:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(i){
        $(this).val(i); // wont work, because 'this' becomes 'i'
    }.bind(i));
}

इसे इस्तेमाल करो:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(e){
        var i = this;
        $(e.originalEvent.target).val(i);
    }.bind(i));
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.