Function Invocation

Tuan Anh Le
andy.le
Published in
4 min readDec 31, 2018
Feature image

Khác với các ngôn ngữ lập trình hướng đối tượng, trong JavaScript, function là một object “đặc biệt". Các function này cùng kế thừa một thuộc tính this. Giá trị của thuộc tính này thay đổi tuỳ theo cách thức function được gọi (way of function's invoke).

Bài viết này liệt kê các cách thức gọi function khác nhau trong JavaScript, cùng với ý nghĩa tương ứng của this

Gọi function trực tiếp

Khi function được gọi trực tiếp, giá trị của this được gán cho đối tượng global. Trong môi trường của một trình duyệt, đối tượng global chính là một window. Hãy xem xét một ví dụ cụ thể:

function setFirstName() {
this.name = 'bob';
}

Copy function trên vào phần console của trình duyệt:

Gọi function theo hình thức trực tiếp

Theo output của console, từ khoá this được liên kết với đối tượng window. Do đó sau khi thực thi function trực tiếp, thuộc tính window.name sẽ mang gía trị “bob".

Gọi function thông qua method

Theo cách gọi này, function là method của một đối tượng nhất định. Giá trị của this theo đó sẽ gắn liền với đối tượng chứa method.

const person = {
firstName: 'daniel',
setFirstName: function(firstName) {
this.firstName: firstName;
}
};
Gọi function thông qua method

Gọi function thông qua “apply” và "call"

Bằng cách sử dụng apply hoặc call, chúng ta có thể “chủ động” gán giá trị của this cho một đối tượng xác định. Method applycall cho phép chúng ta truyền vào một đối tượng JavaScript như một tham số, và yêu cầu JavaScript engine gán giá trị của this cho đối tượng truyền vào.

const person = {
firstName: 'daniel',
setFirstName: function(firstName) {
this.firstName: firstName
}
};
Gọi function thông qua call

Trong ví dụ trên, setFirstName vẫn là một method của đối tượng. Tuy nhiên, bằng cách sử dụng call hoặc apply, giá trị this được gắn với đối tượng window.

Áp dụng call hoặc apply đều trả về kết quả tương tự, ngoại trừ tham số truyền vào apply phải mang kiểu array.

Gọi function thông qua apply

Gọi function thông qua bind

Ngoài cách sử dụng apply hay call, chúng ta cũng có thể sử dụng bind để chủ động thay đổi giá trị của this. Tuy nhiên, phương thức bind không thực thi function, mà sẽ trả lại một đối tượng function mới.

Gọi function thông qua phương thức bind

Một số ứng dụng từ cách gọi function

Trong các phần trước, chúng ta đã tìm hiểu qua một số cách gọi function. Câu hỏi tiếp theo, vậy cách cách gọi khác nhau có tác dụng gì trong thực tế.

Hãy cũng xem xét hai trường hợp cụ thể

  • Function borrowing
  • Curry method

Function borrowing

Giả sử có hai object, personjohn, như sau:

const person = {
name: 'daniel',
setFirstName: function(name) {
this.firstName = name;
}
};
const john = {
name: 'john'
}

Object john không chứa method nào để thay đổi thuộc tính name, tuy nhiên nhờ việc sử dụng method call, nó có thể “kế thừa” method setFirstName từ object person,

person.setName.call(john, 'newJohn');
console.log(john);

Curry method

Với cách giải thích đơn giản, Currying là một quá trình biến đổi một function với nhiều tham số thành một function với ít tham số hơn, “chuyên biệt" hơn. Từ khoá curry được đưa ra dựa theo tên của Haskell Curry, nhà toán học người Mĩ, người tiên phong trong việc xây dựng mô hình tính toán: lambda calculus

Quá trình currying có thể giải thích qua công thức biến đổi hàm số trong toán học như sau:

f: (X, Y, Z) -> N
curry(f): (g: X -> (h: Y -> (k: Z -> N)))

Trong ví dụ trên, hàm số f, bao gồm ba tham số, X, Y, và Z. Quá trình currying chuyển đổi việc đánh giá hàm số f, thông qua một chuỗi các hàm g, h, k. Mỗi phần tử trong chuỗi hàm số chỉ nhận duy nhất một tham số đầu vào.

Quá trình currying có thể được tạo ra qua việc sử dụng bind (hoặc qua nested function)

function multiply(a, b, c) {
return 100 * a + 10 * b + c;
};
const g = multiply.bind(this, 1);
const h = g.bind(this, 1);
const k = h.bind(this, 1);
console.log(multiply(1,1,1)); // print: 111
console.log(k()); // print: 111

Trong ví dụ trên, quá trình trả về giá trị của function multiple(1,1,1) được currying thành việc đánh giá các chuỗi function g, h, k với từng tham số đơn lẻ.

Currying giúp chúng ta xây dựng các higher order function (HOF) từ những function nhỏ hơn. Nói cách khác, nó phân tách việc xử lý logic phức tạp thành những những module nhỏ với tính bảo trì và tái sử dụng tốt hơn.

--

--