Яке використання методу «прив’язати» JavaScript?


651

Для чого використовується bind()JavaScript?


8
Мій стандартний випадок використання:select = document.querySelector.bind(document)
припинення

1
^ І для всіх, хто цікавиться, причина, яка потрібна, полягає в тому, thisщо в іншому випадку посилатися б windowна глобальний об'єкт. З document.querySelector.bind(document), ми гарантуємо , що select«s thisвідноситься до document, а не window. Хтось мене виправить, якщо я це неправильно зрозумів.
ОлександрХ

Відповіді:


613

Bind створює нову функцію, яка змусить thisвнутрішню функцію передати параметр bind().

Ось приклад, який показує, як використовувати bindдля передачі метод члена навколо, який має правильне this:

var myButton = {
  content: 'OK',
  click() {
    console.log(this.content + ' clicked');
  }
};

myButton.click();

var looseClick = myButton.click;
looseClick(); // not bound, 'this' is not myButton - it is the globalThis

var boundClick = myButton.click.bind(myButton);
boundClick(); // bound, 'this' is myButton

Що виводить:

OK clicked
undefined clicked
OK clicked

Ви також можете додати додаткові параметри після першого thisпараметра ( ) і bindпередаватиме ці значення початковій функції. Будь-які додаткові параметри, які ви пізніше перейдете до зв'язаної функції, будуть передані після зв'язаних параметрів:

// Example showing binding some parameters
var sum = function(a, b) {
  return a + b;
};

var add5 = sum.bind(null, 5);
console.log(add5(10));

Що виводить:

15

Ознайомтесь із функцією JavaScript, що прив'язується, щоб отримати більше інформації та інтерактивні приклади.

Оновлення: ECMAScript 2015 додає підтримку =>функцій. =>функції більш компактні і не змінюють thisвказівник від їх визначеної області, тому, можливо, вам не доведеться використовувати bind()так часто. Наприклад, якщо ви хотіли, щоб функція Buttonз першого прикладу підключила clickзворотний виклик до події DOM, наведені нижче є всі дійсні способи цього:

var myButton = {
  ... // As above
  hookEvent(element) {
    // Use bind() to ensure 'this' is the 'this' inside click()
    element.addEventListener('click', this.click.bind(this));
  }
};

Або:

var myButton = {
  ... // As above
  hookEvent(element) {
    // Use a new variable for 'this' since 'this' inside the function
    // will not be the 'this' inside hookEvent()
    var me = this;
    element.addEventListener('click', function() { me.click() });
  }
};    

Або:

var myButton = {
  ... // As above
  hookEvent(element) {
    // => functions do not change 'this', so you can use it directly
    element.addEventListener('click', () => this.click());
  }
};

6
Відмінне пояснення, але я намагаюся знайти приклади, де я хотів би використати третій варіант, який ви описали замість першого. Чи можете ви описати ситуації, коли відчували потребу використовувати третій варіант?
Дарріл

5
Я не думаю, що я ніколи не використовував палітурку, окрім як палітурку "це". Інша форма відома як часткове застосування і досить поширена у функціональних мовах. Я думаю, він включений для повноти.
nkron

42
Якщо когось цікавить, чому looseClick () не прив’язаний до myButton, це тому, що "це" посилається на об'єкт, який викликає функцію (looseClick ()). Об'єкт, який викликає looseClick (), є глобальним об'єктом.
pokero

4
@Darryl - Однією з причин було б передавати параметри від обробників подій. Якщо у вас є цей код реагування:, var Note = React.createClass({ add: function(text){ ... }, render: function () { return <button onClick={this.add.bind(null, "New Note")}/> } }після натискання кнопки він передасть addметоду текст параметра "Нова примітка" .
P. Myer Nore

2
"Ви також можете додати додаткові параметри після 1-го параметра, і прив'язка передасть ці значення початковій функції перед тим, як передати додаткові параметри, які ви передаєте в зв'язану функцію:" Це формулювання заплутане.
Кен Інграм

271

Найпростіше використання bind()- зробити функцію, яка, як би вона не називалася, викликається з певним thisзначенням.

x = 9;
var module = {
    x: 81,
    getX: function () {
        return this.x;
    }
};

module.getX(); // 81

var getX = module.getX;
getX(); // 9, because in this case, "this" refers to the global object

// create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
boundGetX(); // 81

Будь ласка, перейдіть за цим посиланням для отримання додаткової інформації

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


38
Найкращий вступ до bind (), який я коли-небудь бачив.
thomasfl

3
Чудова відповідь, оскільки ваш приклад не вимагає знань про мовні особливості (наприклад prototype), які можуть бути новинками для початківців.
Едвард

1
стислий і дуже зрозумілий!
papigee

172

прив'язка дозволяє-

  • встановити значення "цього" для конкретного об'єкта. Це стає дуже корисним, як іноді це не те, що призначено.
  • методи повторного використання
  • каррі функції

Наприклад, у вас є функція відрахування щомісячних клубних зборів

function getMonthlyFee(fee){
  var remaining = this.total - fee;
  this.total = remaining;
  return this.name +' remaining balance:'+remaining;
}

Тепер ви хочете повторно використовувати цю функцію для іншого члена клубу. Зауважте, що щомісячна плата залежить від члена до члена.

Уявімо, що Рейчел має баланс 500, а членський внесок щомісяця - 90.

var rachel = {name:'Rachel Green', total:500};

Тепер створіть функцію, яку можна використовувати знову і знову, щоб стягувати плату з її рахунку щомісяця

//bind
var getRachelFee = getMonthlyFee.bind(rachel, 90);
//deduct
getRachelFee();//Rachel Green remaining balance:410
getRachelFee();//Rachel Green remaining balance:320

Тепер та сама функція getMonthlyFee може використовуватися для іншого члена з іншим членським внеском. Наприклад, Росс Геллер має 250 залишків і щомісячну плату 25

var ross = {name:'Ross Geller', total:250};
//bind
var getRossFee = getMonthlyFee.bind(ross, 25);
//deduct
getRossFee(); //Ross Geller remaining balance:225
getRossFee(); //Ross Geller remaining balance:200

9
У вашому прикладі я думаю, що я схильний би встановити об'єкт-член, інстанціонізований новим ключовим словом, де кожен член мав свої властивості / методи. Тоді це просто питання ross.getMonthlyFee (25). Чи був цей приклад лише для того, щоб просто продемонструвати використання bind (), чи є якась перевага у вашому підході?
Дарріл

люблю каррі функцію!
Джеррі Лю

я не знаю, але я би зробив var getRachelFee = getMonthlyFee (rachel, 90); І функцією буде функція getMonthlyFee (член, плата) {} щось уздовж рядків.
Мігель

1
@KhanSharp Ваша відповідь правильна, але саме ваші посилання на телесеріали Друзі змушують мене коментувати та підказувати. Дякую за відповідь 🤗.
Саурах Ленде

79

З Документів MDN на Function.prototype.bind():

Метод bind () створює нову функцію, яка при виклику має своє ключове слово, встановлене заданим значенням, із заданою послідовністю аргументів, що передує будь-якому наданому, коли нова функція викликається.

Отже, що це означає ?!

Що ж, візьмемо функцію, яка виглядає приблизно так:

var logProp = function(prop) {
    console.log(this[prop]);
};

Тепер візьмемо об’єкт, який виглядає приблизно так:

var Obj = {
    x : 5,
    y : 10
};

Ми можемо прив’язати свою функцію до нашого об'єкта так:

Obj.log = logProp.bind(Obj);

Тепер ми можемо працювати в Obj.logбудь-якому місці нашого коду:

Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10

Це працює, тому що ми прив'язуємо значення thisдо нашого об'єкта Obj.


Де насправді стає цікаво, це коли ви прив'язуєте не лише значення this, але й його аргумент prop:

Obj.logX = logProp.bind(Obj, 'x');
Obj.logY = logProp.bind(Obj, 'y');

Тепер ми можемо це зробити:

Obj.logX(); // Output : 5
Obj.logY(); // Output : 10

На відміну від Obj.log, ми не повинні проходити xабо y, тому що ми передавали ці значення, коли ми виконували зв'язування.


9
Ця відповідь повинна отримати більше любові. Добре пояснено.
Чакс

Дуже вдале поєднання загального огляду та конкретного прикладу.
Кен Інграм

Де кнопка, яка знімає прямо 100 підйомів?
кушалвм

З цим я також рекомендую прочитати розділ документів MDN щодо частково застосованих функцій, щоб зрозуміти використання bind "null". Він повинен закривати ворота для більшої частини використання прив'язки. developer.mozilla.org/uk/docs/Web/JavaScript/Reference/…
kushalvm

23

Змінні мають місцеві та глобальні сфери. Припустимо, що у нас є дві змінні з однаковою назвою. Один визначається глобально, а інший визначається всередині закриття функції, і ми хочемо отримати значення змінної, яке знаходиться всередині функції закриття. У цьому випадку ми використовуємо цей метод bind (). Дивіться простий приклад нижче:

var x = 9; // this refers to global "window" object here in the browser
var person = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

var y = person.getX; // It will return 9, because it will call global value of x(var x=9).

var x2 = y.bind(person); // It will return 81, because it will call local value of x, which is defined in the object called person(x=81).

document.getElementById("demo1").innerHTML = y();
document.getElementById("demo2").innerHTML = x2();
<p id="demo1">0</p>
<p id="demo2">0</p>


18

Підсумок:

bind()Метод приймає об'єкт в якості першого аргументу і створює нову функцію. Коли функція викликається, значення thisв тілі функції буде об'єктом, переданим як аргумент вbind() функцію.

Як this працює в JS

Значення thisв javascript залежить завжди залежить від того, який об'єкт викликається функцією. Значення цього завжди посилається на об'єкт, що знаходиться зліва від точки, звідки викликається функція . У випадку глобальної сфери застосування це window(або globalв nodeJS). Тільки call, applyі bindможе змінити це зв'язування по- різному. Ось приклад, який показує, як працює це ключове слово:

let obj = {
  prop1: 1,
  func: function () { console.log(this); } 
}

obj.func();   // obj left of the dot so this refers to obj

const customFunc = obj.func;  // we store the function in the customFunc obj

customFunc();  // now the object left of the dot is window, 
               // customFunc() is shorthand for window.customFunc()
               // Therefore window will be logged

Як застосовується зв'язування?

Прив'язка може допомогти у подоланні труднощів із thisключовим словом, маючи фіксований об’єкт, на який thisбуде посилатися. Наприклад:

var name = 'globalName';

const obj = {
  name: 'myName',
  sayName: function () { console.log(this.name);}
}

const say = obj.sayName; // we are merely storing the function the value of this isn't magically transferred

say(); // now because this function is executed in global scope this will refer to the global var

const boundSay = obj.sayName.bind(obj); // now the value of this is bound to the obj object

boundSay();  // Now this will refer to the name in the obj object: 'myName'

Після того, як функція пов'язана з певним thisзначенням, ми можемо передавати її навколо і навіть розміщувати на властивостях інших об'єктів. Значення thisзалишиться колишнім.


3
Ваші коментарі у вашому коді щодо objоб'єкта є об’єктом, тому що він залишився від крапки і windowє об'єктом, тому що це скорочення window.custFunc()та windowліворуч від точки був дуже проникливим для мене.
nzaleski

12

Я поясню зв'язування як теоретично, так і практично

bind в javascript - метод - Function.prototype.bind. bind - метод. Він викликається прототипом функції. Цей метод створює функцію, тіло якої подібне до функції, за якою вона викликається, але "це" відноситься до першого параметра, переданого методу прив'язки. Його синтаксис є

     var bindedFunc = Func.bind(thisObj,optionsArg1,optionalArg2,optionalArg3,...);

Приклад: -

  var checkRange = function(value){
      if(typeof value !== "number"){
              return false;
      }
      else {
         return value >= this.minimum && value <= this.maximum;
      }
  }

  var range = {minimum:10,maximum:20};

  var boundedFunc = checkRange.bind(range); //bounded Function. this refers to range
  var result = boundedFunc(15); //passing value
  console.log(result) // will give true;

По суті, це робить усе, що "це" всередині функції, в будь-який об'єкт, в який ви переходите, правда?
Харві Лін

11

Метод bind () створює новий екземпляр функції, це значення пов'язане зі значенням, переданим у bind (). Наприклад:

   window.color = "red"; 
   var o = { color: "blue" }; 
   function sayColor(){ 
       alert(this.color); 
   } 
   var objectSayColor = sayColor.bind(o); 
   objectSayColor(); //blue 

Тут нова функція під назвою objectSayColor () створюється з sayColor () шляхом виклику bind () та передачі в об'єкт o. Функція objectSayColor () має це значення, еквівалентне o, тому виклик функції, навіть як глобальний виклик, призводить до відображення рядка "синій".

Довідково: Ніколас Закас - ПРОФЕСІЙНИЙ JAVASCRIPT® ДЛЯ WEB-розробників


лаконічний і лаконічний приклад
Ахмад Шаріф

9

Створення нової функції шляхом прив’язки аргументів до значень

bindМетод створює нову функцію з іншої функції з одним або декількома аргументами , пов'язаних з конкретними значеннями, включаючи неявніthis аргументу.

Часткове застосування

Це приклад часткового застосування . Зазвичай ми постачаємо функцію всіма її аргументами, що дає значення. Це відомо як додаток функції. Ми застосовуємо функцію до її аргументів.

Функція вищого порядку (HOF)

Часткове застосування є прикладом функції вищого порядку (HOF), оскільки воно дає нову функцію з меншою кількістю аргументів.

Пов’язування декількох аргументів

Ви можете використовувати bindдля перетворення функцій з декількома аргументами в нові функції.

function multiply(x, y) { 
    return x * y; 
}

let multiplyBy10 = multiply.bind(null, 10);
console.log(multiplyBy10(5));

Перетворення методу інстанції в статичну функцію

У найбільш поширеному випадку використання, коли викликається одним аргументом, bindметод створить нову функцію, яка має thisзначення, прив'язане до конкретного значення. По суті, це перетворює метод примірника в статичний метод.

function Multiplier(factor) { 
    this.factor = factor;
}

Multiplier.prototype.multiply = function(x) { 
    return this.factor * x; 
}

function ApplyFunction(func, value) {
    return func(value);
}

var mul = new Multiplier(5);

// Produces garbage (NaN) because multiplying "undefined" by 10
console.log(ApplyFunction(mul.multiply, 10));

// Produces expected result: 50
console.log(ApplyFunction(mul.multiply.bind(mul), 10));

Реалізація Stateful CallBack

Наступний приклад показує, як використання прив'язки thisможе дозволити методу об'єкта діяти як зворотний виклик, який може легко оновити стан об'єкта.

function ButtonPressedLogger()
{
   this.count = 0;
   this.onPressed = function() {
      this.count++;
      console.log("pressed a button " + this.count + " times");
   }
   for (let d of document.getElementsByTagName("button"))
      d.onclick = this.onPressed.bind(this);
}

new ButtonPressedLogger();      
<button>press me</button>
<button>no press me</button>


6

Як згадувалося, Function.bind()ви можете вказати контекст, в якому буде виконуватися функція (тобто вона дозволяє передавати в якому об’єкті thisключове слово буде вирішено в тілі функції.

Кілька аналогічних методів API інструментарію, які виконують подібну послугу:

jQuery.proxy ()

Dojo.hitch ()


3
/**
 * Bind is a method inherited from Function.prototype same like call and apply
 * It basically helps to bind a function to an object's context during initialisation 
 * 
 * */

window.myname = "Jineesh";  
var foo = function(){ 
  return this.myname;
};

//IE < 8 has issues with this, supported in ecmascript 5
var obj = { 
    myname : "John", 
    fn:foo.bind(window)// binds to window object
}; 
console.log( obj.fn() ); // Returns Jineesh

3

Розглянемо просту програму, перелічену нижче,

//we create object user
let User = { name: 'Justin' };

//a Hello Function is created to Alert the object User 
function Hello() {
  alert(this.name);
}

//since there the value of this is lost we need to bind user to use this keyword
let user = Hello.bind(User);
user();

//we create an instance to refer the this keyword (this.name);

2

Функція зв'язування створює нову функцію з тим же органом функції, що і функція, яку вона викликає. Вона викликається за допомогою цього аргументу. : коли кожен раз створюється новий екземпляр, і ми маємо використовувати перший початковий екземпляр, тоді ми використовуємо bind fun.Ми не можемо замінити bind fun.simply він зберігає початковий об'єкт класу.

setInterval(this.animate_to.bind(this), 1000/this.difference);

0

Інше використання полягає в тому, що ви можете передати прив'язану функцію як аргумент іншій функції, яка працює в іншому контексті виконання.

var name = "sample";
function sample(){
  console.log(this.name);
}
var cb = sample.bind(this);

function somefunction(cb){
  //other code
  cb();
}
somefunction.call({}, cb);

0

Простий приклад

function lol(text) {
    console.log(this.name, text);
}

lol(); // undefined undefined
lol('first'); // undefined first
lol.call({name: 'karl'}); // karl undefined
lol.call({name: 'karl'}, 'second'); // karl second
lol.apply({name: 'meg'}); // meg undefined
lol.apply({name: 'meg'}, ['third']); // meg third
const newLol = lol.bind({name: 'bob'});
newLol(); // bob undefined
newLol('fourth'); // bob fourth

0

Спосіб зв’язування

Реалізація прив'язки може виглядати приблизно так:

Function.prototype.bind = function () {
  const self = this;
  const args = [...arguments];
  const context = args.shift();

  return function () {
    return self.apply(context, args.concat([...arguments]));
  };
};

Функція прив'язки може приймати будь-яку кількість аргументів і повертати нову функцію .

Нова функція викличе початкову функцію за допомогою Function.prototype.applyметоду JS . Метод буде використовувати перший аргумент , який передається цільову функцію в якості контексту ( ), а другий аргумент масиву з методу буде являти собою поєднання інших аргументів з цільової функції, CONCAT з аргументами використовується для виклику повернення функція (у такому порядку). Приклад може виглядати приблизно так:
applythisapply

function Fruit(emoji) {
  this.emoji = emoji;
}

Fruit.prototype.show = function () {
  console.log(this.emoji);
};

const apple = new Fruit('🍎');
const orange = new Fruit('🍊');

apple.show();  // 🍎
orange.show(); // 🍊

const fruit1 = apple.show;
const fruit2 = apple.show.bind();
const fruit3 = apple.show.bind(apple);
const fruit4 = apple.show.bind(orange);

fruit1(); // undefined
fruit2(); // undefined
fruit3(); // 🍎
fruit4(); // 🍊


0

Просте пояснення:

bind () створити нову функцію, нову посилання на функцію, яку вона поверне вам.

У параметрі після цього ключового слова ви передаєте параметр, який потрібно попередньо налаштувати. Насправді вона виконується не відразу, просто готується до виконання.

Ви можете попередньо налаштувати скільки завгодно параметрів.

Простий приклад для розуміння зв'язування:

function calculate(operation) {
  if (operation === 'ADD') {
   alert('The Operation is Addition');
  } else if (operation === 'SUBTRACT') {
   alert('The Operation is Subtraction');
  }
}

addBtn.addEventListener('click', calculate.bind(this, 'ADD'));
subtractBtn.addEventListener('click', calculate.bind(this, 'SUBTRACT'));

-1

bind - це функція, яка доступна в прототипі Java-скрипта, оскільки ім'я передбачає, що прив'язка використовується для прив'язки виклику функції до контексту, з яким ви маєте справу, наприклад:

    var rateOfInterest='4%';
    var axisBank=
    {
    rateOfInterest:'10%',
    getRateOfInterest:function()
    {
    return this.rateOfInterest;
    }
    }
    axisBank.getRateOfInterest() //'10%' 


    let knowAxisBankInterest=axisBank.getRateOfInterest // when you want to assign the function call to a varaible we use this syntax
    knowAxisBankInterest(); // you will get output as '4%' here by default the function is called wrt global context

let knowExactAxisBankInterest=knowAxisBankInterest.bind(axisBank);     //so here we need bind function call  to its local context


    knowExactAxisBankInterest() // '10%' 

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.