1. Bind trong JavaScript là gì?

Bind là một phương thức nằm trong Function.prototype , do đó chỉ có function mới có khả năng gọi nó. Chúng ta gọi phương thức bind để xác định tham số this cho một function . Phương thức bind tạo ra một phương thức mới, khi được gọi, từ khóa this của nó được đặt thành giá trị được cung cấp, với một chuỗi đối số nhất định đứng trước bất kỳ đối số nào được cung cấp khi phương thức mới được gọi.

Cú pháp minh họa

fn.bind(thisArg[, arg1[, arg2[, ...]]])

Trong cú pháp này, phương thức bind() trả về một bản sao của hàm fn với giá trị cụ thể this(thisArg) và các đối số (arg1, arg2,…). Không giống như phương thức call() hay phương thức apply() , phương thức bind() không thực thi ngay hàm. Nó chỉ trả về một phiên bản mới của hàm mà nó được đặt thành đối số thisArg .

Ví dụ:

<script>
const person = {
firstName: 'Thành',
lastName: 'Nguyễn',
showName: function() {
document.write(this.firstName + ' ' + this.lastName);
}
};
//showName truyền vào như callback, ở đây this chính là button
$('button').click(person.showName); 
// Dùng bind để xác định giá trị this
$('button').click(person.showName.bind(person)); //this ở đây vẫn là object person
</script>

2. Sử dụng bind để liên kết hàm

Khi ta truyền một phương thức, một đối tượng đến một hàm khác dưới dạng callback , thì this sẽ bị mất. Ví dụ:

<script>
const sinhVien = {
    Name: "Thành Nguyễn",
    getName: function() {
        document.write(this.Name);
    }
};

setTimeout(sinhVien.getName, 1000);
</script>

Như bạn có thể thấy rõ ràng là sinhVien.getName trả về undefined mà không phải là Thành Nguyễn . Hàm this bên trong hàm setTimeout() được đặt thành đối tượng toàn cục ở chế độ không nghiêm ngặt (non-strict mode) và undefined trong chế độ nghiêm ngặt (strict mode). Để tránh trường hợp này, ta có thể bọc lệnh gọi đến phương thức sinhVien.getName trong một hàm ẩn danh (anonymous function), như sau:

setTimeout(function() {
    sinhVien.getName();
}, 1000);

Cách này sẽ hoạt động đúng mong đợi vì nó lấy sinhVien từ phạm vi bên ngoài và sau đó gọi phương thức getName() . Hoặc có thể sử dụng phương thức bind() mà JS cung cấp:

// Sử dụng bind()
const f = sinhVien.getName.bind(sinhVien);
setTimeout(f, 1000);

Dòng lệnh đầu tiên sẽ liên kết sinhVien.getName đến đối tượng sinhVien sau đó gán vào f . Thứ hai, ta chuyển hàm ràng buộc f với giá trị this đã được đặt cho đối tượng sinhVien vào hàm setTimeout() .

3. Sử dụng phương thức bind() để mượn phương thức từ đối tượng khác

Với phương thức bind() , một đối tượng có thể mượn một phương thức từ một đối tượng khác.

Ví dụ: ta sẽ tạo ra 2 đối tượng. Đối tượng member mượn phương thức tên đầy đủ từ đối tượng person :

<script>
const person = {
  firstName:"Thành",
  lastName: "Nguyễn",
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

const member = {
  firstName:"Nam",
  lastName: "Chu",
}

let fullName = person.fullName.bind(member);

document.write(fullName());
</script>

Khả năng mượn một phương thức của một đối tượng mà không cần tạo bản sao của phương thức đó và duy trì nó ở hai nơi riêng biệt là tính năng rất mạnh trong Js. Tính năng này sẽ giúp ích cho ta rất nhiều khi học nâng cao lên front end Framework như React, Angular…

4. Phương thức bind và this trong JavaScript

Đôi khi phương thức bind() này phải được sử dụng để ngăn chặn việc làm mất this .

Trong ví dụ sau, đối tượng person có một phương thức hiển thị. Trong phương thức hiển thị, this đề cập đến đối tượng person :

<p id="demo"></p>

<script>
const person = {
  firstName:"Thành",
  lastName: "Nguyễn",
  display: function() {
    let x = document.getElementById("demo");
    x.innerHTML = this.firstName + " " + this.lastName;
  }
}

person.display();
</script>

Khi một hàm được sử dụng làm lệnh gọi lại, this sẽ bị mất.

Ví dụ này sẽ cố gắng hiển thị tên người sau 3 giây, nhưng thay vào đó nó sẽ hiển thị undefined :

<p id="demo"></p>

<script>
const person = {
  firstName:"Thành",
  lastName: "Nguyễn",
  display: function() {
    let x = document.getElementById("demo");
    x.innerHTML = this.firstName + " " + this.lastName;
  }
}

setTimeout(person.display, 3000);
</script>

Phương thức bind() giải quyết vấn đề này. Trong ví dụ sau, bind() được sử dụng để liên kết person.display với person . Ví dụ này sẽ hiển thị tên người sau 3 giây:

<p id="demo"></p>

<script>
const person = {
  firstName:"Thành",
  lastName: "Nguyễn",
  display: function() {
    let x = document.getElementById("demo");
    x.innerHTML = this.firstName + " " + this.lastName;
  }
}

let display = person.display.bind(person);
setTimeout(display, 3000);
</script>