Javascript và những câu hỏi khó – part 2
Các bạn có thể xem part 1 tại đây: JavaScript và những câu hỏi khó – Part 1 Hi vọng các bạn sẽ có thêm những trải nghiệm mới mẻ với JavaScript Trên đời vốn chỉ có 2 loại ngôn ngữ lập trình: loại bị nhiều người chê và loại không ai thèm dùng. 44. Output là gì? ...
Các bạn có thể xem part 1 tại đây: JavaScript và những câu hỏi khó – Part 1
Hi vọng các bạn sẽ có thêm những trải nghiệm mới mẻ với JavaScript
Trên đời vốn chỉ có 2 loại ngôn ngữ lập trình: loại bị nhiều người chê và loại không ai thèm dùng.
44. Output là gì?
1 2 3 4 5 6 7 8 9 10 11 |
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
Đáp án: C
Một hàm bình thường không thể bị dừng giữa chừng khi được gọi. Tuy nhiên một generator thì khác, nó có thể “dừng lại” được, và sau đó nó sẽ tiếp tục từ vị trí nó dừng lại. Mỗi khi một generator gặp một từ khóa yield, nó sẽ sinh ra giá trị ngay phía sau nó. Chú ý là generator không trả về giá trị, nó sinh ra giá trị.
Đầu tiên, chúng ta khởi tạo generator với giá trị i là 10. Generator được gọi bằng cách sử dụng phương thức next(). Khi lần đầu gọi thì i vẫn là 10. Khi nó bắt gặp từ khóa yield: nó sẽ sinh ra giá trị i. Generator sẽ được “tạm dừng” tại đây, và ghi ra giá trị 10.
Sau đó chung ta tiếp tục gọi generator bằng cách sử dụng tiếp phương thức next(). Nó sẽ bắt đầu từ vị trí nó tạm dừng lúc trước, khi i vẫn đang là 10. Và khi nó bắt gặp từ khóa yield, nó sẽ sinh ra giá trị i * 2. i là 10, nên nó sẽ sinh ra 10 * 2, tức 20. Vậy kết quả cuối cùng là 10, 20.
45. Giá trị trả về là gì?
1 2 3 4 5 6 7 8 9 10 11 |
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"
Đáp án: B
Khi chúng ta đưa các promise vào trong một hàm Promise.race, nó sẽ chỉ resolves hay rejects promise đầu tiên được resolves/rejects. Với hàm setTimeout, chúng ta đưa vào một khoảng thời gian: 500 mili giây cho promise đầu tiên (firstPromise), và 100 mili giây cho promise thứ hai (secondPromise). Nó có nghĩa là secondPromise sẽ hoàn thành trước và trả về giá trị 'two'. res khi này sẽ nhận giá trị 'two' và được in ra console.
46. Output là gì?
1 2 3 4 5 6 7 |
let person = { name: "Lydia" }; const members = [person]; person = null; console.log(members); |
- A: null
- B: [null]
- C: [{}]
- D: [{ name: "Lydia" }]
Đáp án: D
Đầu tiên, chúng ta khai báo một biến person là một object có thuộc tính name.
Sau đó chúng ta khai báo một biến members. Ta set giá trị đầu tiên của mảng là giá trị của biến person. Khi sử dụng gán bằng, object sẽ được tham chiếu tới object mà nó được gán. Khi ta gán tham chiếu từ một biến sang biến khác, ta tạo ra một bản sao của tham chiếu đó. (nên nhớ rằng đó vẫn là 2 tham chiếu hoàn toàn khác nhau!)
Sau đó ta set giá trị của person bằng null.
Chúng ta chỉ đơn thuần là thay đổi giá trị của biến person mà thôi, chứ không phải giá trị của phần tử đầu tiên ở trong mảng, vì chúng ta có một tham chiếu khác đến object đó. Phần tử đầu tiên của mảng members vẫn giữ tham chiêu đến object gốc. Do vậy, khi chúng ta in ra mảng members, phần tử đầu tiên sẽ vẫn in ra giá trị của objet gốc.
47. Output là gì?
1 2 3 4 5 6 7 8 9 10 |
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]
Đáp án: B
Với vòng lặp for-in chúng ta sẽ lặp qua tất cả các keys của object, trong trường hợp này là name và age. Về cơ bản, object keys là string (nếu nó không phải là Symbol). Tại mỗi vòng lặp, giá trị của item chính là giá trị của key hiện tại trong vòng lặp. Đầu tiên, item là name, và được in ra. Vòng lặp sau, item là age, và được in ra.
48. Output là gì?
1 2 3 |
console.log(3 + 4 + "5"); |
- A: "345"
- B: "75"
- C: 12
- D: "12"
Đáp án: B
Compiler sẽ đánh giá biểu thức dựa trên độ ưu tiên giữa các phép toán trong biểu thức đó, từ đó nó sẽ tính toán hoặc trái-sang-phải hoặc phải-qua-trái. Ở đây chúng ta chỉ có một phép toán mà thôi, phép cộng: +. Với phép cộng, tính toán sẽ là từ trái-qua-phải.
Giá trị 3 + 4 được tính toán trước. Kết quả là 7.
7 + '5' sẽ ra kết quả là "75" bởi xuất hiện ép kiểu tại đây. JavaScript sẽ convert 7 sang dạng string, bạn có thể xem thêm tại câu hỏi 15. Và sau đó 2 string sẽ được nối lại với nhau bởi phép toán cộng +. Kết quả "7" + "5" sẽ là "75".
49. What’s the value of num?
1 2 3 |
const num = parseInt("7*6", 10); |
- A: 42
- B: "42"
- C: 7
- D: NaN
Đáp án: C
Chỉ có số đầu tiên trong chuỗi kí tự được trả về. Hệ cơ số là hệ thập phân_ (đối số thứ 2 trong hàm chính là cơ số: hệ thập phân, hệ 16, hệ 8, hệ nhị phân, vv.), Hàm parseInt sẽ kiểm tra xem các ký tự trong chuỗi có đảm bảo hợp lệ hay không. Một khi chúng tìm ra ký tự không phải là ký tự hợp lệ trong hệ cơ số, nó dừng lại và bỏ qua các ký tự phía sau.
* không phải là một số. Vậy nên nó sẽ chỉ convert ký tự "7" sang hệ thập phân là 7. num sẽ có giá trị là 7.
50. Output là gì?
1 2 3 4 5 6 |
[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 ]
Đáp án: C
Khi ta tiến hành map một mảng, giá trị của num sẽ chính là giá trị của phần tử hiện giờ trong vòng lặp. Trong trường hợp này, các phần tử đều là dạng số, tức là typeof num === "number" sẽ là true. Hàm map sẽ tạo ra một mảng mởi từ các giá trị của mảng ban đầu.
Tuy nhiên chúng ta không hề trả về giá trị nào cả. Khi đó, hàm số sẽ mặc định trả về undefined. Do đó qua mỗi vòng lặp, ta lại nhận được thêm một giá trị undefined nữa.
51. Output là gì?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function getInfo(member, year) { member.name = "Lydia"; year = "1998"; } const person = { name: "Sarah" }; const birthYear = "1997"; getInfo(person, birthYear); console.log(person, birthYear); |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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"
Đáp án: A
Đối số sẽ được đưa vào hàm dạng tham trị, trừ phi nó là object, khi đó nó sẽ được đưa vào hàm dạng tham chiếu. birthYear là dạng giá trị, vì nó là string chứ không phải object. Khi chúng ta đưa vào dạng giá trị, một bản sao của giá trị đó sẽ được tạo ra (xem thêm câu 46).
birthYear trỏ đến giá trị là "1997". Đối số year cũng sẽ rỏ đến giá trị "1997", nhưng giá trị này chỉ là một bản sao của giá trị mà birthYear trỏ tới mà thôi, hai giá trị đó hoàn toàn khác nhau. Do đó khi ta thay đổi giá trị year bằng "1998", chúng ta chỉ thay đổi giá trị của year mà thôi. birthYear sẽ vẫn giữ giá trị là "1997".
person là một object. Biến member có một tham chiếu tới cùng object mà person trỏ tới. Khi chúng ta thay đổi một thuộc tính của object mà member trỏ tới, giá trị của person cũng sẽ tự động thay đổi theo, vì chúng có chung tham chiếu. name của person khi này sẽ có giá trị mới là "Lydia".
52. Output là gì?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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!
Đáp án: D
Với lệnh throw, chúng ta có thể tạo ra các errors tùy ý. Với câu lệnh đó, chúng ta có thể throw các exception. Một exeption có thể là một chuỗi, một số, một boolean hoặc một object. Trong trường hợp này thì nó là chuỗi 'Hello world'.
Với lệnh catch chúng ta có thể xử lý những exeption được throw ra khi thực hiện try. Một exeption đã được throw ra: chuỗi 'Hello world'. e chính là chuỗi đó và chúng ta sẽ in ra. Kết quả là 'Oh an error: Hello world'.
53. Output là gì?
1 2 3 4 5 6 7 8 9 |
function Car() { this.make = "Lamborghini"; return { make: "Maserati" }; } const myCar = new Car(); console.log(myCar.make); |
- A: "Lamborghini"
- B: "Maserati"
- C: ReferenceError
- D: TypeError
Đáp án: B
Khi chúng ta 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ề bởi lệnh return, chứ không phải giá trị được set trong constructor. Chúng ta trả về giá trị là "Maserati", do đó myCar.make sẽ là "Maserati".
54. Output là gì?
1 2 3 4 5 6 7 8 |
(() => { let x = (y = 10); })(); console.log(typeof x); console.log(typeof y); |
- A: "undefined", "number"
- B: "number", "number"
- C: "object", "number"
- D: "number", "undefined"
Đáp án: A
let x = y = 10; chính là cách viết ngắn gọn của:
1 2 3 4 |
y = 10; let x = y; |
Khi ta set y bằng 10, thực tế chúng ta đã sử dụng biến global y (window nếu là trên browser, global nếu là môi trường Node).Trên browser, window.y sẽ là 10.
Sau đó, chúng ta khai báo giá trị của x với giá trị của y, tức 10. Tuy nhiên khi ta khai báo với từ khóa let biến x sẽ chỉ tồn tại trong block scoped; hay trong trường hợp này là hàm thực hiện ngay lập tức (immediately-invoked function – IIFE). Khi ta sử dụng phép toán typeof, x hoàn toàn chưa được định nghĩa: vì x lúc này nằm bên ngoài block nó được định nghĩa lúc trước. Nghĩa là x là undefined. Do đó console.log(typeof x) trả về "undefined".
Tuy nhiên với y thì khác, ta đã có giá trị của y khi set y bằng 10. Giá trị đó có thể truy cập được từ bất kì đâu bởi chúng là biến global. y được định nghĩa với kiểu là "number". Do đó console.log(typeof y) trả về "number".
<a name=20190629></a>55. Output là gì?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
Đáp án: A
Chúng ta có thể xóa các thuộc tính khỏe object bằng từ khóa delete, kể cả với prototype. Khi chúng ta xóa một thuộc tính trên prototype, nó sẽ bị vô hiệu hóa hoàn toàn trong chuỗi prototype. Trong trường hợp này, hàm bark sẽ bị vô hiệu hóa ngay sau khi chúng ta thực hiện hàm xóa delete Dog.prototype.bark, tất nhiên ta vẫn có thể truy cập vào nó nhưng giá trị sẽ là undefined.
Khi chúng ta chạy một thứ không phải là hàm, nó sẽ bắn ra một TypeError. Trong trường hợp này là TypeError: pet.bark is not a function, vì bản thân thuộc tính pet.bark là undefined.
56. Output là gì?
1 2 3 4 5 |
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}
Đáp án: D
Set là một tập hơp các giá trị không trùng nhau.
Chúng ta đưa đầu vào là một mảng [1, 1, 2, 3, 4] với giá trị 1 bị trùng. Giá trị trùng đó sẽ bị loại bỏ. Kết quả là {1, 2, 3, 4}.
57. Output là gì?
1 2 3 4 5 |
// counter.js let counter = 10; export default counter; |
- 1 2 anh em xây dựng được đế chế kinh doanh trị giá 35 tỷ USD từ 7 dòng code
- 2 Thời cơ tuyển dụng ngành CNTT đã đến cơ hội hoàn thành KPI tuyển dụng năm 2019
- 3 Một lập trình viên đã jailbreak thành công iOS 13.1.1 vừa ra mắt, bằng lỗ hổng bảo mật không thể vá của Apple
- 4 Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 12) [Phần đặc biệt]
- 5 Webpack là gì? Hướng dẫn webpack 4: tất cả những gì bạn cần biết từ 0 đến khi ra sản phẩm
- 6 Tinh tế trong việc lựa chọn chất liệu áo sơ mi nam
- 7 Nhiều giải pháp tiết kiệm năng lượng được áp dụng trong sản xuất than
- 8 Top 7 khu mua sắm nổi tiếng nhất tại Singapore
- 9 Giá trị kinh tế mang lại của cây Ca Cao mang lại
- 10 Cách sử dụng tủ mát ra sao cho hiệu quả và tiết kiệm điện