JavaScript - Lợi dụng sự khác biệt của call và apply
TIL
763
@100daysTIL
72
White

Huy Trần viết ngày 19/02/2018

#Day015

Xết hai đoạn code sau:

let a = [1, 2];
a.unshift([3]);
// result: a = [ [3], 1, 2 ]

let b = [1, 2];
b.unshift.apply([3]);
// result: b = [3, 1, 2]

Nhìn có vẻ giống nhau, nhưng có hành vi và kết quả khác nhau, một bên là chèn một mảng vào một mảng khác, cái còn lại merge hai mảng lại với nhau.

Lý do là vì cách chúng ta gọi hàm Array.prototype.unshift theo hai cách khác nhau.

Khi gọi hàm unshift trực tiếp, ví dụ a.unshift(), thực chất chúng ta gọi nó với method Function.prototype.call:

a.unshift([3]);   ->   a.unshift.call(a, [3]);

Với trường hợp thứ 2 thì chúng ta dùng method Function.prototype.apply:

b.unshift.apply(a, [3]);

Method Function.prototype.call nhận vào một list các tham số, Function.prototype.apply nhận vào một mảng các tham số.

Function.prototype.call(thisArg, args1, arg2, ...)
Function.prototype.apply(thisArg, [argsArray])

Chúng ta truyền [3] với tư cách là tham số đầu tiên (trong list các tham số) khi gọi a.unshift([3]), có nghĩa là chúng ta muốn chèn mảng [3] vào vị trí bắt đầu mảng a.

Trong lệnh gọi b.unshift.apply([3]), thì mảng [3] là mảng chứa một tham số là giá trị 3, có nghĩa là chúng ta muốn chèn số 3 vào đầu mảng b. Thành ra hiệu ứng merge hai mảng.


Lợi dụng sự khác biệt về tính chất này, chúng ta có thể dễ dàng ứng dụng vào thực tế, hoặc trong vài trường hợp, là đi phỏng vấn :D ví dụ với bài "làm phẳng" một Array thường hay gặp khi phỏng vấn ở Facebook:

Flatten array. This array can have multiple types : {}, [], "", undefined, null, 123 are all valid types inside the array.

For example
Input: [1, 2, { a: 3, b: 4 }, [5, 7]]
Output: [1, 2, 3, 4, 5, 7]

Có nhiều cách giải cho bài này, nhưng chúng ta có thể sử dụng Function.prototype.apply để giải bằng cách không dùng đệ quy:

let process = input;
let result = [];
while (process.length) {
  let current = process.shift();
  if (Array.isArray(current)) {
    process.unshift.apply(process, current);
  } else if (typeof current == 'object') {
    Object.keys(current).forEach(key => result.push(current[key]));
  } else {
    result.push(current);
  }
}

huytd 19-02-2018

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Huy Trần

119 bài viết.
2034 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
182 46
Tại sao phải viết blog kĩ thuật? Có rất nhiều bài viết trên mạng nói về vấn đề tại sao một lập trình viên nên thường xuyên viết các bài blog kĩ thu...
Huy Trần viết 5 năm trước
182 46
White
157 39
(Ảnh) Tiếp tục sêri (Link) lần này, chúng ta sẽ cùng tìm hiểu và mô phỏng lại một chức năng mà mọi người đang bắt đầu sử dụng hằng ngày, đó là chứ...
Huy Trần viết hơn 4 năm trước
157 39
White
119 19
Phần 1: Tự truyện Tui và Toán đã từng là hai kẻ thù không đội trời chung trong suốt hơn mười lăm năm ròng rã. Ngay từ ánh nhìn đầu tiên đã ghét nh...
Huy Trần viết hơn 4 năm trước
119 19
Bài viết liên quan
White
0 4
fCC: Technical Documentation Page note So I have finished the HTML part of this exercise and I want to come here to lament about the lengthy HTML ...
HungHayHo viết hơn 2 năm trước
0 4
White
3 1
Javascript inititalValue trong reduce() có quan trọng không? Day 41: Đọc code mẫu về hàm reduce() trong (Link), thấy hàm reduce() khá "đơn giản"....
Minh-Trung Nguyễn viết hơn 2 năm trước
3 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
119 bài viết.
2034 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!