[JS] Arrow function khác function thường như thế nào?

Trong một bài viết trước đây mình có giới thiệu đến các bạn một cái mới gọi là arrow function, nó được trình làng trong ES6 và được xem như là một cải tiến quan trọng. Vậy hôm nay mình sẽ cùng nhau đi tìm hiểu arrow function với regular function (function thường) khác nhau như thế nào và nên xài arrow function lúc nào là hợp lý nhé.

Điểm 1: Cú pháp

Các bạn nhìn code sẽ suy ra được cú pháp nha

1
2
3
4
5
6
7
8
9
10
11
12
// regular function
function hello() {
// todo something
}

// arrow function
var hi = () => {
// todo something
}

console.dir(hello);
console.dir(hi);

Nếu arrow function chỉ có return về giá trị thôi thì không cần dấu “{}” lun cũng được.

1
2
3
4
// viết như vầy nó sẽ hiểu là return về string 'hello'
var hi = () => 'hello';

console.info(hi()); // hello

Nhìn qua ảnh này đi, không cần nhìn kỹ, xí đọc xong nhìn lại thấy sẽ hiểu hơn.

image

Điểm 2: this khác nhau

Một regular function khi được gọi this của nó sẽ trở tới object gọi nó. (Object này lại phụ thuộc vào context nữa)

1
2
3
4
5
6
7
8
9
10
var name = 'Github';

var repo = {
name: 'Bitbucket',
showNameRepo: function () {
console.log(this.name);
}
};

repo.showNameRepo(); // Bitbucket

Nếu thay showNameRepo là một arrow function thì kết quả sẽ khác

1
2
3
4
5
6
7
8
9
10
var name = 'Github';

var repo = {
name: 'Bitbucket',
showNameRepo: () => {
console.log(this.name);
}
};

repo.showNameRepo(); // Github

Kết quả khác nhau đúng không nào, nguyên nhân là arrow function không có this của nó, this trong arrow function trỏ sẵn tới this bên ngoài của nó (bên ngoài nó chính là context gần nhất). Bạn hãy tưởng tượng context (ngữ cảnh) giống như nơi chứa nó, nơi nó được thực thi.

Một thèn thì this phụ thuộc vào đứa gọi nó. Một thèn thì this phụ thuộc của context gần nhất, ở phạm vi bài viết thì this này là global hoặc window (nếu thực thi ở trình duyệt).

Điểm 3: Arrow function không có arguments

Khi một regular function được gọi, đồng thời nó sẽ được trình biên dịch binding thêm một cái gọi là arguments. Nó dặc biệt hữu ích khi bạn không xác định được cần có bao nhiêu argument truyền vào.

Ví dụ:

1
2
3
4
5
6
7
function students() {
console.info(`Có ${arguments.length} student`);
}

students('Mai', 'Hồng'); // Có 2 student
students('Mai', 'Hồng', 'Phượng'); // Có 3 student
students(); // Có 0 student

Còn với arrow function thì mọi chuyện lại khác, nó không có arguments

1
2
3
4
5
var students = () => {
console.info(`Có ${arguments.length} student`);
}

students('Mai', 'Hồng'); // arguments is not defined

Để khắc chế điều này các bạn có thể dùng toán tử spread ... trên parameters.

Điểm 4: Ở Arrow function method bind không thay đổi được cục diện this

Bản thân arrow function không có this, this được dùng từ bên ngoài của nó, nên việc binding này là vô tác dụng. Đối với regular function khi bind thì this sẽ được set theo cái đã bind vào.

1
2
3
4
5
6
7
8
9
var person = 'Mai';

function hi() {
console.log(this.person);
}

hi(); // Mai
var hiHong = hi.bind({ person: 'Hồng' });
hiHong(); // Hồng

.bind return về function mới nên gọi lại nó mới chạy được.

Đối với arrow function thì vô tác dụng nhé.

1
2
3
4
5
6
7
8
9
var person = 'Mai';

var hi = () => {
console.log(this.person);
}

hi(); // Mai
var hiHong = hi.bind({ person: 'Hồng' });
hiHong(); // Mai

Điểm 5: Arrow function không hoisting được

Thử đoạn code này bạn sẽ hiểu rõ, cái này được nói trong tài liệu đặc tả của ES6 các bạn tìm đọc sẽ thấy. Regular function khi bạn khai báo ở cuối file nhưng lúc thực thi nó sẽ được hoist lên trên, còn với arrow function thì không.

1
2
3
4
5
6
7
x()

function x() {}

y(); // TypeError: y is not a function

var y = () => {}

Điểm 6: Arrow function không new được

Không dùng nó để làm hàm contructor được, trình biên dịch không cho phép. Còn ở regular function khi đã khai báo rồi, bạn có thể dùng từ khóa new, để tạo ra object.

1
2
3
4
5
6
7
8
function Person(name, age) {
this.name = name;
this.age = age;
}

var me = new Person('Simple', 03);

console.dir(me);
image

Thử với arrow function xem sao nhé.

1
2
3
4
5
6
7
var Person = (name, age) => {
this.name = name;
this.age = age;
}

var me = new Person('Simple', 03);
// TypeError: Person is not a constructor

Tổng kết

Về cơ bản trên đó là vài khác biệt, sẽ có thể còn nữa, nhưng thôi, chừng đó là đủ để nắm rồi đấy. Arrow function dùng thì sướng thật, viết cũng đã tay nữa, cơ mà như bạn thấy đấy không phải lúc nào arrow function cũng là tốt. Các khác biệt trên nhắc chúng ta rằng nên cân nhắc tùy trường hợp mà sử dụng, quan trọng là phù hợp chứ chẳng cái ai tốt hơn ai.

Tham khảo

 Comments
Comment plugin failed to load
Loading comment plugin