Những câu hỏi hay trong Javascript Phần 3
Tiếp nối với 2 phần trước trong series Những câu hỏi hay trong Javascript, rất vui khi trở lại đây cùng các bạn trong phần 3, dưới đây sẽ là danh sách các câu hỏi và đáp án theo thứ tự tiếp nối với phần 1 và 2.
51. Cách từng ký tự trong chuỗi đơn giản, ngắn gọn như thế nào?
[..."Lydia"];
A: ["L", "y", "d", "i", "a"]
B: ["Lydia"]
C: [[], "Lydia"]
D: [["L", "y", "d", "i", "a"]]
Một chuỗi là được ghép từ các ký tự. Toán tử spread ánh xạ mỗi ký tự thành một phần tử
Note: Nếu không sử dụng toán tử Spread. Bạn cũng có thể tách ký tự bằng phương thức split
52. Generator function là gì?
Xét VD sau :
function* generator(i) { yield i; yield i * 2; } const gen = generator(10); console.log(gen.next().value); console.log(gen.next().value);
A: [0, 10], [10, 20]
B: 20, 20
C: 10, 20
D: 0, 10 and 10, 20
Đối với Regular function
không thể bị dừng giữa chừng sau khi gọi. Tuy nhiên, đối với generator function
, nó lại có thể dừng lại tại một vị trí cụ thể sau khi gọi hàm, và sau đó nó tiếp tục hàm từ vị trí dừng đó. Mỗi khi hàm thực thi đến từ khóa yield
, nó sẽ tạo ra một giá trị cụ thể sau nó. Chú ý rằng generator function
trong trường hợp này không return
giá trị, nó chỉ cung cấp một giá trị.
Xét VD trên, đầu tiên, chúng ta khởi tạo hàm với biến i
là 10. Để gọi generator function, ta sử dụng phương thức next()
. Ở Lần đầu tiên chúng ta gọi generator function, i
bằng 10
. Khi Hàm này đi qua từng câu lệnh, nếu nó thấy từ khóa yield
nó sẽ tạo ra giá trị của i
, sau đó generator lúc này sẽ tạm dừng và log ra giá trị 10
.
Sau đó, nếu chúng ta gọi hàm này một lần nữa với từ phương thức next()
, hàm này sẽ tiếp tục vị chạy từ vị trí tạm dừng của lần trước, i
vẫn là 10
cho đến khi hàm bắt gặp từ khóa yield
tiếp theo, lúc này hàm sẽ tạo ra giá trị mới là i * 2
, do đó, i
từ 10
sẽ trở thành 10 * 2
là 20
.
Vậy đáp án là 10,20
53. Promise race là gì?
Xét VD sau :
const firstPromise = new Promise((res, rej) => { setTimeout(res, 500, 'one'); }); const secondPromise = new Promise((res, rej) => { setTimeout(res, 100, 'two'); }); Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
A: "one"
B: "two"
C: "two" "one"
D: "one" "two"
Khi chúng ta truyền nhiều promises đến phương thức Promise.race
, nó sẽ trả về một lời hứa là hoàn thành hoặc từ chối ngay khi một trong số các promises được đưa vào hoàn thành hoặc từ chối, với giá trị hoặc lý do từ chối từ promise đó. Nói đơn giản là lời hứa nào hoàn thành sớm hoặc chối bỏ sớm thì sẽ công bố lời hứa đó luôn, không cần phải chờ thêm những lời hứa còn lại.
54. Mối liên hệ giữa Object và Array
let person = { name: 'Lydia' }; const members = [person]; person = null; console.log(members);
A: null
B: [null]
C: [{}]
D: [{ name: "Lydia" }]
Đầu tiên, chúng ta khai báo biến person
với giá trị của một object có thuộc tính là name
.
Sau đó, chúng ta khai báo một mảng tên là members
và thiết lập phần tử đầu tiên trong mảng này là object person
. Các objects liên hệ với nhau bằng tham chiếu khi thiết lập chúng bằng nhau. Nếu như ta gán một tham chiếu từ biến này đến một biến khác, tức là ta sao chép địa chỉ tham chiểu đó
Sau đó, ta cho biến person
có giá trị null
Chúng ta chỉ thay đổi giá trị của biến person
, nhưng phần tử đầu tiên của mảng không thay đổi vì phần tử đó có một tham chiếu (được sao chép) khác đến object. Phần tử đầu tiên trong mảng members
vẫn giữ tham chiếu của nó đến object nguồn. Khi chúng ta log mảng members
ra, phần tử đầu tiên vẫn giữ giá trị của object.
55. Sử dụng vòng lặp đối với Object trong JS?
Xét VD sau :
const person = { name: 'Lydia', age: 21, }; for (const item in person) { console.log(item); }
A: { name: "Lydia" }, { age: 21 }
B: "name", "age"
C: "Lydia", 21
D: ["name", "Lydia"], ["age", 21]
Với vòng lặp for-in
, chúng ta có thể lặp các keys trong object, trong trường hợp này là name
và age
. Nhưng phía sau nó, các object keys cơ bạn là một chuỗi (string) chúng không phải là một Symbol. Ở mỗi lần lặp, chúng ta thiết lập giá trị của item
tương ứng với key
hiện tại. Chẳng hạn như VD trên, lần lặp đầu tiên tương ứng với key
là name
thì item
đó có giá trị là name
, sau đó, đến vòng lặp tiếp theo, key
là age
thì item
có giá trị là age
.
56. Số cộng với chuỗi ra gì?
console.log(3 + 4 + '5');
A: "345"
B: "75"
C: 12
D: "12"
Phép toán kết hợp là thứ tự mà trình biên dịch đánh giá các biểu thức, từ trái sang phải hoặc từ phải sang trái. Điều này chỉ xảy ra nếu tất cả các toán tử có cùng thứ tự ưu tiên. Ở đây, chúng ta chỉ có toán tử +
và có thứ tự từ trái sang phải.
3+4
là 2 số được tính toán đầu tiên, kết quả là 7
Sau đó, lấy 7
vừa tính ra cộng với một ký tự "5"
, theo quy tắc, JS sẽ tự động ép số kiểu thành kiểu string để cồng 2 chuỗi ký tự lại với nhau, nên lúc này giá trị đúng là "75"
chứ không phải 15
.
57. Ép kiểu cho một chuỗi
const num = parseInt('7*6', 10);
A: 42
B: "42"
C: 7
D: NaN
Khi ép kiểu cho một chuỗi nhân như trên, chỉ các số đầu tiên trong chuỗi được trả về. Dựa trên cơ số (đối số thứ hai để chỉ định loại số mà chúng ta muốn phân tích cú pháp nó thành : cơ số 10, thập lục phân, nhị phân, bát phân ...). parseInt
kiểm tra xem các ký tự trong chuỗi có hợp lệ không. Khi nó thấy một ký tự không phải là số phù hợp so với cơ số, nó sẽ ngưng phân tích cú pháp và bỏ qua những ký tự còn lại.
Ở VD trên, *
không phải là số, trong khi "7"
là một số thập phân. Do đó, num
giữ giá trị là 7
.
58. Điều gì sẽ xảy ra nếu return
không có giá trị nào trong map function?
[1, 2, 3].map(num => {
if (typeof num === 'number') return;
return num * 2;
});
A: []
B: [null, null, null]
C: [undefined, undefined, undefined]
D: [ 3 x empty ]
Khi ánh xạ qua một mảng, giá trị của num
bằng với phần tử hiện tại mà nó đang lặp. Trong trường hợp này, các phần tử đều có kiểu number
, mà trong vòng lặp lại có điều kiện if(typeof num === "number")
returns true
. Hàm ánh xạ (map function) tạo ra một mảng mới và chèn các giá trị trả về từ hàm hiện tại.
Tuy nhiên, chúng ta return
mà không có bất kỳ giá trị nào trong đó. Khi chúng ta return
mà không có một giá trị nào trong function
thì function
đó sẽ mặc định trả về undefined
. Với mỗi phần tử trong một mảng, khi hàm trong phương thúc map được gọi, nó sẽ trả với undefined
tương ứng với số phần tử trong mảng đáp ứng điều kiện đó.
59. Truyền đối số là một object và một giá trị nguyên thủy vào hàm thì outer scope có gì thay đổi?
function getInfo(member, year) { member.name = 'Lydia'; year = '1998'; } const person = { name: 'Sarah' }; const birthYear = '1997'; getInfo(person, birthYear); console.log(person, birthYear);
A: { name: "Lydia" }
, "1997"
B: { name: "Sarah" }
, "1998"
C: { name: "Lydia" }
, "1998"
D: { name: "Sarah" }
, "1997"
Các đối số được truyền vào hàm bằng một giá trị, trừ khi giá trị của chúng là một object thì khi đó chúng được truyền vào hàm bằng một tham chiếu. birthYear
là một giá trị, nên khi truyền đối số là một giá trịm một bản copy giá trị sẽ được tạo ra.
Biến birthYear
tham chiếu đến giá trị "1997"
. Đối số year
cũng tham chiếu đến giá trị 1997
. Khi update giá trị year
thành 1998
thì chúng ta chỉ update giá trị của year
, còn birthYear
vẫn là 1997
.
Còn person
là một object, nên đối số member
trong hàm có một bản tham chiếu (được copy) đến cùng một object với person
. Do đó, khi chúng ta thực hiện thay đổi, chỉnh sửa member
, giá trị của person
cũng sẽ thay đổi theo vì cả 2 lúc này cùng tham chiếu đến 1 đối tượng. Thuộc tính name
trong person
sau khi trong hàm tiến hành chỉnh sửa sẽ là Lydia
60. Try, catch với một hàm bên ngoài
function greeting() { throw 'Hello world!'; } function sayHi() { try { const data = greeting(); console.log('It worked!', data); } catch (e) { console.log('Oh no an error:', e); } } sayHi();
A: It worked! Hello world!
B: Oh no an error: undefined
C: SyntaxError: can only throw Error objects
D: Oh no an error: Hello world!
Bằng việc khai báo throw
, chúng ta có thể tạo ra những lỗi tùy chỉnh hay những ngoại lệ. Một ngoại lệ có thể là một chuỗi, number, boolean, hay một object. Trong trường hợp này, ngoại lệ là một chuỗi Hello world!.
Bằng cách sử dụng catch
, chúng ta có thể làm việc cụ thể với những ngoại lệ được ném ra trong khối lệnh try
. Khi một ngoại lệ được ném, chuỗi Hello world!
sẽ là một đối số e
trong catch
. Khi log ra, kết quả sẽ là "Oh an error: Hello world!"
61. Toán tử new
trong function?
Xét VD sau:
function Car() { this.make = 'Lamborghini'; return { make: 'Maserati' }; } const myCar = new Car(); console.log(myCar.make);
A: "Lamborghini"
B: "Maserati"
C: ReferenceError
D: TypeError
Khi bạn trả về một thuộc tính, giá trị của thuộc tính bằng với giá trị được trả về, không phải là giá trị được đặt trong hàm khởi tạo. Do đó, ta trả về Maserati
, myCar.make
chính là Maserati
62. Kiểu của biến trả về trong anonymous function là gì?
(() => { let x = (y = 10); })(); console.log(typeof x); console.log(typeof y);
A: "undefined", "number"
B: "number", "number"
C: "object", "number"
D: "number", "undefined"
let x = (y = 10)
thực sự là viết tắt của :
y \= 10; let x \= y ;
Khi chúng ta tạo y = 10
, chúng ta đã thực sự tạo biến y
thành một đối tượng toàn cục (global object, global object này là window
nếu trong trình duyệt, global
trong Node). Trong trình duyệt, window.y
bây giờ là 10
.
Sau đó, ta khai báo biến x
với giá trị của biến y
, tức là 10
. Biến được khai báo với từ khóa let
được đưa vào trong khối lệnh (block scope). chúng chỉ được xác định trong khối lệnh mà chúng được khai báo; biểu thức hàm được gọi ngay lập tức (IIFE) trong trường hợp này. Khi chúng ta sử dụng typeof
, x
chưa được định nghĩa vì ta đang cố gắng truy cập x
từ phía bên ngoài khối lệnh thực thi x
, nghĩa là lúc này x
chưa được định nghĩa. Những giá trị chưa được gán giá trị thì mặc định có kiểu undefined
. Đó đó, console.log(x)
sẽ là undefined
.
Tuy vậy, biến y
lại được gán thành biến toàn cục khi thiết lập y = 10
. Giá trị này có thể tiếp cận bất cứ nơi đâu trong đoạn code vì y
đã được định nghĩa, và giữ giá trị kiểu number
. Do đó, console.log(typeof y)
trả về number
63. Xóa một phương thức bằng delete
trong class?
class Dog { constructor(name) { this.name = name; } } Dog.prototype.bark = function() { console.log(`Woof I am ${this.name}`); }; const pet = new Dog('Mara'); pet.bark(); delete Dog.prototype.bark; pet.bark();
A: "Woof I am Mara", TypeError
B: "Woof I am Mara", "Woof I am Mara"
C: "Woof I am Mara", undefined
D: TypeError, TypeError
Chúng ta có thể xóa một thuộc tính nào đó trong object (hàm là một object) bằng việc sử dụng delete
cũng như prototype của nó. Bằng cách xóa đi thuộc tính trong prototype, nó không còn khả dụng trong prototype chain nữa. Trong trường hợp này, hàm bark
không còn có sẵn trên prototype sau khi delete Dog.prototype.bark
, nhưng chúng ta vẫn cố gắng tiếp cận nó. Lúc đó, lỗi TypeError
sẽ được ném ra. Trong trường hợp này TypeError: pet.bark is not a function
vì pet.bark
đã là biến undefined
64. Set
có tác dụng gì?
const set = new Set([1, 1, 2, 3, 4]); console.log(set);
A: [1, 1, 2, 3, 4] B: [1, 2, 3, 4] C: {1, 1, 2, 3, 4} D: {1, 2, 3, 4}
Set
là một tập hợp các giá trị duy nhất. Khi chúng ta cố gắng đưa các giá trị giống nhau vào tập hợp của Set
, nó sẽ chỉ lấy giá trị đầu tiên, còn những giá trị giống nhau kia sẽ bị loại bỏ đi, và kết quả trả về là một object {1,2,3,4}
65. Output dưới đây là gì?
const name = 'Lydia'; age = 21; console.log(delete name); console.log(delete age);
A: false, true B: "Lydia", 21 C: true, true D: undefined, undefined
66. Gán giá trị một biến bên trong []
cho một mảng sẽ như thế nào?
const numbers = [1, 2, 3, 4, 5]; const [y] = numbers; console.log(y);
A: [[1, 2, 3, 4, 5]]
B: [1, 2, 3, 4, 5]
C: 1
D: [1]
Chúng ta có thể lấy ra những giá trị của mảng hoặc thuộc tính trong một object thông qua destructing
. VD:
Giá trị của biến a
lúc này là 1
, b
là 2
. Những gì chúng ta thực sự thực hiện trong câu hỏi này là :
Khi sử dụng [y]
ta lấy được phần tử đầu tiên trong mảng, có giá trị là 1
67. Sử dụng destructing trong object
const user = { name: 'Lydia', age: 21 }; const admin = { admin: true, ...user }; console.log(admin);
A: { admin: true, user: { name: "Lydia", age: 21 } }
B: { admin: true, name: "Lydia", age: 21 }
C: { admin: true, user: ["Lydia", 21] }
D: { admin: true }
Chúng ta có thể kết hợp các object lại với nhau thông qua toán tử ...
. Nó giúp cho chúng ta có thể tạo ra bản copy các cặp key/values của object đó, sau đó đưa bản copy đó vào trong một object khác.
Trong trường hợp này, chúng ta tạo bản copy cho object user
, sau đó, đem bản copy này vào trong object admin
. Lúc này, admin
chứa những cặp key/values từ bản copy ban đầu, dẫn đến KQ là : { admin: true, name: "Lydia", age: 21 }
68. Sử dụng Object.defineProperty
như thế nào?
const person = { name: 'Lydia' }; Object.defineProperty(person, 'age', { value: 21 }); console.log(person); console.log(Object.keys(person));
A: { name: "Lydia", age: 21 }, ["name", "age"]
B: { name: "Lydia", age: 21 }, ["name"]
C: { name: "Lydia"}, ["name", "age"]
D: { name: "Lydia"}, ["age"]
Với phương thức defineProperty
, chúng ta có thể thêm thuộc tính mới vào trong object hoặc thay đổi giá trị của thuộc tính hiện tại. Khi chúng tôi thêm một thuộc tính vào một đối tượng bằng phương thức defineProperty
, chúng theo mặc định không thể liệt kê trong object. Do đó, phương thức Object.keys()
sẽ không trả về được tất cả các thuộc tính của object, trong trường hợp này là name
.
Các thuộc tính được thêm vào bằng phương thức defineProperty
là không thay đổi theo mặc định. Bạn có thể ghi đè lên hành vi này bằng việc sử dụng các thuộc tính writable
, configuarable
, enumerable
. Bằng cách này, phương thức defineProperty
sẽ cung cấp cho bạn thêm nhiều quyền quản lý các thuộc tính khi bạn thêm chúng vào object đó
69. JSON.stringify
hoạt động như thế nào?
const settings = { username: 'lydiahallie', level: 19, health: 90, }; const data = JSON.stringify(settings, ['level', 'health']); console.log(data);
A: "{"level":19, "health":90}"
B: "{"username": "lydiahallie"}"
C: "["level", "health"]"
D: "{"username": "lydiahallie", "level":19, "health":90}"
Trong JSON.stringify
, tham số thứ 2 là một replacer
tức là một giá trị thay thế cho tham số thứ 1. replacer
này có thể là một hàm hay một mảng và để cho bạn có thể quản lý được những giá trị nào nên được chuyển thành kiểu chuỗi stringified
Nếu replacer
là một mảng, chỉ có tên của những thuộc tính nào nằm trong mảng mới được đưa vào chuỗi JSON. Trong trường hợp này, chỉ có 2 thuộc tính là level
và health
được đưa vào, còn username
bị loại ra, data
hiện tại chỉ còn "{"level":19, "health":90}"
Nếu replacer
là một hàm, hàm này được gọi khi mọi thuộc tính trong object mà bạn đang chuyển thành chuỗi. Giá trị trả về từ hàm này sẽ là giá trị của thuộc tính khi nó được thêm vào chuỗi JSON. Nếu giá trị là undefined
, thuộc tính này sẽ bị loại khỏi chuỗi JSON.
70. Toán tử ++
và mối liên hệ giữa các hàm khi sử dụng nó
let num = 10; const increaseNumber = () => num++; const increasePassedNumber = number => number++; const num1 = increaseNumber(); const num2 = increasePassedNumber(num1); console.log(num1); console.log(num2);
A: 10, 10 B: 10, 11 C: 11, 11 D: 11, 12
Toán tử một ngôi ++
đầu tiên trả về giá trị của hạng tử, sau đó nó tăng giá trị của hạng tử đó lên 1 đơn vị. Giá trị của num1
là 10
, vì hàm increaseNumber
trả về giá trị cho biến num
là 10
và chỉ tăng giá trị của num
lên sau đó.
num2
là 10
vì khi chúng ta truyền num1
vào increasePassedNumber
, number
nhận giá trị truyền vào là 10
(giá trị của num1
. Một lần nữa, toán tử một ngôi ++
lần đầu nó trả về giá trị cho hạng tử, sau đó mới tăng giá trị của hạng tử đó lên 1 đơn vị). Do đó, giá trị của number
là 10
, nên num2
cũng là 10
.
71. Truyền đối số vào trong hàm là một object khác với bản copy object như thế nào?
const value = { number: 10 }; const multiply = (x = { ...value }) => { console.log((x.number *= 2)); }; multiply(); multiply(); multiply(value); multiply(value);
A: 20, 40, 80, 160
B: 20, 40, 20, 40
C: 20, 20, 20, 40
D: NaN, NaN, 20, 40
Trong ES6, chúng ta có thể khởi tạo tham số mặc định cho một hàm, nếu không có có bất kỳ tham số nào đưa vào tham số đó, nó sẽ sử dụng giá trị mặc định hoặc trả về undefined
. Trong trường hợp này, chúng ta trải rộng các thuộc tính của value
vào một đối tượng mới, vị vậy x
có giá trị mặc định là { number : 10 }
Đối số mặc định được đánh giá tại thời điểm gọi! Mỗi khi chúng ta gọi hàm, một đối tượng mới được tạo ra. Chúng ta gọi hàm multiply()
lần đầu tiên mà không chuyển giá trị được truyền vào, x
sẽ lấy giá trị mặc định là { number : 10}
Sau đó, chúng ta log giá trị nhân của số đó, là 20
Lần thứ ba chúng ta gọi nhân, chúng ta truyền một đối số: đối tượng được gọi là value
. Toán tử *=
thực sự là viết tắt của x.number = x.number * 2
: chúng sửa đổi giá trị của x.number
và log giá trị 20
.
Ở lần cuối cùng, chúng ta truyền value
vào object một lần nữa, x.number
lần trước đã được thay đổi thành 20
, lần này, nó vẫn tiếp tục được tham chiếu tới, vì thế x.number *= 2
sẽ log ra 40
72. Sử dụng reduce
trong mảng
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
A: 1 2 and 3 3 and 6 4
B: 1 2 and 2 3 and 3 4
C: 1 undefined and 2 undefined and 3 undefined and 4 undefined
D: 1 2 and undefined 3 and undefined 4
Đối số đầu tiên mà phương thức reduce
nhận được là bộ tích lũy (accumulator), x
trong trường hợp này, đối số thứ 2 là giá trị của phần tử hiện tại trong mảng sau mỗi vòng lặp, y
. Với phương thức reduce
, chúng ta thực thi một hàm callback
cho mỗi thành phần trong mảng mà cuối cùng có thể dẫn đến một giá trị duy nhất.
Trong VD trên, chúng ta không hề trả về bất cứ giá trị nào, chúng ta đơn giản chỉ log những giá trị tích lũy đó và giá trị hiện tại ra sau mỗi lần lặp.
Giá trị của bộ tích lũy bằng giá trị được trả về trước đó của hàm callback nếu như không truyền vào tham số khởi tạo tùy chọn initialValue
cho phương thức reduce
tại đối số thứ 2 trong hàm này, bộ tích lũy bằng với phần tử đầu tiên trong lần gọi đầu tiên. Trong lần gọi đầu tiên, bộ tích lũy (x) là 1 và giá trị hiện tại (y) là 2. Chúng ta không trả về từ hàm gọi lại, chúng ta chỉ ghi lại bộ tích lũy và giá trị hiện tại: 1 và 2 được ghi lại.
Nếu bạn không trả về giá trị từ một hàm, nó sẽ trả về undefined
. Trong lần gọi tiếp theo, bộ tích lũy sẽ là undefined
, và giá trị hiện tại là 3. undefined
và 3 được ghi lại.
Trong lần gọi thứ tư, một lần nữa chúng ta không quay trở lại từ hàm gọi lại. Bộ tích lũy một lần nữa là undefined
, và giá trị hiện tại là 4. undefined
và 4 được ghi lại.
73. Với hàm khởi tạo nào, chúng ta có thể mở rộng thành công lớp Dog?
class Dog { constructor(name) { this.name = name; } }; class Labrador extends Dog { // 1 constructor(name, size) { this.size = size; } // 2 constructor(name, size) { super(name); this.size = size; } // 3 constructor(size) { super(name); this.size = size; } // 4 constructor(name, size) { this.name = name; this.size = size; } };
A: 1
B: 2
C: 3
D: 4
Trong một lớp dẫn xuất, bạn không thể truy cập từ khóa this
trước khi gọi super. Nếu bạn cố gắng làm điều đó, nó sẽ tạo ra một ReferenceError: 1 và 4 sẽ tạo ra một lỗi tham chiếu.
Với từ khóa super
, chúng ta gọi hàm tạo của lớp cha đó với các đối số đã cho. Hàm tạo của cha nhận đối số name
, vì vậy chúng ta cần chuyển name
cho super.
Lớp Labrador
nhận hai đối số, name
vì nó mở rộng Dog
và size
như một thuộc tính bổ sung trên lớp Labrador
. Cả hai đều cần được chuyển tới hàm khởi tạo trên Labrador
, hàm này được thực hiện chính xác bằng cách sử dụng hàm tạo 2.
74. Hàm hoạt động ra sao khi import
và export
nó?
// index.js console.log('running index.js'); import { sum } from './sum.js'; console.log(sum(1, 2)); // sum.js console.log('running sum.js'); export const sum = (a, b) => a + b;
A: running index.js, running sum.js, 3
B: running sum.js, running index.js, 3
C: running sum.js, 3, running index.js
D: running index.js, undefined, running sum.js
Với từ import
, tất cả các mô-đun đã nhập đều được phân tích cú pháp trước.
Điều này có nghĩa là các mô-đun đã nhập sẽ được chạy trước, code trong tệp nhập mô-đun sẽ được thực thi sau.
Đây là sự khác biệt so với require()
trong CommonJS, với require
, bạn có thể load các dependencies bằng lệnh trong khi code đang được thực thi. Nếu như sử dụng require
thay cho import
, running index.js
running sum.js
, 3
sẽ được log ra màn hình console.
So sánh sau khi ép kiểu
console.log(Number(2) === Number(2)); console.log(Boolean(false) === Boolean(false)); console.log(Symbol('foo') === Symbol('foo'));
A: true, true, false
B: false, true, false
C: true, false, true
D: true, true, true
Mỗi Symbol
là duy nhất. Mục đích của một tham số khi truyền vào Symbol
là để Symbol có được một mô tả. Giá trị của Symbol không phụ thuộc vào đối số được truyền vào. Khi chúng ta kiểm tra bằng nhau, chúng ta đang tạo ra hai Symbol hoàn toàn mới: Hai giá trị này là duy nhất và không bằng nhau. Do đó, Symbol('foo') === Symbol('foo')
trả về false
.
Phẩn 3 đến đây là hết, hẹn gặp lai các bạn ở phần 4