Việc sử dụng phương pháp 'liên kết' JavaScript là gì?


651

Việc sử dụng bind()JavaScript là gì?


8
Trường hợp sử dụng tiêu chuẩn của tôi:select = document.querySelector.bind(document)
ceving

1
^ Và đối với bất cứ ai tự hỏi, lý do cần thiết là vì thisnếu không thì sẽ đề cập đến window, đối tượng toàn cầu. Với document.querySelector.bind(document), chúng tôi đảm bảo rằng selectthisđề cập đến document, và không window. Ai đó sửa tôi nếu tôi hiểu lầm rằng, mặc dù.
Alexanderr

Câu trả lời:


613

Bind tạo ra một hàm mới sẽ buộc thisbên trong hàm phải là tham số được truyền vào bind().

Đây là một ví dụ cho thấy cách sử dụng bindđể truyền một phương thức thành viên xung quanh có chính xác 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

Mà in ra:

OK clicked
undefined clicked
OK clicked

Bạn cũng có thể thêm các tham số bổ sung sau tham số 1st ( this) và bindsẽ chuyển các giá trị đó cho hàm ban đầu. Bất kỳ tham số bổ sung nào sau này bạn chuyển đến hàm bị ràng buộc sẽ được truyền vào sau các tham số bị ràng buộc:

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

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

Mà in ra:

15

Kiểm tra liên kết Hàm JavaScript để biết thêm thông tin và ví dụ tương tác.

Cập nhật: ECMAScript 2015 bổ sung hỗ trợ cho các =>chức năng. =>các hàm nhỏ gọn hơn và không thay đổi thiscon trỏ từ phạm vi xác định của chúng, vì vậy bạn có thể không cần sử dụng bind()thường xuyên. Ví dụ: nếu bạn muốn một hàm trên Buttontừ ví dụ đầu tiên kết nối cuộc clickgọi lại với một sự kiện DOM, thì đây là tất cả các cách hợp lệ để thực hiện điều đó:

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

Hoặc là:

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() });
  }
};    

Hoặc là:

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

6
Giải thích tuyệt vời, nhưng tôi đang vật lộn để tìm các ví dụ mà tôi muốn sử dụng tùy chọn thứ ba mà bạn đã mô tả thay vì tùy chọn đầu tiên. Bạn có thể mô tả các tình huống mà bạn cảm thấy cần phải sử dụng tùy chọn thứ ba không?
Darryl

5
Tôi không nghĩ rằng tôi đã từng sử dụng ràng buộc khác hơn là ràng buộc 'cái này'. Hình thức khác được gọi là Ứng dụng một phần và khá phổ biến trong các ngôn ngữ chức năng. Tôi tưởng tượng nó được bao gồm cho sự hoàn chỉnh.
nkron

42
Trong trường hợp bất cứ ai thắc mắc tại sao LooseClick () không bị ràng buộc với myButton, thì đó là vì "điều này" đề cập đến đối tượng gọi hàm (LooseClick ()). Đối tượng gọi LooseClick () là đối tượng toàn cục.
pokero

4
@Darryl - Một lý do tại sao sẽ là để truyền tham số từ trình xử lý sự kiện. Nếu bạn có mã phản ứng này: var Note = React.createClass({ add: function(text){ ... }, render: function () { return <button onClick={this.add.bind(null, "New Note")}/> } }thì khi nhấp vào nút, nó sẽ chuyển một văn bản tham số "Ghi chú mới" cho addphương thức.
P. Myer Nore

2
"Bạn cũng có thể thêm các tham số bổ sung sau tham số thứ nhất và liên kết sẽ chuyển các giá trị đó cho hàm ban đầu trước khi chuyển các tham số bổ sung mà bạn chuyển sang hàm bị ràng buộc:" Từ ngữ này gây nhầm lẫn.
Ken Ingram

271

Việc sử dụng đơn giản nhất bind()là tạo ra một hàm, cho dù nó được gọi như thế nào, được gọi với một thisgiá trị cụ thể .

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

Vui lòng tham khảo liên kết này để biết thêm thông tin

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


38
Giới thiệu tốt nhất về bind () tôi từng thấy.
thomasfl

3
Câu trả lời tuyệt vời, vì ví dụ của bạn không yêu cầu kiến ​​thức về các tính năng ngôn ngữ (ví dụ prototype) có thể mới đối với người mới bắt đầu.
Edward

1
cô đọng & rất rõ ràng!
papigee

172

ràng buộc cho phép-

  • đặt giá trị của "cái này" cho một đối tượng cụ thể. Điều này trở nên rất hữu ích vì đôi khi đây không phải là mục đích.
  • phương pháp sử dụng lại
  • cà ri một chức năng

Ví dụ: bạn có chức năng khấu trừ phí câu lạc bộ hàng tháng

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

Bây giờ bạn muốn sử dụng lại chức năng này cho một thành viên câu lạc bộ khác. Lưu ý rằng phí hàng tháng sẽ thay đổi từ thành viên này sang thành viên khác.

Hãy tưởng tượng Rachel có số dư 500 và phí thành viên hàng tháng là 90.

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

Bây giờ, hãy tạo một chức năng có thể được sử dụng nhiều lần để khấu trừ phí từ tài khoản của cô ấy mỗi tháng

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

Bây giờ, chức năng getMonthlyFee tương tự có thể được sử dụng cho một thành viên khác với phí thành viên khác. Ví dụ: Ross Geller có số dư 250 và phí hàng tháng là 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
Trong ví dụ của bạn, tôi nghĩ rằng tôi sẽ có xu hướng thiết lập một đối tượng thành viên ngay lập tức với từ khóa mới nơi mỗi thành viên có các thuộc tính / phương thức riêng. Sau đó, nó chỉ đơn giản là vấn đề của ross.getMonthlyFee (25). Có phải ví dụ này chỉ để chứng minh việc sử dụng bind (), hoặc có một số lợi thế cho cách tiếp cận của bạn?
Darryl

yêu cà ri một chức năng!
Jerry Liu

tôi không biết, nhưng tôi sẽ làm var getRachelFee = getMonthlyFee (rachel, 90); Và hàm sẽ là hàm getMonthlyFee (thành viên, phí) {} một cái gì đó dọc theo dòng.
Miguel

1
@KhanSharp Câu trả lời của bạn là chính xác, nhưng đó là tài liệu tham khảo của bạn về bạn bè trên TV khiến tôi nhận xét và upvote. Cảm ơn bạn đã trả lời.
Saurabh Lende

79

Từ các tài liệu MDN trên Function.prototype.bind():

Phương thức bind () tạo ra một hàm mới, khi được gọi, từ khóa này được đặt thành giá trị được cung cấp, với một chuỗi các đối số đã cho trước bất kỳ được cung cấp nào khi hàm mới được gọi.

Vậy điều đó có ý nghĩa gì?!

Chà, hãy lấy một chức năng trông như thế này:

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

Bây giờ, hãy lấy một đối tượng trông như thế này:

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

Chúng ta có thể liên kết chức năng của mình với đối tượng như thế này:

Obj.log = logProp.bind(Obj);

Bây giờ, chúng tôi có thể chạy Obj.logbất cứ nơi nào trong mã của chúng tôi:

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

Điều này hoạt động, bởi vì chúng tôi ràng buộc giá trị của thisđối tượng của chúng tôi Obj.


Nơi nó thực sự trở nên thú vị, là khi bạn không chỉ ràng buộc một giá trị cho this, mà còn cho đối số của nó prop:

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

Bây giờ chúng ta có thể làm điều này:

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

Không giống như Obj.log, chúng tôi không phải vượt qua xhoặc y, bởi vì chúng tôi đã vượt qua những giá trị đó khi chúng tôi thực hiện ràng buộc của mình.


9
Câu trả lời này sẽ nhận được nhiều tình yêu hơn. Giải thích tốt.
Chax

Kết hợp rất tốt của tổng quan chung và ví dụ cụ thể.
Ken Ingram

Nút chụp lên 100 điểm ở đâu?
kushalvm

Với điều này, tôi cũng khuyên bạn nên đọc phần tài liệu MDN của các hàm được áp dụng một phần để hiểu việc sử dụng liên kết "null". Nó sẽ đóng cổng cho hầu hết các sử dụng liên kết. developer.mozilla.org/en/docs/Web/JavaScript/Reference/
Kẻ

23

Biến có phạm vi địa phương và toàn cầu. Giả sử rằng chúng ta có hai biến có cùng tên. Một cái được định nghĩa toàn cục và cái kia được định nghĩa bên trong một hàm đóng và chúng ta muốn lấy giá trị biến bên trong hàm đóng. Trong trường hợp đó, chúng tôi sử dụng phương thức bind () này. Xin vui lòng xem ví dụ đơn giản dưới đây:

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

Tóm lược:

Các bind()phương pháp có một đối tượng như một tham số đầu tiên và tạo ra một chức năng mới. Khi hàm được gọi, giá trị của thistrong thân hàm sẽ là đối tượng được truyền vào dưới dạng đối số trong bind()hàm.

Làm thế nào để thislàm việc trong JS nào

Giá trị của thisjavascript phụ thuộc luôn phụ thuộc vào đối tượng mà hàm được gọi. Giá trị của điều này luôn đề cập đến đối tượng bên trái của dấu chấm từ đó hàm được gọi . Trong trường hợp phạm vi toàn cầu, đây là window(hoặc globaltrong nodeJS). Chỉ call, applybindcó thể thay đổi ràng buộc này khác nhau. Dưới đây là một ví dụ để cho thấy từ khóa này hoạt động như thế nào:

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

Liên kết được sử dụng như thế nào?

Bind có thể giúp khắc phục khó khăn với thistừ khóa bằng cách có một đối tượng cố định nơi thissẽ tham chiếu. Ví dụ:

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'

Khi hàm được liên kết với một thisgiá trị cụ thể, chúng ta có thể chuyển nó xung quanh và thậm chí đặt nó vào các thuộc tính trên các đối tượng khác. Giá trị của thissẽ vẫn như cũ.


3
Nhận xét của bạn trong mã của bạn về objđối tượng là vì nó nằm bên trái dấu chấm và windowlà đối tượng vì nó là tốc ký window.custFunc()windowcòn lại của dấu chấm rất sâu sắc đối với tôi.
nzaleski

12

Tôi sẽ giải thích ràng buộc về mặt lý thuyết cũng như thực tế

liên kết trong javascript là một phương thức - Function.prototype.bind. liên kết là một phương pháp. Nó được gọi là nguyên mẫu chức năng. Phương thức này tạo ra một hàm có thân tương tự như hàm được gọi nhưng 'cái này' chỉ tham số đầu tiên được truyền cho phương thức liên kết. Cú pháp của nó là

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

Thí dụ:--

  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;

Về cơ bản, nó biến bất cứ thứ gì 'cái này' bên trong hàm thành bất kỳ đối tượng nào bạn truyền vào, đúng không?
Harvey Lin

11

Phương thức bind () tạo ra một thể hiện hàm mới có giá trị này được liên kết với giá trị được truyền vào bind (). Ví dụ:

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

Ở đây, một hàm mới gọi là objectSayColor () được tạo từ sayColor () bằng cách gọi bind () và truyền vào đối tượng o. Hàm objectSayColor () có giá trị này tương đương với o, do đó, việc gọi hàm, ngay cả như một cuộc gọi toàn cầu, dẫn đến chuỗi Chuỗi màu xanh da trời được hiển thị.

Tham khảo: Nicholas C. Zakas - JAVASCRIPT® CHUYÊN NGHIỆP CHO CÁC NHÀ PHÁT TRIỂN WEB


ví dụ súc tích và ngắn gọn
Ahmad Sharif

9

Tạo một hàm mới bằng cách liên kết các đối số với các giá trị

Các bindphương pháp tạo ra một chức năng mới từ một chức năng với một hoặc nhiều đối số ràng buộc để các giá trị cụ thể, trong đó có tiềm ẩn thisđối số.

Ứng dụng một phần

Đây là một ví dụ về ứng dụng một phần . Thông thường chúng ta cung cấp một hàm với tất cả các đối số của nó mang lại một giá trị. Điều này được gọi là ứng dụng chức năng. Chúng tôi đang áp dụng chức năng cho các đối số của nó.

Hàm bậc cao hơn (HOF)

Ứng dụng một phần là một ví dụ về hàm bậc cao hơn (HOF) vì nó mang lại một hàm mới với số lượng đối số ít hơn.

Liên kết nhiều đối số

Bạn có thể sử dụng bindđể chuyển đổi các hàm có nhiều đối số thành các hàm mới.

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

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

Chuyển đổi từ Phương thức sơ thẩm sang Hàm tĩnh

Trong trường hợp sử dụng phổ biến nhất, khi được gọi với một đối số, bindphương thức sẽ tạo ra một hàm mới có thisgiá trị ràng buộc với một giá trị cụ thể. Trong thực tế, điều này biến đổi một phương thức thể hiện thành một phương thức tĩnh.

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));

Thực hiện một cuộc gọi lại có trạng thái

Ví dụ sau đây cho thấy cách sử dụng ràng buộc thiscó thể cho phép một phương thức đối tượng hoạt động như một cuộc gọi lại có thể dễ dàng cập nhật trạng thái của một đối tượng.

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

Như đã đề cập, Function.bind()cho phép bạn chỉ định ngữ cảnh mà hàm sẽ thực thi (nghĩa là nó cho phép bạn chuyển vào đối tượng mà thistừ khóa sẽ phân giải trong phần thân của hàm.

Một vài phương thức API của bộ công cụ tương tự thực hiện một dịch vụ tương tự:

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

Hãy xem xét Chương trình đơn giản được liệt kê dưới đây,

//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

Hàm liên kết tạo ra một hàm mới có cùng thân hàm với hàm mà nó đang gọi. Nó được gọi với đối số này. Tại sao chúng ta sử dụng liên kết vui vẻ. : khi mỗi khi một cá thể mới được tạo và chúng ta phải sử dụng cá thể ban đầu đầu tiên thì chúng ta sẽ sử dụng liên kết fun. Chúng ta không thể ghi đè liên kết fun.simply nó lưu trữ đối tượng ban đầu của lớp.

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

0

Một cách sử dụng khác là bạn có thể truyền hàm bị ràng buộc làm đối số cho hàm khác đang hoạt động trong bối cảnh thực thi khác.

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

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

0

Ví dụ đơn giản

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

Phương pháp ràng buộc

Việc thực hiện liên kết có thể trông giống như vậy:

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

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

Hàm liên kết có thể nhận bất kỳ số lượng đối số và trả về một hàm mới .

Hàm mới sẽ gọi hàm ban đầu bằng Function.prototype.applyphương thức JS .
Các applyphương pháp sẽ sử dụng đối số đầu tiên truyền cho hàm mục tiêu như bối cảnh của nó ( this), và đối số mảng thứ hai của applyphương pháp sẽ là một sự kết hợp của phần còn lại của các đối số từ hàm mục tiêu, concat với những lập luận sử dụng để gọi sự trở lại chức năng (theo thứ tự đó).

Một ví dụ có thể trông giống như vậy:

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

Giải thích đơn giản:

bind () tạo một hàm mới, một tham chiếu mới tại một hàm mà nó trả về cho bạn.

Trong tham số sau từ khóa này, bạn chuyển vào tham số bạn muốn cấu hình sẵn. Trên thực tế, nó không thực thi ngay lập tức, chỉ chuẩn bị để thực hiện.

Bạn có thể định cấu hình nhiều tham số như bạn muốn.

Ví dụ đơn giản để hiểu ràng buộc:

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

liên kết là một chức năng có sẵn trong nguyên mẫu tập lệnh java, vì tên gợi ý liên kết được sử dụng để liên kết lệnh gọi hàm của bạn với ngữ cảnh mà bạn đang xử lý, ví dụ:

    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%' 

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.