Bộ câu hỏi phỏng vấn Javascript phần 1

Sự khác nhau giữa null và undefined trong Javascript?


Undefined có nghĩa là không xác định. Trong javascript, khi bạn khai báo một biến nhưng chưa gán giá trị cho nó, giá trị của biến đó sẽ là undefined.

var test;
alert(test); //undefined

Bất cứ biến nào cũng có thể bị làm rỗng bằng cách thiết lập giá trị về không xác định (undefined).

var test = undefined;
alert(test); //undefined

Null có nghĩa là giá trị rỗng hoặc giá trị không tồn tại, nó có thể được sử dụng để gán cho một biến như là một đại diện không có giá trị.

var test = null;
alert(test); //null

Ngoài ra thì còn một chú ý nữa đó là undefine có kiểu giá trị là undefined nhưng null lại là 1 object

typeof undefined; // undefined
typeof null; // object

Kể tên các kiểu dữ liệu cơ bản trong Javascript


Kiểu dữ liệu nguyên thủy:

  • Number: Các số nguyên hoặc số thực. Ví dụ: 5 hoặc 5.05
  • String: là các text như “Các kiểu dữ liệu trong JavaScript”, text có thể có một hoặc nhiều ký tự.
  • Boolean: chỉ có 2 giá trị là true hoặc false.
  • Undefine: là các giá trị không xác định.
  • Null: đơn giản là không có giá trị nào cả.
  • Symbol: mới được giới thiệu trong ES6. Nó lưu trữ các giá trị duy nhất và ẩn danh

Kiểu dữ liệu không nguyên thủy (tham chiếu):

  • Object: Thể hiện một đối tượng và các thuộc tính có thể truy cập đến.
  • Array: Nhóm các giá trị giống nhau.
  • RegExp: Biểu thức chính quy.

Giải thích về ép kiểu ngầm trong JavaScript?

Ép kiểu ngầm trong javascript là sự chuyển đổi tự động của giá trị từ kiểu dữ liệu này sang kiểu khác. Nó xảy ra khi thực hiện một biểu thức với các kiểu dữ liệu khác nhau.

Ép kiểu String

Ép kiểu string xảy ra khi dùng toán tử +. Một số cộng với một chuỗi, kiểu số sẽ bị ép thành kiểu chuỗi.

Ví dụ:

var x = 3;
var y = "3";
x + y; // Returns "33"
var x = 24;
var y = "Hello";
x + y; // Returns "24Hello";

Để hiểu về hai ví dụ khi ta cộng một số vào chuỗi, thì khi JavaScript thấy biểu thức x+y với hai kiểu khác nhau (một số và một chuỗi), nó chuyển đổi kiểu số thành chuỗi để thực hiện hành động. Sau khi chuyển đổi, cả hai biến đều là kiểu chuỗi, thao tác + lúc này sẽ thành phép nối chuỗi kết quả là ra chuỗi "33" và "24Hello".

Ngược lại, khi thực hiện phép toán -, thì chuỗi lại bị ép kiểu ngầm thành số. Ví dụ:

var x = 3;
Var y = "3";
x - y    //Returns 0 since the variable y (string type) is converted to a number type

Ép kiểu Boolean

Ép kiểu boolean xảy ra khi sử dụng các toán tử logic, lệnh if hay kiểm tra vòng lặp. Để hiểu về ép kiểu logic, ta cần hiểu về giá trị truthyfalsy.

Giá trị truthy là cái sẽ được ép kiểu thành true. Còn falsy sẽ được ép kiểu thành false.

Tất cả các giá trị ngoại trừ 0, 0n, -0, "", null, undefined, và NaN thì đều là truthy.

Câu lệnh If:

var x = 0;
var y = 23;

if (x) {
  console.log(x);
} // The code inside this block will not run since the value of x is 0(Falsy)

if (y) {
  console.log(y);
} // The code inside this block will run since the value of y is 23 (Truthy)

Toán tử Logic:

Toán tử logic trong javascript không giống các ngôn ngữ lập trình khác, nó không trả về true hay false, mà nó trả về một toán hạng.

OR ( || ) - Nếu giá trị đầu tiên là truthy, giá trị đầu tiên sẽ được trả về, ngược lại thì nó trả về giá trị thứ hai.

AND ( && ) - Nếu hai giá trị đều là truthy, giá trị thứ hai sẽ được trả về. Nếu giá trị đầu là falsy sẽ trả về giá trị đầu hoặc giá trị hai là falsy sẽ trả về giá trị hai.

Ví dụ:

var x = 220;
var y = "Hello";
var z = undefined;

x | | y    // Returns 220 since the first value is truthy

x | | z   // Returns 220 since the first value is truthy

x && y    // Returns "Hello" since both the values are truthy

y && z   // Returns undefined since the second value is falsy

if( x && y ){
  console.log("Code runs" ); // This block runs because x && y returns "Hello" (Truthy)
}

if( x || z ){
  console.log("Code runs");  // This block runs because x || y returns 220(Truthy)
}

Ép kiểu dấu bằng

Xảy ra khi thực hiện phép "==". Nhớ lại thì phép "==" được dùng để so sánh hai giá trị khác kiểu.

Thực tế khi sử dụng "==" một ép kiểu ngầm đã xảy ra, chuyển đổi tất cả toán hạng về cùng kiểu và so sánh chúng.

Ví dụ:

var a = 12;
var b = "12";
a == b; // Returns true because both 'a' and 'b' are converted to the same type and then compared. Hence the operands are equal.

Ép kiểu ngầm không xảy ra khi dùng "===".

var a = 226;
var b = "226";

a === b // Returns false because coercion does not take place and the  operands are of different types. Hence they are not equal.

</div>

<div class="question question--basic">
  <h2>Cho biết kết quả của đoạn code dưới đây?</h2>

```js
console.log(1 < 2 < 3);
console.log(3 > 2 > 1);

Kết quả:

true false

Giải thích:

Phép toán trên sẽ thực hiện từ phải sang trái, chúng sẽ so sánh lần lượt các phép tính ở dòng lệnh bên trên 1 < 2 sẽ trả về true tiếp tục true so sánh với 3, khi đó true sẽ bị ép kiểu thành 1 < 3 và kết quả là true. Dòng lệnh thứ 2 giải thích tương tự chúng ta sẽ thu được về kết quả là false

Cho biết kết quả của đoạn code dưới đây?

console.log(typeof undefined == typeof null);

Kết quả: false

Giải thích:

undefine có kiểu giá trị là undefined nhưng null lại là 1 object

Cho biết kết quả của đoạn code dưới đây?

console.log(typeof typeof 1);

Kết quả: string

Giải thích:

typeof 1 là Number và typeof Number là string

Hàm setInterval trả về cái gì?

setInterval(() => console.log("Hi"), 1000);
  • A: một id duy nhất

  • B: số lượng milliseconds

  • C: function truyền vào

  • D: undefined


Đáp án: A

Nó trả về một id duy nhất. Id này dùng để clear interval sau này với hàm clearInterval().

Sự khác nhau giữa Bind, Call và Apply trong Javascript?


Ba hàm bind, callapply là các prototype của Function nên chỉ có Function mới có thể gọi được 3 hàm này. Sở dĩ, một Function có thể gọi Function khác vì trong JavaScript, Function cũng là một loại Object, mà đã là Object thì sẽ có prototype, hay nói cách khác là gọi được phương thức của nó.

  • Nhìn chung, hàm call và apply là gần giống nhau. Chúng đều gọi hàm trực tiếp. Chỉ khác ở cách truyền tham số vào (apply truyền vào một array chứa toàn bộ các tham số còn call truyền lần lượt từng tham số.)
  • Hàm bind thì hơi khác hơn một chút. Hàm này không gọi hàm trực tiếp mà nó sẽ trả về một hàm mới. Và bạn có thể sử dụng hàm số mới này sau. Về cách truyền tham số vào thì nó giống với hàm call.

Hàm anonymous là gì và khi nào nên sử dụng?


Một Anonymous Function là một hàm không có tên (hay còn gọi là hàm ẩn danh), là một hàm được sinh ra đúng vào thời điểm chạy của chương trình.

Thông thường khi bạn khai báo một hàm thì trình biên dịch sẽ lưu lại trong bộ nhớ nên bạn có thể gọi ở trên hay dưới vị trí khai báo hàm đều được, nhưng với anonymous functions thì nó sẽ được sinh ra khi trình biên dịch xử lý tới vị trí của nó. Ví dụ:

// gọi trước hàm
showDomain(); // hoạt động

function showDomain() {
  alert("Học Javascript tại kungfutech.edu.vn");
}

// gọi sau hàm
showDomain(); // hoạt động

Trong ví dụ này cho dù bạn gọi hàm ở phía trên hay dưới đều hoạt động tốt là vì chương trình đã lưu hàm đó vào bộ nhớ. Nhưng nếu ta sử dụng anonymous function như ví dụ dưới đây sẽ bị lỗi ngay.

// gọi trước hàm
showDomain(); // Lỗi vì hàm này chưa tồn tại

var showDomain = function () {
  alert("Học Javascript tại kungfutech.edu.vn");
};

// gọi sau hàm
showDomain(); // hoạt động vì hàm đã tồn tại

Vậy thì, khi nào thì cần Anonymous Function?

Nếu hàm cần được truyền ở nhiều nơi:

  • Định nghĩa 1 hàm thông thường.
  • Truyền hàm đó vào 1 hàm.

Nếu hàm chỉ truyền 1 nơi?

  • Bất tiện khi tạo ra 1 hàm mới (các chi phí như đặt tên hàm).
  • Giúp tăng tính ràng buộc cho việc chỉ được phép truyền 1 lần.
  • Bên cạnh đó hỗ trợ được thêm khả năng chỉ gọi 1 lần.

Strict mode trong JavaScript là gì?


Strict hiểu đơn giản theo nghĩa tiếng Việt là "nghiêm ngặt, nghiêm khắc". Strict Mode là một quy mẫu nghiêm khắc của Javascript. Nếu như coi việc viết code bình thường là Normal Mode, thì Strict Mode sẽ có thêm nhiều quy định khác so với Normal Mode. Việc đó khiến cho một thao tác vốn bình thường có thể chạy ngon lành trở nên lỗi, và throw ra errors.

Nhìn chung, Strict được tạo ra nhằm:

  • Ngăn chặn sử dụng, và throw errors khi người lập trình thực hiện những xử lý được coi là unsafe, những xử lý mà có thể là ngoài ý muốn.
  • Vô hiệu hoá các tính năng có thể gây nhầm lẫn, hoặc không nên được sử dụng.
  • Ngăn chặn sử dụng một số từ mà có thể sẽ được sử dụng làm keywork trong tương lai. Dưới đây là một số ví dụ

Gán giá trị cho biến chưa được khai báo

"use strict";
variable = "thaycacac";
console.log(variable);

//Uncaught ReferenceError: variable is not defined

Báo lỗi khi sử dụng delete

"use strict";
function getName(name) {
  alert(name);
}
delete getName;
//Uncaught SyntaxError: Delete of an unqualified
//identifier in strict mode.

Các tham số của hàm không được trùng nhau

"use strict";
function getName(name, name, age) {
  //code
}
//Uncaught SyntaxError: Duplicate parameter name not allowed in this context

Không cho phép khai báo biến dưới dạng hệ nhị phân

var num = 01010;
//Uncaught SyntaxError: Octal literals are not allowed in strict mode.

Không được phép ghi đè lên thuộc tính chỉ được phép đọc

"use strict";
var obj = {};
Object.defineProperty(obj, "ver", { value: 1, writable: false });
obj.ver = 10;

Không sử dụng được with

"use strict";
var bar = 1;
var foo = 2;
with (bar) {
  console.log(foo);
}
//Uncaught SyntaxError: Strict mode code may not include a with statement

Không cho phép khai báo biến trong eval

"use strict";
eval("var x = 4");
alert(x);
//Uncaught ReferenceError: x is not defined

Không chấp nhận khai báo các keyword. Ở chế độ strict mode thì các bạn sẽ không sử dụng được các từ khóa sau để khai báo làm tên biến, hằng,...

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static
  • yield
  • arguments

Làm sao để clone một mảng?


Để clone một mảng, chúng ta có thể sử dụng một trong các cách dưới đây:

1. Sử dụng hàm slice:

var newArr = originArr.slice();

2. Sử dụng hàm JSON.stringify()JSON.parse() (deep copy):

var str = JSON.stringify(originArr);
var newArr = JSON.parse(str);

3. Sử dụng toán tử spread operator [...] trong ES6:

const newArr = [...originArr];

4. Sử dụng Object.assign:

var newArr = Object.assign([], originArr);

5. Sử dụng Array.map()

const arrOrigin = [1, 2, 3];
const newArr = arrOrigin.map(x => x);

Ngoài ra chúng ta cũng có thể clone mảng qua các hàm như vòng lặp while(), vòng lặp for(), Array.filter(),...

Scope của 1 biến trong javascript là gì? Có bao nhiêu loại scope?


Scope của 1 biến là phạm vi trong chương trình của bạn mà biến đó được định nghĩa và thể sử dụng được.

Trong javascript có 3 loại scope:

  • Global scope: có phạm vị hoạt động ở bất kỳ trong mã javascript của bạn.
  • Function scope: có phạm vi hoạt động trong function mà bạn khai báo biến đó.
  • Block scope: có phạm vị trong cặp dấu {} mà bạn khai báo biến đó. (ES6)

Khi nào cần sử dụng async và defer trong javascript?


<html>
<head></head>
<body>
    <script src="script.js">
</body>
</html>

Với thẻ script không có thuộc tính gì khác thì HTML file sẽ được parse cho đến khi gặp phải thẻ script, đến lúc này thì quá trình parse sẽ tạm dùng và để fetch script file về (nếu là external file), sau đó execute những code script này, sau đó mới tiếp tục lại quá trình parse html.

<script async src="script.js">

Với thẻ script có thuộc tính async, khi quá trình parse html gặp phải script này, nó sẽ vẫn tiếp tục parse html cho đến khi script này được download xong, thì quá trình parse html mới tạm dừng để execute những code script này, sau đó lại tiếp tiếp quá trình parse html.

<script defer src="script.js">

Với thẻ script có thuộc tính defer, quá trình parse html sẽ không bị dừng lại mà parse cho đến khi hoàn thành, quá trình download các script file được tiến hành song song, và cuối cùng thì sẽ execute những script code này khi html đã parse xong.

Việc hiểu rõ tính chất, nguyên lý của 2 thuộc tính trên sẽ giúp biết rõ nên sử dụng chúng trong từng trường hợp cụ thể nào. Một số gợi ý:

  • Nếu script của bạn là một module nào đó, chạy độc lập và không phụ thuộc vào bất kỳ script nào khác thì dùng thuộc tính async.
  • Nếu script của bạn phụ thuộc vào một script khác hoặc được một script khác sử dụng lại (phụ thuộc vào) thì nên sử dụng thuộc tính defer.
  • Nếu script của bạn nhỏ chỉ có vài dòng code thì xuất ngay các đoạn code vào bên trong thẻ script luôn (inline script), đừng tạo file JavaScript độc lập và không dùng 2 thuộc tính kia.
  • Nếu script của bạn nhỏ như bên trên (ít code), và được một script khác sử dụng thuộc tính async phụ thuộc vào thì xuất script theo kiểu inline và đặt trước đoạn script async.
Avatar Techmely Team
VIẾT BỞI

Techmely Team