JavaScript Nâng Cao - Kỳ 5
Có một câu nói là: Trên đời chỉ có thứ nhiều người chửi và thứ không ai thèm dùng.
Javascript là một ví dụ điển hình, nó có một số điểm thú vị nhưng cũng khiến chúng ta phải đau đầu. Lý thuyết thì dễ hiểu, nhưng khi thực hành là cả một vấn đề. Vậy nên, mình sẽ cùng các bạn đi sâu vào từng ví dụ cụ thể và phân tích, mổ xẻ nó để hiểu hơn về Javascript nhé
Series này có thể sẽ khá dài mình không biết sẽ có bao nhiêu Kỳ tuy nhiên để tiện cho các bạn nào không đọc các bài trước đó của mình về JS thì trong loạt bài này mình sẽ giải thích lại toàn bộ. Các lý thuyết trong loạt bài này mình cũng có thể sẽ giải thích lại nhiều lần (tùy hứng) để các bạn có thể năm rõ nó hơn nhé. Ok vào bài thôi nào... GÉT GÔ 🚀
Nếu có bất kỳ câu hỏi nào đừng ngại hãy bình luận dưới phần
comment
nhé. Hoặc chỉ cần để lại mộtcomment chào mình
là đã giúp mình có thêm động lực hoàn thành series này. Cảm ơn các bạn rất nhiều. 🤗
1. Hàm eval trong JavaScript
Giá trị của sum
là gì?
const sum = eval("10*10+5");
- A:
105
- B:
"105"
- C:
TypeError
- D:
"10*10+5"
Đáp án của câu hỏi này là
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
Đáp án: A
Cùng mình đi tìm hiểu tại sao kết quả lại là như vậy nhé ❓️
1.1. Hàm eval là gì?
Hàm eval
trong JavaScript là một hàm đặc biệt cho phép chúng ta thực thi một đoạn mã JavaScript được biểu diễn dưới dạng chuỗi. Nó sẽ đánh giá và thực thi đoạn mã đó.
Ví dụ:
const result = eval("2 + 2");
console.log(result); // Output: 4
Trong ví dụ trên, hàm eval
sẽ đánh giá biểu thức "2 + 2" và trả về kết quả là 4.
1.2. Phân tích đoạn code
Quay lại với đoạn code ban đầu:
const sum = eval("10*10+5");
Ở đây, chúng ta truyền vào hàm eval
một chuỗi chứa biểu thức toán học "10*10+5". Hàm eval
sẽ đánh giá biểu thức này và tính toán kết quả.
Biểu thức "10*10+5" tương đương với phép tính 10 nhân 10 cộng 5, kết quả sẽ là 105.
Vì vậy, giá trị của biến sum
sẽ là 105, đúng với đáp án A.
1.3. Lưu ý khi sử dụng eval
Mặc dù hàm eval
có thể hữu ích trong một số trường hợp, nhưng nó cũng tiềm ẩn nhiều rủi ro bảo mật. Nếu chúng ta sử dụng eval
với dữ liệu đầu vào không đáng tin cậy (ví dụ: dữ liệu từ người dùng), kẻ tấn công có thể chèn mã độc vào và thực thi nó.
Do đó, tốt nhất là nên tránh sử dụng eval
nếu có thể. Thay vào đó, hãy cố gắng tìm các giải pháp thay thế an toàn hơn.
2. Lưu trữ dữ liệu với sessionStorage
Biến cool_secret sẽ truy cập được trong bao lâu?
sessionStorage.setItem("cool_secret", 123);
- A: Mãi mãi, dữ liệu sẽ không bao giờ mất.
- B: Khi user đóng tab lại.
- C: Khi user không chỉ là đóng tab, mà đóng browser lại.
- D: Khi user tắt máy tính đi.
Đáp án của câu hỏi này là
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
Đáp án: B
Cùng mình đi tìm hiểu tại sao kết quả lại là như vậy nhé ❓️
2.1. sessionStorage là gì?
sessionStorage
là một đối tượng trong Web Storage API của JavaScript. Nó cho phép chúng ta lưu trữ dữ liệu dưới dạng cặp key-value trong trình duyệt.
Đặc điểm của sessionStorage
là dữ liệu sẽ tồn tại trong phiên làm việc (session) của người dùng. Khi người dùng đóng tab hoặc cửa sổ trình duyệt, dữ liệu trong sessionStorage
sẽ bị xóa.
2.2. Phân tích đoạn code
Trong đoạn code trên, chúng ta sử dụng phương thức setItem
của sessionStorage
để lưu trữ một cặp key-value. Key là "cool_secret" và value là 123.
sessionStorage.setItem("cool_secret", 123);
Điều này có nghĩa là chúng ta đang lưu trữ giá trị 123 với key "cool_secret" trong sessionStorage
.
2.3. Thời gian tồn tại của dữ liệu trong sessionStorage
Như đã đề cập, dữ liệu trong sessionStorage
sẽ tồn tại trong phiên làm việc của người dùng. Khi người dùng đóng tab hoặc cửa sổ trình duyệt, dữ liệu sẽ bị xóa.
Vì vậy, đáp án đúng cho câu hỏi này là B: Khi user đóng tab lại.
2.4. So sánh với localStorage
Ngoài sessionStorage
, JavaScript còn cung cấp một đối tượng khác để lưu trữ dữ liệu là localStorage
. Sự khác biệt chính giữa sessionStorage
và localStorage
là:
- Dữ liệu trong
sessionStorage
sẽ bị xóa khi đóng tab hoặc cửa sổ trình duyệt. - Dữ liệu trong
localStorage
sẽ tồn tại vĩnh viễn cho đến khi bị xóa thủ công hoặc xóa bởi JavaScript.
Nếu chúng ta muốn lưu trữ dữ liệu lâu dài, không bị mất khi đóng trình duyệt, thì localStorage
sẽ là lựa chọn phù hợp hơn.
3. Khai báo biến với var
Output là gì?
var num = 8;
var num = 10;
console.log(num);
- A:
8
- B:
10
- C:
SyntaxError
- D:
ReferenceError
Đáp án của câu hỏi này là
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
Đáp án: B
Cùng mình đi tìm hiểu tại sao kết quả lại là như vậy nhé ❓️
3.1. Khai báo biến với var
Trong JavaScript, từ khóa var
được sử dụng để khai báo biến. Một đặc điểm của var
là nó cho phép khai báo lại biến với cùng tên mà không gây ra lỗi.
Khi chúng ta khai báo lại một biến với var
, giá trị của biến sẽ được cập nhật thành giá trị mới nhất.
3.2. Phân tích đoạn code
Hãy xem xét đoạn code sau:
var num = 8;
var num = 10;
console.log(num);
Ở đây, chúng ta khai báo biến num
hai lần với từ khóa var
.
- Lần đầu tiên,
num
được gán giá trị 8. - Lần thứ hai,
num
được gán lại giá trị 10.
Khi chúng ta gọi console.log(num)
, giá trị của num
sẽ là giá trị được gán cuối cùng, tức là 10.
Vì vậy, output của đoạn code trên sẽ là 10, đúng với đáp án B.
3.3. So sánh với let và const
Khác với var
, từ khóa let
và const
trong JavaScript không cho phép khai báo lại biến với cùng tên trong cùng một phạm vi (block scope).
Nếu chúng ta thử khai báo lại biến với let
hoặc const
, sẽ gây ra lỗi SyntaxError
.
Ví dụ:
let count = 5;
let count = 10; // Lỗi SyntaxError
const value = 3;
const value = 6; // Lỗi SyntaxError
Vì vậy, khi sử dụng let
và const
, chúng ta cần chú ý không khai báo lại biến với cùng tên trong cùng một phạm vi. Tuy nhiên best practice là không nên khai báo lại biến với cùng tên dù sử dụng var
. Và đa số các bạn không nên dùng var
nữa mà hãy sử dụng let
hoặc const
nhé. Chỉ sử dụng var
khi bạn thật sự hiểu rõ về nó.
4. Kiểm tra sự tồn tại của key trong object và set
Output là gì?
const obj = { 1: "a", 2: "b", 3: "c" };
const set = new Set([1, 2, 3, 4, 5]);
obj.hasOwnProperty("1");
obj.hasOwnProperty(1);
set.has("1");
set.has(1);
- A:
true
false
false
true
- B:
false
true
true
true
- C:
true
true
false
true
- D:
true
true
true
true
Đáp án của câu hỏi này là
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
Đáp án: C
Cùng mình đi tìm hiểu tại sao kết quả lại là như vậy nhé ❓️
4.1. Phân tích đoạn code
Đầu tiên, chúng ta có một object obj
với các keys là số và values là string. Mặc dù chúng ta không viết các keys dưới dạng string, nhưng chúng sẽ luôn được chuyển đổi thành string dưới hood.
Vì vậy, obj.hasOwnProperty('1')
trả về true
. Tương tự, obj.hasOwnProperty(1)
cũng trả về true
, vì giá trị 1
sẽ được tự động chuyển thành string.
Tiếp theo, chúng ta có một Set
. Không giống như object, Set
không chuyển đổi các keys thành string. Trong set
của chúng ta, không có giá trị '1'
, nên set.has('1')
trả về false
. Tuy nhiên, set
có chứa giá trị số 1
, nên set.has(1)
trả về true
.
4.2. Tóm lại
Khi làm việc với object, hãy nhớ rằng các keys luôn được chuyển đổi thành string (trừ khi chúng là Symbol
). Nhưng với Set
, điều này không xảy ra. Đó là lý do tại sao obj.hasOwnProperty('1')
trả về true
, nhưng set.has('1')
trả về false
.
Symbol
là một kiểu dữ liệu mới được giới thiệu trong ES6, nó tạo ra một giá trị không thể thay đổi và không trùng lặp được sử dụng làm key cho các thuộc tính của object. Ví dụ:const mySymbol = Symbol();
. Chi tiết vềSymbol
mình sẽ giới thiệu trong một bài viết khác nhé.
5. Ghi đè thuộc tính trong object
Output là gì?
const obj = { a: "one", b: "two", a: "three" };
console.log(obj);
- A:
{ a: "one", b: "two" }
- B:
{ b: "two", a: "three" }
- C:
{ a: "three", b: "two" }
- D:
SyntaxError
Đáp án của câu hỏi này là
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓
Đáp án: C
Cùng mình đi tìm hiểu tại sao kết quả lại là như vậy nhé ❓️
5.1. Phân tích đoạn code
Trong JavaScript, khi bạn khai báo một object với các keys trùng nhau, thì key sau cùng sẽ ghi đè lên các key trước đó.
Trong ví dụ này, object obj
được khai báo với hai thuộc tính a
. Giá trị của thuộc tính a
đầu tiên là "one"
, và giá trị của thuộc tính a
thứ hai là "three"
.
Vì key a
xuất hiện hai lần, nên giá trị của nó sẽ là giá trị gán cuối cùng, tức là "three"
. Tuy nhiên, thứ tự của các thuộc tính trong object vẫn giữ nguyên như khi chúng được khai báo.
Vì vậy, khi chúng ta log obj
, kết quả sẽ là { a: "three", b: "two" }
.
5.2. Tóm lại
Khi khai báo một object với các keys trùng nhau, key sau cùng sẽ ghi đè lên các key trước đó. Giá trị của key đó sẽ là giá trị gán cuối cùng, nhưng thứ tự của các thuộc tính trong object vẫn giữ nguyên như khi chúng được khai báo.
Hy vọng qua bài viết này, các bạn đã hiểu rõ hơn về cách hoạt động của JavaScript khi gặp phải các tình huống như trên. Hẹn gặp lại các bạn trong các bài viết tiếp theo của series "JavaScript Nâng Cao" nhé! 😉
All rights reserved