Mọi nhà phát triển JavaScript nên hiểu các khái niệm cơ bản của ngôn ngữ phức tạp này.

Các khái niệm dưới đây không phải là tất cả, nhưng đây là những khái niệm cơ bản chung mà bạn cần biết để tiến lên một bước.

1. IIFE

IIFE là viết tắt của biểu thức hàm - hàm này được gọi ngay khi viết. 

Làm thế nào bạn có thể xác định một IIFE? Hãy xem ví dụ dưới đây: 

(() => console.log(‘Hello world’))();

Lý do sử dụng IIFE là để bảo vệ khả năng truy cập của các biến. Các biến được định nghĩa trong IIFE không thể được truy cập từ bên ngoài. Đó là cách để viết mã có thể bảo trì và ngăn mã nguồn của bạn trở thành một mớ hỗn độn.

2. Cấu trúc MVC

Không chỉ trong JavaScript, mà cấu trúc MVC được sử dụng trong hầu hết các ngôn ngữ lập trình. MVC là một khái niệm phổ biến để tổ chức mã nguồn thành các lớp khác nhau như dữ liệu, chế độ xem, logic và xử lý chúng một cách riêng biệt. 

Là một dự án lớn, bạn cần có một cấu trúc để mở rộng quy mô mà không phải cắm đầu vào tường. MVC là một trong những điều tốt nhất để theo dõi ngay từ đầu cho kế hoạch dài hạn. Tại một số thời điểm trong tương lai khi thêm các tính năng mới hoặc điều tra lỗi, bạn sẽ cảm ơn bản thân vì đã dành thời gian triển khai MVC trong quá khứ.

3. Closure

Chúng ta sử dụng khái niệm này khi nói về một hàm bên trong luôn có quyền truy cập vào các biến và tham số của hàm bên ngoài của nó, ngay cả sau khi hàm bên ngoài đã trả về.

Closure cho phép bạn cung cấp khả năng truy cập vào dữ liệu bên trong một hàm mà không cần trực tiếp sửa đổi chúng. Bằng cách này, bạn có thể bảo vệ code của mình trong khi cung cấp cho người khác khả năng mở rộng mã. Đặc biệt là khi bạn công khai một thư viện.

const sayHelloTo = name => {
  let message = ‘Hello ‘ + name;
  return () => console.log(message);
}
const sayHelloToAmy = sayHelloTo(‘Amy’);
sayHelloToAmy(); // Hello Amy

4. Async/await

Async / await cho phép bạn làm việc với xử lý không đồng bộ. Bạn thường rơi vào các tác vụ không đồng bộ khi xử lý việc gọi API. Dữ liệu cần được tìm nạp đầy đủ trước khi hiển thị trên chế độ xem.

Xem ví dụ bên dưới để biết cách sử dụng async / await:

const displayData = async () => {
  const data = await fetch(‘https://api.github.com/repositories');
  const jsonData = await data.json();
  console.log(jsonData);
};
displayData();

5. Scope

Có hai loại phạm vi trong JavaScript: phạm vi cục bộ phạm vi toàn cầu.

Ví dụ:

// Global scope
const globalCow = ‘global cow’;
const showCow = () => {
  const localCow = ‘local cow’;
  return globalCow;
};
const clonedCow = globalCow;
const mixedCow = globalCow + localCow; // error: Uncaught ReferenceError: localCow is not defined

Như bạn có thể thấy, biến globalCow có thể được sử dụng ở bất cứ đâu ngay cả trong ngữ cảnh cục bộ của hàm showCow. Nhưng bạn không thể sử dụng biến localCow bên ngoài hàm showCow vì nó được định nghĩa cục bộ. Biến toàn cầu là bạn có thể gọi ở bất kỳ đâu trong tệp dự án, biến cục bộ chỉ được gọi trong phạm vi được cho phép, ví dụ như trong một hàm.

6. Loại tham trị và loại tham chiếu

Khi bạn chỉ định giá trị cho các biến, việc chỉ định giá trị không đơn giản như vậy. Bạn cần hiểu liệu đó là giá trị thực hay tham chiếu, nếu không, bạn có thể thay đổi các giá trị một cách không chủ ý. 

Câu chuyện thật dễ dàng khi bạn gán các kiểu nguyên thủy như chuỗi, số hoặc boolean. Chúng là giá trị thực tế.

Phức tạp hơn một chút nếu bạn gán các đối tượng, mảng hoặc hàm. Lần này, biến sẽ không giữ giá trị thực mà là tham chiếu đến các ô nhớ lưu trữ giá trị trong bộ nhớ. 

Ví dụ:

let num1 = 1;
let num2 = num1;
// Changing num2’s value does not change num1’s value
num2 = 4;
console.log(num1); // 1
console.log(num2); // 4

let arr1 = [‘Amy’, ‘John’];
let arr2 = arr1;
// Changing elements’ value in arr2 leads to changing elements’ value in arr1
arr2[0] = ‘Jane’;
console.log(arr1); // [“Jane”, “John”]
console.log(arr2); // [“Jane”, “John”]

7. Callback

Trong JavaScript, một hàm callback là một hàm được thực thi sau khi một hàm khác được gọi. Bạn có thể chuyển một hàm callback làm tham số cho các hàm khác.

Vậy tại sao chúng ta sử dụng callback? Thông thường, đoạn mã chúng ta viết chạy tuần tự từ trên xuống dưới. Tuy nhiên, trong một số trường hợp, có những công việc cần được thực hiện trước khi thực hiện những công việc khác. Đây là lúc việc gọi lại là cần thiết. 

const fetchUsers = callback => {
  setTimeout(() => {
    let response = ‘[{name: “Amy”}, {name: “John”}]’;
    callback(response);
  }, 500);
};
const showUsers = users => console.log(users);
fetchUsers(showUsers);

Trong ví dụ trên, chúng ta gọi hàm fetchUsers và chuyển hàm callback showUsers làm tham số. Khi tất cả dữ liệu được tải đầy đủ, showUsers sẽ hiển thị trên màn hình.

8. Prototype

Bất cứ khi nào chúng ta tạo một hàm hoặc đối tượng trong JavaScript, một thuộc tính nguyên mẫu sẽ được thêm vào bên trong chúng. Nguyên mẫu là một đối tượng được liên kết với các chức năng và đối tượng theo mặc định, trong đó chúng ta có thể đính kèm các thuộc tính bổ sung có thể được kế thừa bởi các đối tượng khác.

Ví dụ:

function Person() {
  this.name = ‘Amy’;
  this.age = 28;
}
Person.prototype.job = ‘Programmer’;
Person.prototype.showName = function() {
  console.log(‘My name is ‘ + this.name);
}
let person = new Person();
person.showName(); // My name is Amy

9. Class

Trước ES6, không có classes nào trong JavaScript. Bạn chỉ có thể tiếp cận khái niệm lớp tương tự theo cách chức năng.

function Book(title) {
  this.title = title;
}
Book.prototype.showTitle = function() {
  console.log(this.title);
};
let book = new Book(‘JavaScript’);
book.showTitle(); // JavaScript

Trong ES6, bạn có thể tạo một lớp thực tế giống như bất kỳ nền tảng ngôn ngữ dựa trên lớp nào:

class Book {
  constructor(title) {
    this.title = title;
  }
  showBook() {
    console.log(this.title);
  }
}
let book = new Book(‘ES6’);
book.showBook();

Thật tiện lợi vì nó hợp nhất một số cách tạo lớp thành một lớp duy nhất.

10. Destructing

Đó là một cách dễ dàng để trích xuất thuộc tính từ các đối tượng.

Cách sử dụng cơ bản:

const person = {
  name: ‘Amy’,
  age: 28
};
let { name, age } = person;
console.log(name); // Amy
console.log(age); // 28

Bạn có thể giữ các biến giống như tên thuộc tính như trên hoặc xác định các biến mới:

let { name: newName, age: newAge } = person;
console.log(newName); // Amy
console.log(newAge); // 28

11. Spread Operator

Cái này sẽ cung cấp cho bạn quyền truy cập vào bên trong của một đối tượng có thể lặp lại. Nói một cách đơn giản, đó là một cách nhanh chóng và ngắn gọn để thêm các mục vào mảng, kết hợp các đối tượng hoặc kéo các mục riêng lẻ ra khỏi một mảng và sau đó chuyển chúng vào một.

// Combining Arrays
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = […arr1, …arr2];
console.log(arr3); // [1, 2, 3, 4, 5, 6]
// Combining Objects
let obj1 = {
  name: ‘Amy’,
  age: 28
};
let obj2 = {
  job: ‘programmer’
};
let obj3 = { …obj1, …obj2 };
console.log(obj3); // {name: “Amy”, age: 28, job: “programmer”}
// Spreading out an array and pass it to a function
const sum = (…arr) => {
  const length = arr.length;
  let sum = 0;
  for (let i = 0; i < length; i++) {
    sum += arr[i];
  }
  return sum;
};
let arr = [3, 5, 3, 2, 1];
console.log(sum(…arr)); // 14
console.log(sum(3, 5, 4, 1)); // 13

Tham khảo khóa học Web Frontend + React 5 tháng

Kết luận

Bạn có hiểu đầy đủ tất cả các khái niệm trên không? Nếu không, đã đến lúc kiểm tra tất cả chúng và sẵn sàng nâng các kỹ năng của bạn lên cấp độ tiếp theo. 

Nguồn bài viết tham khảo từ đây.