Kiến thức javascript thực chiến cần nắm phần 1
1. Scope, Closure
Scope là gì ?
Scope là phạm vi truy cập của biến trong chương trình.
Các loại scope cơ bản:
Global scope: biến khai báo bên ngoài mọi hàm/ block
Function scope: biến trong hàm chỉ dùng trong hàm đó.
Block scope: biến khai báo bằng
let,constchỉ dùng trong{}.
Ví dụ:
const globalVar = "blog chia se kien thuc ve cong nghe";
function testScope() {
const functionVar = "day la function scope";
if (true) {
let blockVar = "day la block scope";
console.log(globalVar); // OK
console.log(functionVar); // OK
console.log(blockVar); // OK
}
// console.log(blockVar); // Error
}
testScope();Closure là gì?
Closure là một hàm ghi nhớ được biến ở scope bên ngoài của nó, kể cả khi scope bên ngoài đã thực thi xong.
Ví dụ:
function createCount() {
let count = 0;
return function() {
count++;
return count;
}
}
const counter = createCount();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3Ở đây hàm trả về vẫn nhớ biến count.
So sánh Scope & Closure
Scope = quy tắc xác định biến nào truy cập được ở đâu
Clouse = hiện tượng hàm giữ lại biến từ scope bên ngoài
2. Hosting
Định nghĩa: Hoisting là cơ chế Javascript đưa phần khai báo lên đầu scope trước khi chạy code.
Với var:
được hoist
giá trị ban đầu là undefined
console.log(a); // undefined
var a = 10;JS hiểu gần giống:
var a;
console.log(a);
a = 10;Với let và const:
cũng được hoist
nhưng nằm trong Temporal Dead Zone (TDZ)
không dùng trước khi khai báo
// console.log(b); // ReferenceError
let b = 20;Với function declaration:
sayHello(); // "Hello"
function sayHello() {
console.log("Hello");
}So sánh:
var: hoist và dùng trước được, nhưng làundefinedlet/const: hoist nhưng không dùng trước đượcfunction declaration: hoist đầy đủfunction expression: không như function declaration
3. this
Định nghĩa
this là đối tượng đang gọi hàm tại thời điểm hàm được thực thi.
Quan trọng: this không phụ thuộc nơi hàm được viết, mà phụ thuộc cách hàm được gọi.
Ví dụ cơ bản
Gọi như method
const user = {
name: "An",
sayHi() {
console.log(this.name);
}
};
user.sayHi(); // "An"Gọi như function thường
function show() {
console.log(this);
}
show();Trong trình duyệt non-strict: có thể là
windowTrong strict mode:
undefined
Arrow function
Arrow function không có this riêng, nó lấy this từ scope bên ngoài.
const obj = {
name: "Tuan",
normal() {
console.log(this.name);
},
arrow: () => {
console.log(this.name);
}
};
obj.normal(); // "Tuan"
obj.arrow(); // thường không phải "Tuan"So sánh function thường và arrow function
Function thường: this do cách gọi quyết định
Arrow function: this lấy từ bên ngoài, không bind lại được theo cách thông thường.
4. Prototype ở mức cơ bản
Định nghĩa
Javascript dùng prototype-based inheitance.
Mỗi object có thể liên kết tới một object khác gọi là prototype. Khi truy cập thuộc tính:
nếu object hiện tại không có
JS sẽ tìm lên prototype chain
Ví dụ:
const animal = {
eats: true
};
const dog = Object.create(animal);
dog.barks = true;
console.log(dog.barks); // true
console.log(dog.eats); // true (lấy từ prototype)Với constructor function
function Persion(name) {
this.name = name;
}
Perion.prototype.sayHi = function() {
console.log("Hi, I am " + this.name)
}
const p1 = new Person("Tuan");
p1.sayHi(); // Hi, I am TuanSo sánh
Thuộc tính đặt trong
this: riêng cho từng objectThuộc tính/method đặt trong
prototype: dùng chung cho nhiều object
Ví dụ:
function User(name) {
this.name = name; // riêng
}
User.prototype.sayHello = function () {
console.log("Hello " + this.name); // dùng chung
};5. Array methods: map, filter, reduce
map
Dùng để biến đổi từng phần tử và trả về mảng mới cùng số lượng phần tử.
// array map
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6]filter
Dùng để lọc phần tử theo điều kiện, trả về mảng mới.
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]reduce
Dùng để gom mảng thành một giá trị duy nhất.
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 10So sánh
map: sửa đổi từng phần tửfilter: chọn phần tử thỏa điều kiệnreduce: gom về 1 kết quả
So sánh nhanh
const arr = [1, 2, 3, 4];
console.log(arr.map(x => x * 2)); // [2, 4, 6, 8]
console.log(arr.filter(x => x > 2)); // [3, 4]
console.log(arr.reduce((a, b) => a + b)); // 106. Destructuring, Spread/Rest
Destructuring
Là cách tách giá trị từ object hoặc array ra biến.
Array destructuring
const arr = [10, 20, 30];
const [a, b] = arr;
console.log(a); // 10
console.log(b); // 20Object destructuring
const user = { name: "Minh", age: 25 };
const { name, age } = user;
console.log(name); // Minh
console.log(age); // 25Spread
Spread dùng để trải phần tử / thuộc tính ra
// spread basic
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
console.log(arr2); // [1, 2, 3, 4];// spread object
const user = { name: "An" };
const updateUser = { ...user, age: 20 };
console.log(updatedUser); // { name: "An", age: 20 }Rest
Rest dùng để gom phần tử lại.
// rest basic
const [first, ...rest] = [1, 2, 3, 4];
console.log(first); // 1
console.log(rest); // [2, 3, 4]// rest params
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0)
}
console.log(sum(1, 2, 3)); // 6So sánh Spread và Rest
Cùng dùng cú pháp ... nhưng khác vai trò:
Spread = bung ra
Rest = gom lại
7. Module import/export
Định nghĩa
Module giúp chia code thành nhiều file để dễ quản lý, tái sử dụng.
Export
Named export
export const pi = 3.14
export function add(a, b) {
return a + b;
}Default export
export default function greet(name) {
return `Hello, ${name}`;
}Import
Import named
import { pi, add } from "./math.js";
console.log(pi);
console.log(add(2, 3));Import default
import greet from "./greet.js";
console.log(greet("Lan"));So sánh named export và default export
Named export: một file có thể export nhiều thứ
Default export: mỗi file chỉ có 1 default export
Named import phải đúng tên, default import thì đặt tên gì cũng được
8. Promise, async/await
Promise là gì?
Promise là object đại diện cho kết quả của tác vụ bất đồng bộ trong tương lai.
Ba trạng thái:
pending
fulfiled
rejected
Ví dụ
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Done!");
}, 1000);
});
promise.then(result => {
console.log(result);
});async/await là gì?
async/await là cú pháp giúp viết code bất đồng bộ trông giống đồng bộ hơn.
function wait() {
return new Promise(resolve => {
setTimeout(() => resolve("Finished"), 1000);
});
}
async function run() {
const result = await wait();
console.log(result);
}
run();So sánh Promise và async/await
Promise + .then(): chain bằng callback
async/await: dễ đọc hơn trong nhiều trường hợp
awaitchỉ dùng bên trongasync function(hoặc top-level await trong một số môi trường/module)
9. Event loop, microtask/macrotask
Định nghĩa ngắn gọn
JavaScript chạy theo cơ chế single-threaded nhưng xử lý bất đồng bộ nhờ:
Call stack
Web APIs / runtime APIs
Task queues
Event loop
Macrotask
Ví dụ:
setTimeoutsetIntervalsetImmediate(một số môi trường)I/O, UI events
Microtask
Ví dụ:
Promise.then/catch/finallyqueueMicrotaskMutationObserver
Quy tắc quan trọng
Sau khi call stack rỗng:
chạy hết microtask queue
rồi mới lấy 1 macrotask
lặp lại
Ví dụ
console.log("1");
setTimeout(() => {
console.log("2");
}, 0);
Promise.resolve().then(() => {
console.log("3");
});
console.log("4");kết quả
1
4
3
2So sánh microtask và macrotask
Microtask ưu tiên cao hơn
Promise.thenthường chạy trướcsetTimeout(..., 0)
10) fetch, error handling
fetch là gì ?
fetch dùng để gửi HTTP request trong JavaScript.
Ví dụ GET
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error("Error:", error);
});Dùng với async/await
async function getPost() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
if (!response.ok) {
throw new Error("HTTP error: " + response.status);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Fetch failed:", error.message);
}
}
getPost();Error handling
Trong JS, thường xử lý lỗi bằng:
.catch()try...catchtự
throw new Error(...)
Lưu ý quan trọng với fetch
fetch() không tự reject chỉ vì status là 404 hay 500.
Nó chỉ reject khi có lỗi mạng, CORS, request bị chặn...
Vì vậy cần kiểm tra:
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}So sánh
.catch()hợp với Promise chaintry...catchdễ đọc hơn khi dùngasync/awaitresponse.okxử lý lỗi HTTPcatchxử lý lỗi runtime / network