Những câu hỏi hay trong Javascript Phần 2
Tiếp nối với phần 1 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 2, 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.
26. Truyền object như tham số và sau đó đem so sánh object đó với object khác thì chuyện gì sẽ xảy ra?
Xét VD :
function checkAge(data) { if (data === { age: 18 }) { console.log("You are an adult!"); } else if (data == { age: 18 }) { console.log("You are still an adult."); } else { console.log(`Hmm.. You don't have an age I guess`); } } checkAge({ age: 18 });
A: You are an adult!
B: You are still an adult.
C: Hmm.. You don't have an age I guess
Khi kiểm tra sự bằng nhau, các kiểu dữ liệu nguyên thủy (primitive type) được so sánh với giá trị của chúng, nhưng với object chúng không được so sánh bằng giá trị, vì mỗi khi tạo một object nó sẽ tạo ra vùng nhớ trong Memory Heap
, do đó, để so sánh 2 object có bằng nhau hay không, đầu tiên phải xem chúng có tham chiếu đến cùng một vùng nhớ hay không.
Trong VD trên, hai object mà chúng ta đang so sánh không có cùng một tham chiếu, object chúng ta truyền dưới dạng tham số đề cập đến vị trí khác trong bộ nhớ so với đối tượng chúng ta đã sử dụng để kiểm tra sự bằng nhau.
Đây là lý do cả hai { age: 18 } === { age: 18 }
và { age: 18 } == { age: 18 }
trả về giá trị false
.
Hai object chỉ bằng nhau khi chúng được tham chiếu đến cùng một địa chỉ trong vùng nhớ
27. Hiểu thêm về toán tử spread ( toán tử ... )
Xét VD sau :
function getUser(...args){ console.log(args) console.log(typeof args) } getUser("john doe", "john_doe@email.com", 24} //["john doe", "john_doe@email.com", 24]
A: "number"
B: "array"
C: "object"
D: "NaN"
Toán tử spread ...
(...args)
trả về một mảng các đối số. Trong JS mảng là một object, vì thể typeof args
sẽ trả về một object
.
28. "use strict" có tác dụng gì?
Xét VD sau :
function getName(){ name = "John Doe" console.log(name) } getName() //John Doe
function getName(){ "use strict" name = "John Doe" console.log(name) } getName()
Đáp án :
A: 21
B: undefined
C: ReferenceError
D: TypeError
Với việc sử dụng use strict
, JS có thể đảm bảo rằng bạn không vô tình khai báo biến toàn cục. Rõ ràng, ở VD trên chúng ta chưa hề khai báo biến name
, và bằng việc gán thêm một dòng use strict
, nó sẽ ném lỗi tham chiếu (Referrence error
) ngay.
Nếu không dùng use strict
như ví dụ đầu, hàm getUser
vẫn hoạt động và trả về giá trị như bình thường, bởi vì thuộc tính age
đã được JS khởi tạo ở đầu quá trình thực thi và gán biến name
là một biến toàn cục trước khi hàm getUser
chạy.
29. eval
trong JS là gì?
Đoán xem kết quả dưới đây là gì?
const sum = eval('10*10+5');
A: 105
B: "105"
C: TypeError
D: "10*10+5"
eval đánh giá các code được truyền dưới dạng một chuỗi. Nếu đó là một biểu thức, như trong trường hợp này, nó sẽ đánh giá biểu thức.
Biểu thức là 10 * 10 + 5 vì thế kết quả sẽ trả về số 105.
30. Dữ liệu được lưu trữ trong sessionStorage bị xóa khi nào?
sessionStorage.setItem("token","mySecret");
A: Mãi Mãi, các dữ liệu không bị mất.
B: Khi người dùng đóng tab.
C: Khi người đóng lại toàn bộ trình duyệt, không chỉ là đóng tab.
D: Khi người dùng dùng tắt máy tính của họ.
Dữ liệu được lưu trữ trong sessionStorage sẽ bị xóa sau khi đóng tab.
Nếu bạn sử dụng localStorage, dữ liệu sẽ ở đó mãi mãi, trừ khi localStorage.clear() được gọi.
31. Khai báo nhiều biến cùng tên trong cùng phạm vi có được không?
var a = 5; var a = 10; let b = 15; let b = 20; const c = 25; const c = 30;
A: 8 20 30
B: 10 SyntaxErr SyntaxErr
C: SyntaxError SyntaxErr SyntaxErr
D: ReferenceError 20 SyntaxErr
Với từ khóa var
, bạn có thể khai báo nhiều biến cùng tên được. Biến được khai báo sau sẽ giữ giá trị mới nhất.
Nhưng bạn không thể làm điều tương tự với let
hay const
vì chúng nằm trong block-scoped
32. Object key được coi là kiểu 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: false true false true
B: false true true true
C: true true false true
D: true true true true
Tất cả các object key (ngoại trừ symbol) được coi là chuỗi, ngay khi bạn không gõ nó như một chuỗi.
Đây là lý do tại sao obj.hasOwnProperty('1')
cũng trả về true
Tuy nhiên, nó không hoạt động tương tự với set
, không có '1'
trong set
dẫn đến set.has('1')
trả về false
.
Nó có kiểu số là 1
, vì thế set.has(1)
trả về true
33. Điều gì sẽ xảy ra nếu trong một object có các thuộc tính giống nhau?
const obj = { first : "1", second : "2", first : "3" } console.log(obj)
A: { a: "one", b: "two" }
B: { b: "two", a: "three" }
C: { a: "three", b: "two" }
D: SyntaxError
Nếu bạn có 2 key giống nhau trong cùng một object, object đó sẽ lấy giá trị của key cuối cùng để thay thế và thứ tự của key trong object đó vẫn giữ nguyên.
34. Có phải Javascript global execution context tạo ra 2 thứ: global object và từ khóa "this"?
Đúng
Vì cơ bản Global execution context giúp chúng ta có thể truy cập mọi nơi trong code.
35. continue
trong vòng lặp có ý nghĩa gì?
for (let i = 1; i < 5; i++) { if (i === 3) continue; console.log(i); }
A: 1 2
B: 1 2 3
C: 1 2 4
D: 1 3 4
Câu lệnh continue
bỏ qua một lần lặp nếu một điều kiện nhất định trả về true.
36. Có thể thêm thuộc tính vào một string hay không?
String.prototype.greeting = function(){ return "Happy new Year" } let name = "John Doe" name.greeting()
A: "Happy new Year"
B: TypeError: not a function
C: SyntaxError
D: undefined
String
là một constructor được xây dựng sẵn trong JS (built-in constructor), vì thể chúng ta có thể thêm các thuộc tính vào. Mình chỉ cần thêm một phương thức vào prototype của nó.
Các chuỗi nguyên thủy sẽ tự động được chuyển thành string object, cái mà được tạo tạo bởi string prototype function. Do đó, tất cả các chuỗi (string object) đều có thể truy cập đến phương thức đó.
37. Đặt object làm key thì chúng sẽ hoạt động như thế nào?
const a = {}; const b = { key: "b" }; const c = { key: "c" }; a[b] = 123; a[c] = 456; console.log(a[b]);
A: 123
B: 456
C: undefined
D: ReferenceError
Các Object key sẽ tự động chuyển thành chuỗi. Vì chúng ta đang cố gắng đặt một object làm key cho object a
, với giá trị 123
.
Tuy nhiên, khi chúng ta cố gắng chuyển thành chuỗi một object, nó sẽ hoạt động không đúng, cụ thể ở đây là [object Object]
. Vì vậy, những gì chúng ta đang nói với JS ở đây là a["[object Object]"] = 123
Sau đó, chúng ta lại làm tương tự một lần nữa với c
c là một object khác mà chúng ta đang ngầm xâu chuỗi. Vì vậy, a["Object object"] = 456
Sau đó chúng ta log a[b]
, thực sự là a["Object object"]
. Và chúng ta đã đặt nó bằng 456
, vậy kết quả nhận được là 456
.
38. Call Stack trong javascript hoạt động như thế nào?
const foo = () => console.log('First'); const bar = () => setTimeout(() => console.log('Second')); const baz = () => console.log('Third'); bar(); foo(); baz();
A: First Second Third
B: First Third Second
C: Second First Third
D: Second Third First
Chúng ta có một hàm setTimeout
và gọi nó trước. Tuy nhiên, nó đã được log cuối cùng.
Điều này là do trong các trình duyệt, chúng ta không chỉ có runtime engine, chúng ta cũng có WebAPI. WebAPI cung cấp cho chúng ta một số hàm như setTimeout()
để bắt đầu, VD như DOM
.
Sau khi callback được đẩy lên WebAPI, hàm setTimeout
(nhưng không phải là callback!) Được loại ra khỏi stack.
Sau khi loại bar()
ra khỏi call stack để đẩy nó sang queue stack
cho WebAPI xử lý, callstack tiếp tục xử lý function tiếp theo, ở đây là foo()
được gọi và trả giá trị First
Hàm foo()
sau khi gọi xong sẽ bị loại bỏ ra khỏi callstack, và callstack tiếp tục xử lý function tiếp theo là hàm baz()
được gọi và trả về giá trị Third
.
Callstack lúc này đã xử lý hoàn tất, WebAPI không thể chờ đẩy nhiệm vụ vào vào stack bất cứ khi nào nó sẵn sàng. Thay vào đó, nó đẩy hàm callback đến một thứ gọi là hàng đợi (queue).
Đây là nơi một vòng lặp sự kiện (event loop) bắt đầu hoạt động. Một vòng lặp sự kiện nhìn vào stack và nhiệm vụ trong hàng đợi. Nếu stack trống, nó sẽ lấy nhiệm vụ đầu tiên trên hàng đợi và đẩy nó lên stack.
Lúc này bar
được gọi, 'Second'
được log và nó bật ra khỏi stack.
39. Envet.target gì xảy ra khi click vào button?
Xét VD sau:
<div onclick="console.log('first div')"> <div onclick="console.log('second div')"> <button onclick="console.log('button')"> Click! </button> </div> </div>
A: first div
B: second div
C: button
D: Một mảng của tất cả các div lồng nhau
Phần tử lồng nhau sâu nhất gây ra sự kiện là mục tiêu của sự kiện. Bạn có thể ngừng bubbling bằng event.stopPropagation
.
40. Khi bấm vào đoạn văn bản thì log ra cái gì?
<div onclick="console.log('div')"> <p onclick="console.log('p')"> Click here! </p> </div>
A: p div
B: div p
C: p
D: div
Nếu chúng ta click vào p, chúng ta sẽ thấy hai bản ghi: p và div
.
Trong quá trình truyền sự kiện, có 3 giai đoạn: bắt giữ (capturing), nhắm mục tiêu (target) và sủi bọt (bubbling).
Theo mặc định, các trình xử lý sự kiện (event handlers) được thực thi trong giai đoạn sủi bọt (trừ khi bạn đặt useCapture thành true). Nó đi từ phần tử lồng sâu nhất ra bên ngoài.
41. Sự khác nhau của hàm call và hàm bind là gì?
const person = { name: "Lydia" }; function sayHi(age) { console.log(`${this.name} is ${age}`); } sayHi.call(person, 21); sayHi.bind(person, 21);
A: undefined is 21 Lydia is 21
B: function function
C: Lydia is 21 Lydia is 21
D: Lydia is 21 function
Đối với cả 2 trường hợp, chúng ta có thể truyền object mà chúng ta muốn this
tham chiếu đến. Tuy nhiên, call()
thì gọi ngay lập tức.
Bạn có thể hiểu hàm call
là : Gọi hàm và cho phép bạn truyền một object và các đối số phân cách nhau bởi dấu ,
function.call(arg1, arg2,...)'
Còn hàm bind()
: trả về một hàm số mới, cho phép truyền một object và các đối số phân cách nhau bởi dấu ,
.
var newFunction = fun.bind(thisArg[, arg1[, arg2[, ...]]])
Vì bind
trả về một bản copy function nhưng với một bối cảnh ràng buộc (bound context) nên nó không được thực thi ngay.
42. typeof sayHi() là gì?
function sayHi() { return (() => 0)(); } typeof sayHi();
A: "object"
B: "number"
C: "function"
D: "undefined"
Hàm sayHi()
trả về giá trị của hàm được gọi ngay lập tực (IIFE). Hàm này trả về 0
, thuộc kiểu number
.
Trong JS có 7 kiểu dữ liệu : null
, undefined
, boolean
, number
, string
, object
, symbol
. function
không phải là kiểu dữ liệu, nhưng vì các hàm là các object nên nó thuộc object
43. Giá trị nào sau đây là falsy?
0; new Number(0); (""); (" "); new Boolean(false); undefined;
A: 0, '', undefined
B: 0, new Number(0), '', new Boolean(false), undefined
C: 0, '', new Boolean(false), undefined
D: All of them are falsy
Có 8 giá trị falsy:
- undefined
- null
- NaN
- false
- 0
- ''
(empty string)
- -0
- 0n
(BigInt(0))
Trong Function constructor như là new Boolean()
, new Number()
đều là truthy
44. Kiểu của kiểu của number về kết quả là gì?
console.log(typeof typeof 5);
A: "number"
B: "string"
C: "object"
D: "undefined"
Vì typeof 5 trả về number
là một string. Do đó typeof typeof 5 === typeof 'number' là string
.
45. Set giá trị vượt quá độ dài của mảng trong Javascript thì xảy ra vấn đề gì?
const numbers = [1, 2, 3]; numbers[10] = 11; console.log(numbers);
A: [1, 2, 3, 7 x null, 11]
B: [1, 2, 3, 11]
C: [1, 2, 3, 7 x empty, 11]
D: SyntaxError
Trong Java thì điều này không được phép. Nhưng trong Javascript thì khi bạn set một giá trị có index vượt quá độ dài của mảng, JavaScript sẽ tạo ra một thứ gọi là empty
.
Chúng thực sự có giá trị undefined
, nhưng bạn sẽ thấy là : [1, 2, 3, 7 x empty, 11]
tùy thuộc vào nơi bạn chạy nó (nó khác nhau đối với các trình duyệt, node, v.v.)
46. Chương trình Javascript sau trả về kết quả gì?
(() => { let x, y; try { throw new Error(); } catch (x) { (x = 1), (y = 2); console.log(x); } console.log(x); console.log(y); })();
A: 1 undefined 2
B: undefined undefined undefined
C: 1 1 2
D: 1 undefined undefined
Khối catch nhận đối số x
. Biến này không giống như x
khi chúng ta truyền đối số. Biến x
này là block-scoped.
Sau đó, chúng ta đặt biến block-scoped này bằng 1
và đặt giá trị của biến y. Bây giờ, chúng ta log biến block-scoped x, kết quả bằng 1.
Bên ngoài khối catch, x
vẫn là undefined
và y là 2
. Khi chúng ta muốn console.log(x)
bên ngoài khối catch, nó trả về undefined
và y trả về 2
.
47. Mọi thứ trong JavaScript đều là gì?
A: primitive or object
B: function or object
C: only objects
D: number or object
Javascript chỉ có kiểu nguyên thủy (primitive type) và kiểu object
Kiểu nguyên thủy gồm :
- boolean
- string
- number
- null
- undefined
- bigint
- symbol
Sự khác biệt giữa primitive và object đó là: primitive không có thuộc tính (property) hay phương thức (method). Tuy nhiên, có thể bạn sẽ hỏi tại sao "foo".toUppercase()
tạo thành FOO
và không trả về kết quả TypeError
. Lý do là vì khi bạn truy cập đến các thuộc tính hay phương thức của kiểu nguyên thủy như string
, JS sẽ ngầm bọc kiểu nguyên thủy trong những lớp bao bọc, chằng hạn như kiểu string
sẽ được bao bọc trong String
và sau đó ngay lập tức loại bỏ wrapper sau khi biểu thức được đánh giá. Tất cả các primitive ngoại trừ null và undefined đều có cách thức hoạt động như này.
48. Reduce trong JS có tác dụng gì?
[[0, 1], [2, 3]].reduce( (acc, cur) => { return acc.concat(cur); }, [1, 2], );
A: [0, 1, 2, 3, 1, 2]
B: [6, 1, 2]
C: [1, 2, 0, 1, 2, 3]
D: [1, 2, 6]
reduce
dùng để tích lũy hay nói khác đi là cộng dồn nếu như mỗi vòng lặp đi qua và thỏa điều kiện nào đó để đưa phần tử đó vào trong biến tích lũy (acc). biến tích lũy có thể là một number
hay một object
, array
[1, 2]
là giá trị ban đầu của chúng ta. Đây là giá trị chúng ta bắt đầu và giá trị đầu tiên của acc
.
Trong vòng đầu tiên, acc
là [1,2] và cur
là [0, 1]. Chúng ta ghép chúng lại, kết quả là [1, 2, 0, 1].
Sau đó, [1, 2, 0, 1] là acc
và [2, 3] là cur
. Chúng ta nối chúng và nhận được kết quả [1, 2, 0, 1, 2, 3].
49. Câu hỏi về toán tử !! tính chất truthy và falsy của dữ liệu.
!!null; !!""; !!1;
A: false true false
B: false false true
C: false true true
D: true true false
null
là falsy
. !null
trả về true
. !true
trả về false
.
""
là falsy
. !""
trả về true
. !true
trả về false
.
1
là truthy
. !1
trả về false
. !false
trả về true
50. Phương thức setInterval trả về cái gì?
setInterval(() => console.log("Hi"), 1000);
A: Một id duy nhất
B: Số mili giây được chỉ định
C: passed function
D: undefined
Nó trả về một id duy nhất. Id này có thể được sử dụng để xóa khoảng nghỉ đó với hàm clearInterval()
.
Phần 2 trong series Những câu hỏi hay trong Javascript đến đây là kết thúc, hẹn gặp lại các bạn ở phần tiếp theo