এটি আবদ্ধ না করে ফাংশন আর্গুমেন্টগুলি কীভাবে আবদ্ধ করবেন?


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
যদি ফাংশনটির ইতিমধ্যে এই সীমাবদ্ধ থাকে, তবে প্রথমে বাঁধাইয়ের যুক্তি হিসাবে নাল ব্যবহার করা বিষয়গুলিকে বিঘ্নিত করবে (অর্থাত্ কোনও অবজেক্ট পদ্ধতিটিকে বিশ্বজুড়ে আবদ্ধ করুন)।
ইম্বু

1
আপনি যা করার চেষ্টা করছেন তা আমি সত্যিই অস্পষ্ট। আপনার thisজাভাস্ক্রিপ্টে সম্পূর্ণ আনবাউন্ড থাকতে পারে না । এর অর্থ সর্বদা কিছু না কিছু । বাঁধাই তাই thisকরতে thisপরিক্ষেপ ফাংশনের ধারণা অনেক তোলে।
কোজিরো

আমি জেএসে বেশ নতুন। প্রশ্নটি আরও পরিষ্কার করার জন্য আমি সম্পাদনা করেছি। এটি হতে পারে যা আমি চাই তা সম্ভব নয়। ধন্যবাদ।
ইম্বু

উত্তর:


32

আপনি এটি করতে পারেন, তবে এটি "বাধ্যতামূলক" হিসাবে ভাবনা এড়ানো ভাল কারণ এটি "এই" মানটি সেট করার জন্য ব্যবহৃত শব্দটি। সম্ভবত এটি কোনও ফাংশনে যুক্তিগুলিকে "মোড়ানো" হিসাবে ভাবেন?

আপনি যা করেন তা হ'ল একটি ফাংশন তৈরি করুন যা এতে ক্লোজারের মাধ্যমে কাঙ্ক্ষিত যুক্তিগুলি তৈরি করে:

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

আশা করি আমি ঠিক সেখানে বাক্য গঠন পেয়েছি। এটি যা করে তা হ'ল র্যাপডআরগমেন্টস () নামে একটি ফাংশন তৈরি করা (এটি পেডেন্টিক হওয়ার জন্য এটি ভেরিয়েবলের কাছে নির্ধারিত একটি বেনাম ফাংশন) যা আপনি যে কোনও সময় যে কোনও সময় কল করতে পারেন এবং সর্বদা সত্যইআর্গ 1 ভ্যালু এবং আসলআর্গ 2 ভ্যালু এবং আপনি যে কিছু স্থাপন করতে চান তার সাথে কাজ করবে is আছে। আপনি চাইলে কল করার সময় এটি আরও যুক্তি স্বীকার করতেও পারেন। চূড়ান্ত বন্ধনী বন্ধনী পরে গোপন হ'ল প্রথম বন্ধনী। এর ফলে বাহ্যিক ক্রিয়াকলাপটি তত্ক্ষণাত্ সম্পাদিত হওয়ার সাথে সাথে উত্তীর্ণ হওয়া মানগুলির সাথে এবং অভ্যন্তরীণ ফাংশন তৈরি করতে পারে যা পরে বলা যেতে পারে। পাস করা মানগুলি তখন ফাংশনটি উত্পন্ন করার সময় হিমায়িত হয়।

এটি কার্যকরভাবে বাঁধাই কী করে, তবে এটি পরিষ্কারভাবে বোঝা যায় যে মোড়ানো যুক্তিগুলি কেবল স্থানীয় ভেরিয়েবলগুলিতে ক্লোজার হয় এবং এর আচরণ পরিবর্তন করার প্রয়োজন নেই।


16
মনে রাখবেন এটিকে সাধারণত "কারিইং" বলা হয়।
এম

@ এম 3 ডি ক্যাপিটালাইজিং যা এটিকে এত অদ্ভুত দেখাচ্ছে।
অ্যান্ড্রু

এটি কীভাবে এটি ব্যবহার করতে হয় তার একটি উদাহরণ সরবরাহ করা থাকলে এটি আরও অনেক সহায়ক হবে।
অ্যান্ড্রু

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

ইএস In-তে, স্প্রেড অপারেটরের সাথে মিল রেখে বিশ্রামের পরামিতিগুলি ব্যবহার করে এটি সহজেই করা যায় ।

সুতরাং আমরা এমন একটি ফাংশন সংজ্ঞায়িত করতে পারি 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
টেবিল এ এস 6 এনেছে, এখনও বিভিন্ন ব্যবহার করে :(
ড্যানিয়েল কোবে

7
@ ড্যানিয়েলকোব ধন্যবাদ! স্প্রেড অপারেটর এবং বাকী প্যারামগুলি ফায়ারফক্সে অনেক আগে প্রয়োগ করা হয়েছিল letএবং constএটি প্রথম পোস্ট করার সময় পর্যন্ত পাওয়া যায় নি। এটি এখন আপডেট হয়েছে।
0

এটি দুর্দান্ত এবং কলব্যাক ফাংশনের জন্য কাজ করে! চার্জগুলি যুক্ত করার পরিবর্তে চারপাশে পরিবর্তন করা যেতে পারে them
ডেনিসম

1
উল্লেখযোগ্য যে এটি প্রতিবারে বাইন্ডআরগস () নামে ডাকা হয়, যার অর্থ পারফরম্যান্স নেটিভ বাইন্ড () কার্যকারিতা ব্যবহার করার মতো ততটা ভাল নয় as
জোশুয়া ওয়ালশ

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
@ জ্যাকডবার্নিয়ার: আপনার দরকার নেই তবে আমি এটির মতো একটি পদ্ধতি হিসাবে আরও স্বজ্ঞাত বলে মনে করি bind। আপনি সহজেই এটিকে রূপান্তর করতে পারেনfunction bindArgs(fn){ …, args = slice.call(arguments, 1); …}
বার্গি

@ কোয়ান্টাস ৯৪ হ্যাভি: আপনি যখন যত্নশীল হবেন তখন আপনাকে সর্বদা এটি thisকরতে হবে a। আপনি bindঅবশ্যই পরিবর্তে ব্যবহার করতে পারেন । তবুও, ওপি স্পষ্টভাবে মানটির কোনও যত্ন করে না thisএবং একটি আনবাউন্ড আংশিক ফাংশন চেয়েছিল।
বার্গি

@ বার্গি: আমি অনুমান করছিলাম যে সেটিং না করার উদ্দেশ্যটি 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");

দেখে মনে হচ্ছে এটি প্রয়োগ করার সময় "নাল" পাস করা আরও সঠিক হবে ()
এডিডুওলড

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-funitions-in- জাভাস্ক্রিপ্ট /


এই ফাংশনটি কাজ করে না, আপনি একাধিকবার আংশিক প্রয়োগ ফাংশনটি কল করতে পারবেন না।
বার্গি

আমি অনুসরণ করছি নিশ্চিত না। আপনি কি কিছুটা বিশদভাবে বলতে পারেন বা জেসবিনের উদাহরণ পোস্ট করতে পারেন?
কেভিন এনিস

এই উদাহরণটি দেখুন । এছাড়াও, আপনার আর্গুমেন্টগুলির সাথে কাজ 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);

এটা ভাল উপায়।




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(this.myFunction, 
        undefined /* leaving the context empty */, 
        [precededArg1, precededArg2]);

-5

জেকুরি ব্যবহারের কেস:

পরিবর্তে:

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));
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.