Function.prototype.apply()
Baseline
Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Phương thức apply() của các instance Function gọi hàm này với một giá trị this cho trước và các tham số được cung cấp dưới dạng mảng (hoặc một đối tượng giống mảng).
Try it
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max);
// Expected output: 7
const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2
Syntax
apply(thisArg)
apply(thisArg, argsArray)
Parameters
thisArg-
Giá trị của
thisđược cung cấp cho lời gọi hàmfunc. Nếu hàm không ở chế độ strict,nullvàundefinedsẽ được thay thế bằng đối tượng toàn cục, và các giá trị nguyên thủy sẽ được chuyển đổi thành object. argsArrayOptional-
Một đối tượng giống mảng, xác định các tham số mà
funcsẽ được gọi với, hoặcnullhoặcundefinednếu không cần truyền tham số nào cho hàm.
Return value
Kết quả của việc gọi hàm với giá trị this và tham số đã chỉ định.
Description
Note:
Hàm này gần giống hệt call(), ngoại trừ các tham số hàm được truyền vào call() riêng lẻ dưới dạng danh sách, còn với apply() chúng được kết hợp trong một đối tượng, thường là mảng — ví dụ: func.call(this, "eat", "bananas") so với func.apply(this, ["eat", "bananas"]).
Thông thường, khi gọi một hàm, giá trị của this bên trong hàm là đối tượng mà hàm đó được truy cập từ. Với apply(), bạn có thể gán một giá trị tùy ý làm this khi gọi một hàm hiện có, mà không cần gắn hàm đó vào đối tượng như một thuộc tính trước. Điều này cho phép bạn sử dụng các phương thức của một đối tượng như các hàm tiện ích chung.
Bạn cũng có thể sử dụng bất kỳ loại đối tượng giống mảng nào làm tham số thứ hai. Trong thực tế, điều này có nghĩa là nó cần có thuộc tính length và các thuộc tính số nguyên ("chỉ số") trong phạm vi (0..length - 1). Ví dụ, bạn có thể dùng NodeList, hoặc một đối tượng tùy chỉnh như { 'length': 2, '0': 'eat', '1': 'bananas' }. Bạn cũng có thể dùng arguments, ví dụ:
function wrapper() {
return anotherFn.apply(null, arguments);
}
Với rest parameters và spread syntax, đoạn trên có thể được viết lại thành:
function wrapper(...args) {
return anotherFn(...args);
}
Nhìn chung, fn.apply(null, args) tương đương với fn(...args) khi dùng spread syntax, ngoại trừ args được kỳ vọng là đối tượng giống mảng trong trường hợp trước với apply(), và một đối tượng iterable trong trường hợp sau với spread syntax.
Warning:
Không dùng apply() để nối chuỗi các constructor (ví dụ, để thực hiện kế thừa). Việc này gọi hàm constructor như một hàm thông thường, nghĩa là new.target là undefined, và các class sẽ báo lỗi vì chúng không thể được gọi mà không có new. Hãy dùng Reflect.construct() hoặc extends thay thế.
Examples
>Sử dụng apply() để thêm một mảng vào mảng khác
Bạn có thể dùng Array.prototype.push() để thêm một phần tử vào mảng. Vì push() nhận số lượng tham số tùy ý, bạn cũng có thể thêm nhiều phần tử cùng lúc. Tuy nhiên, nếu bạn truyền một mảng vào push(), nó sẽ thêm mảng đó như một phần tử đơn lẻ, thay vì thêm từng phần tử riêng lẻ, kết quả là có một mảng bên trong mảng. Mặt khác, Array.prototype.concat() có hành vi mong muốn trong trường hợp này, nhưng nó không thêm vào mảng hiện có — nó tạo và trả về một mảng mới.
Trong trường hợp này, bạn có thể dùng apply để ngầm "trải rộng" một mảng thành một chuỗi tham số.
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
Hiệu ứng tương tự có thể đạt được với spread syntax.
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push(...elements);
console.info(array); // ["a", "b", 0, 1, 2]
Sử dụng apply() với các hàm tích hợp sẵn
Việc dùng apply() một cách thông minh cho phép bạn sử dụng các hàm tích hợp sẵn cho một số tác vụ mà nếu không sẽ phải duyệt qua tập hợp theo cách thủ công (hoặc dùng spread syntax).
Ví dụ, chúng ta có thể dùng Math.max() và Math.min() để tìm giá trị lớn nhất và nhỏ nhất trong một mảng.
// min/max number in an array
const numbers = [5, 6, 2, 3, 7];
// using Math.min/Math.max apply
let max = Math.max.apply(null, numbers);
// This about equal to Math.max(numbers[0], …)
// or Math.max(5, 6, …)
let min = Math.min.apply(null, numbers);
// vs. loop based algorithm
max = -Infinity;
min = Infinity;
for (const n of numbers) {
if (n > max) {
max = n;
}
if (n < min) {
min = n;
}
}
Nhưng hãy cẩn thận: khi dùng apply() (hoặc spread syntax) với danh sách tham số có độ dài tùy ý, bạn có nguy cơ vượt quá giới hạn độ dài tham số của JavaScript engine.
Hậu quả của việc gọi hàm với quá nhiều tham số (tức là, hơn vài chục nghìn tham số) không được xác định và khác nhau tùy engine. (Engine JavaScriptCore có giới hạn tham số cứng là 65536.) Hầu hết các engine sẽ ném ngoại lệ; nhưng không có quy định chuẩn nào ngăn chặn các hành vi khác, chẳng hạn như giới hạn tùy ý số lượng tham số thực sự được truyền vào hàm. Để minh họa trường hợp sau này: nếu một engine có giới hạn bốn tham số (giới hạn thực tế tất nhiên cao hơn đáng kể), nó sẽ giống như chỉ có các tham số 5, 6, 2, 3 được truyền vào apply trong các ví dụ trên, thay vì toàn bộ mảng.
Nếu mảng giá trị của bạn có thể tăng lên đến hàng chục nghìn, hãy sử dụng chiến lược kết hợp: áp dụng hàm cho từng đoạn của mảng mỗi lần:
function minOfArray(arr) {
let min = Infinity;
const QUANTUM = 32768;
for (let i = 0; i < arr.length; i += QUANTUM) {
const subMin = Math.min.apply(
null,
arr.slice(i, Math.min(i + QUANTUM, arr.length)),
);
min = Math.min(subMin, min);
}
return min;
}
const min = minOfArray([5, 6, 2, 3, 7]);
Specifications
| Specification |
|---|
| ECMAScript® 2027 Language Specification> # sec-function.prototype.apply> |