Function Invocation
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:
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 “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 apply
và call
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
}
};
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 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.
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, person
và john
, 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àmg, 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.