Blog#16: Điểm khác nhau giữa Regular Function vs Arrow Function 😊 (Series: Bí kíp Javascript - PHẦN 13)

image.png

Mình là TUẤN hiện đang là một Full-stack Developer tại Tokyo 😉. Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé 😊.

Bạn có thể khai báo các Functions của bạn theo nhiều cách.

Sử dụng keyword function:

// function declaration
function test(msg) {
  return `Hey ${msg}`;
}

// function expression
const test = function (msg) {
  return `Hey ${msg}`;
};

Bạn có thể gọi cả khai báo và biểu thức hàm là Normal/Regular Function

Arrow function được giới thiệu trong ES6 và còn được gọi là arrow function.

const arrowFunction = (msg) => { 
    return `Hey $ {msg}` 
}

Như bạn thấy cả hai function hoạt động giống nhau trong ví dụ trên. Bây giờ câu hỏi đặt ra là tại sao chúng ta cần regular funcion hoặc arrow function.

1️. Syntax - Cú pháp

Chúng ta có thể viết hàm regular và arrow function theo cách này 😎

// ES5
var add = function (x, y) {
  return x + y;
};

// ES6
let add = (x, y) => x + y;

Implicit Return - Return ngầm định

Trong hàm thông thường, bạn phải sử dụng keyword return để trả về bất kỳ value nào. Nếu bạn không trả về bất kỳ thứ gì thì hàm sẽ trả về undefined.

function regFunc() {
  return "Regular Function";
}

regFunc();
// Regular Function
function regFunc() {
  console.log("Regular Function");
}

regFunc();
// Regular Function
// undefined

Các arrow function hoạt động theo cách tương tự khi trả về giá trị.

Nếu arrow function chứa một biểu thức, bạn có thể bỏ qua dấu ngoặc nhọn và khi đó biểu thức sẽ được trả về implicitly returned.

{}không bắt buộc nếu nó chỉ có một dòng tuyên bố

const addOne = (number) => number + 1;
addOne(10);

()không bắt buộc nếu bạn chỉ có một đối số

let add = (x) => x + x;

Nếu không có đối số

let arrowFunc = _ => console.log("Arrow Function");

2️. Arguments binding - Đối số ràng buộc

Trong hàm thông thường, các keyword arguments có thể được sử dụng để truy cập các đối số được truyền cho hàm.

Thí dụ:

function regularFunction(a, b) {
  console.log(arguments);
}
regularFunction(1, 2);
// Arguments[1,2]

Các arrow function không có ràng buộc đối số.

const arrowFunction = (a, b) => {
  console.log(arguments);
};
arrowFunction(1, 2);
//ReferenceError: arguments is not defined

Tuy nhiên, nếu bạn muốn truy cập các đối số trong một arrow function, bạn có thể sử dụng toán tử rest:

var arrowFunction = (...args) => {
  console.log(...args);
};
arrowFunction(1, 2);
// 1 2

3️. this

Trong hàm thông thường, this thay đổi theo cách hàm đó được gọi.

  • Simple Invocation: this bằng đối tượng toàn cục hoặc có thể không xác định nếu bạn đang sử dụng chế độ strict mode.
  • Method Invocation: this bằng đối tượng sở hữu hàm.
  • Indirect Invocation: this bằng đối số đầu tiên.
  • Constructor Invocation: this bằng instance mới được tạo.
// 1️⃣ Simple Invocation
function simpleInvocation() {
  console.log(this);
}
simpleInvocation();
// Window Object

// 2️⃣ Method Invocation
const methodInvocation = {
  method() {
    console.log(this);
  },
};
methodInvocation.method();
// logs methodInvocation object

// 3️⃣ Indirect Invocation
const context = { aVal: "A", bVal: "B" };
function indirectInvocation() {
  console.log(this);
}
indirectInvocation.call(context); // logs { aVal: 'A' }
indirectInvocation.apply(context); // logs { bVal: 'A' }

// 4️⃣ Constructor Invocation
function constructorInvocation() {
  console.log(this);
}
new constructorInvocation();
// logs an instance of constructorInvocation

Các arrow function không có this riêng và chúng không xác định lại value của this bên trong hàm.

this bên trong một arrow function luôn đề cập đến this từ contexts bên ngoài.

var name = "Suprabha"
let newObject = {
    name : "supi",
    arrowFunc: () => {
        console.log(this.name); 
    },
    regularFunc() {
        console.log(this.name); 
    }   
}
newObject.arrowFunc(); // Suprabha
newObject.regularFunc(); // supi

4️. new

Các hàm thông thường có thể sử dụng constructor, chúng có thể được gọi bằng cách sử dụng keyword new.

function add(x, y) {
  console.log(x + y);
}
let sum = new add(2, 3);
// 5

Tuy nhiên, các arrow function không bao giờ có thể được sử dụng như các hàm khởi tạo. Do đó, chúng không bao giờ có thể được gọi với keyword new

let add = (x, y) => console.log(x + y);
const sum = new add(2, 4);
// TypeError: add is not a constructor

5️. paramaters không được đặt tên trùng lặp

Trong function bình thường, chúng ta có thể làm điều này:

// ✅ will work
function add(a, a) {}

// ❌ will not work
("use strict");
function add(a, a) {}
// Uncaught SyntaxError: Duplicate parameter name not allowed in this context

Các arrow function không bao giờ được có các tham số được đặt tên trùng lặp, cho dù ở chế độ strict mode hay non-strict mode.

const arrowFunc = (a, a) => {};
// Uncaught SyntaxError: Duplicate parameter name not allowed in this context

6️. Function Hoisting

Trong function thông thường, function được hoisting lên ở đầu.

normalFunc();
function normalFunc() {
  return "Normal Function";
}
// "Normal Function"

Trong arrow function, hàm được hoisting vào nơi bạn khai báo nó. Vì vậy, nếu bạn gọi hàm trước khi khai báo, bạn sẽ nhận được referenceError.

arrowFunc();
const arrowFunc = () => {
  return "Arrow Function";
};
// ReferenceError: Cannot access 'arrowFunc' before initializati

7️. Methods

Bạn có thể xác định các hàm trong lớp bằng cách sử dụng hàm thông thường.

class FullName {
  constructor(name) {
    this.name = name;
  }
  result() {
    console.log(this.name);
  }
}
let name = new FullName("Suprabha");
console.log(name);
// FullName {name: "Suprabha"}

Bạn cũng cần áp dụng callback.

setTimeout(name.result, 2000);
// after 1 second logs ""

Nhưng nếu bạn ràng buộc this

setTimeout(name.result.bind(name), 2000);
// Suprabha

Bằng ví dụ trên, bạn có thể thấy rằng bạn phải liên kết contexts this với context của chúng.

Trong arrow function, bạn không cần phải ràng buộc với context.

class FullName {
  constructor(name) {
    this.name = name;
  }
  result = () => {
    console.log(this.name);
  };
}
let name = new FullName("Suprabha");
setTimeout(name.result, 2000); // Suprabha

Khi nào không sử dụng arrow function 👩🏻‍💻

Object

let dog = {
  count: 3,
  jumps: () => {
    this.count++;
  },
};

Khi bạn gọi dog.jumps, số đếm không tăng lên. Đó là bởi vì this không bị ràng buộc với bất cứ điều gì, và sẽ kế thừa value của this từ phạm vi cha của nó.

Tham khảo 🧐

Tóm tắt

Trong hàm thông thường, this value là động, Trong arrow functionthis value bằng với value của hàm ngoài.

Trong hàm thông thường, các đối số sẽ cung cấp cho bạn danh sách tham số arguments được truyền vào hàm. argument của arrow function không được xác định.

Trong hàm thông thường, bạn luôn phải trả về bất kỳ value nào, nhưng trong arrow function, bạn có thể bỏ qua keyword return và có thể viết single line.

Trong mũi tên, các tham số của hàm phải là duy nhất.

Vấn đề Hoisting trong arrow function vì hàm không được gọi trước khi khởi tạo.

Như mọi khi, mình hy vọng bạn thích bài viết này và biết thêm được điều gì đó mới.

Cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo! 😍

Nếu bạn thấy thích blog của mình thì nhấn theo dõi để ủng hộ mình nhé. Thank you.😉

NGUYỄN ANH TUẤN

Xin chào, mình là Tuấn, một kỹ sư phần mềm đang làm việc tại Tokyo. Đây là blog cá nhân nơi mình chia sẻ kiến thức và kinh nghiệm trong quá trình phát triển bản thân. Hy vọng blog sẽ là nguồn cảm hứng và động lực cho các bạn. Hãy cùng mình học hỏi và trưởng thành mỗi ngày nhé!

Đăng nhận xét

Mới hơn Cũ hơn