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

Sự khác biệt giữa các kiểu dữ liệu trong JavaScript?


Trong JavaScript các kiểu dữ liệu được chia làm hai loại là kiểu nguyên thuỷ và đối tượng. Để biết kiểu dữ liệu của các biến JavaScript, ta có thể sử dụng typeof.

Kiểu nguyên thuỷ

String - biểu diễn một mảng ký tự hay một chuỗi. Kiểu chuỗi trong javascript có thể sử dụng một cặp dấu ngoặc kép hoặc dấu ngoặc kép đơn.

var str = "Vivek Singh Bisht"; //sử dụng dấu ngoặc kép
var str2 = "John Doe"; // sử dụng dấu ngoặc đơn

Number - biểu diễn cả số nguyên và số thực.

var x = 3; // số nguyên
var y = 3.6; // số thực

BigInt - kiểu dữ liệu này được sử dụng để lưu trữ các số vượt quá giới hạn của kiểu dữ liệu Number. Nó có thể lưu trữ các số nguyên lớn và được biểu diễn bằng cách thêm “n” vào một chữ số nguyên.

var bigInteger = 234567890123456789012345678901234567890;

Boolean - kiểu luận lý, có hai giá trị là truefalse. Thường được dùng với điều kiện.

var a = 2;
var b = 3;
var c = 2;
(a == b)(
  // trả về false
  a == c,
); // trả về true

undefined - khi giá trị của một biến là không xác định.

var x; // giá trị của x là undefined
var y = undefined; // ta cũng có thể gán một biến là undefined

null - biểu diễn giá trị null. Vì JavaScript là case-sensitive, null sẽ không giống với Null, NULL, hoặc bất kỳ biến thể khác.

var z = null;

Symbol - mới được giới thiệu trong ES6. Nó lưu trữ các giá trị duy nhất và ẩn danh.

var symbol1 = Symbol("symbol");

Sử dụng typeof để tìm kiểu nguyên thuỷ:

typeof "John Doe"; // Returns "string"
typeof 3.14; // Returns "number"
typeof true; // Returns "boolean"
typeof 234567890123456789012345678901234567890n; // Returns bigint
typeof undefined; // Returns "undefined"
typeof null; // Returns "object" (đặc trưng của JavaScript)
typeof Symbol("symbol"); // Returns Symbol

Trong JavaScript nếu dữ liệu không phải là kiểu nguyên thuỷ thì tất cả đều là object.

Object dùng để lưu trữ tập hợp dữ liệu

// Tập hợp dữ liệu dạng key-value

var obj1 = {
  x: 43,
  y: "Hello world!",
  z: function () {
    return this.x;
  },
};

// Tập hợp dữ liệu dạng danh sách

var array1 = [5, "Hello", true, 4.1];

Sự khác biệt giữa throw Error('msg') so với throw new Error(‘msg’) là gì?


var err1 = Error("message");
var err2 = new Error("message");

Cái nào đúng và tại sao?

Cả hai đều tốt; lệnh gọi hàm Error(…) tương đương với biểu thức tạo đối tượng mới new Error(…) với các đối số giống nhau.

IIFEs (Immediately Invoked Function Expressions) là gì?


Đó là một Immediately-Invoked Function Expression, gọi tắt là IIFE. Nó thực thi ngay sau khi được tạo:

(function IIFE() {
  console.log("Hello!");
})();
// "Hello!"

IIFEs thường được sử dụng khi cố gắng tránh làm rối global namespace, bởi vì tất cả các biến được sử dụng bên trong IIFE (giống như trong bất kỳ hàm thông thường nào khác) đều không thể sử dụng bên ngoài phạm vi của nó.

Lập trình bất đồng bộ trong Javascript là gì?


Lập trình bất đồng bộ (async) là 1 phần quan trọng trong javascript. Cách tiếp cận phổ biến là sử dụng các callback.

Ví dụ như 1 lệnh ajax gửi request lên server và sau khi nhận được thành công data trả về từ server thì callback sẽ được thực hiện. Thời điểm mà callback được thực hiện không phải là ngay lập tức sau khi có request ajax mà có thể là 1 vài giây sau đó tùy thuộc vào tốc độ xử lí của server.

Ví dụ khác:

console.log("A");
console.log("B");
console.log("C");

thực hiện đoạn code trên cho ra kết quả:

A;
B;
C;

Nhìn vào đoạn code này ta thấy nó hoạt động giống như cơ chế đồng bộ nghĩa là sẽ thực thi từng dòng lệnh một. Ta thay đổi đoạn code trên 1 chút như sau:

console.log("A");

setTimeout(function () {
  console.log("B");
}, 2000);

console.log("C");

Đoạn code trên cho ra kết quả:

A;
C;
B;

Ta thấy rằng thay vì chờ đợi phần lệnh console.log('B') trong setTimeout() chạy xong thì lệnh console.log('C') mới thực hiện giống như cơ chế chạy đồng bộ thì lệnh console.log('C') lại trả về kết quả trước. Đây chính là điểm khác nhau giữa cơ chế bất đồng bộ và đồng bộ trong việc lập trình javascript.

Coercion trong JavaScript là gì?


Đây là cách thức chuyển đổi type của các giá trị trong Javascript, một cách ngầm định, còn rõ ràng thì gọi là type casting. Coercion chính là bí ẩn đằng sau những phép so sánh, phép toán không thể dị hơn của javascript.

Coercion có 2 kiểu: explicit và implicit. Hiểu đơn giản là một cái chuyển kiểu dữ liệu một cách tường minh, mình có thế nhìn thấy được qua mã, trong khi đó kiểu kia thì coercion ngầm định.

Đây là một ví dụ về explicit coercion:

var a = "42";
var b = Number(a);
a; // "42"
b; // 42 -- the number!

Và đây là một ví dụ về implicit coercion:

var a = "42";
var b = a \* 1; // "42" implicitly coerced to 42 here
a; // "42"
b; // 42 -- the number!

Equality operator (==)

console.log(69 == "69"); // true

Sỡ dĩ điều này xảy ra là gì trước khi phép so sánh thực sự xảy ra, javascript sẽ thực hiện coercion. Nói cách khác, nếu 2 value có cùng type, thì chỉ việc so sánh, nhưng nếu chúng khác type, javascript sẽ cố gắng để convert chúng về cùng 1 type rồi mới so sánh. Ở đây 69 và '69' đã được convert về cùng 1 type là number. 69 vẫn giữ nguyên, nhưng '69' sẽ được convert thành 69. 69 == '69' => 69 == 69 => true coercion không tuần theo 1 logic nào cả, mà nó tuân theo các rules mà ta phải nhớ, áp dụng cho vô số các trường hợp (khi so sánh các value, type với nhau). Tôi sẽ liệt kê ra đây 1 số trường hợp mà các bạn hay gặp

So sánh number và string

string sẽ được convert thành number, sau đó so sánh. Trường hợp này dẫn tới 2 trường hợp, 1 là string convert được thành number (ví dụ các string như '10', '1252', ...), việc so sánh là bình thường. Trường hợp 2 là string không thể convert được thành số (ví dụ các string như 'abc', 's1fe13324', ...) các gía trị này sẽ convert thành NaN, và như tôi đã nói ở trên, NaN không bằng giá trị nào cả, nên kết quả trả về luôn là false

So sánh boolean với các type values khác

Đầu tiền boolean value (true => 1, false => 0) thành number, rồi mới so sánh, ví dụ "1" == true sẽ được đổi thành 1 == 1 do true được convert thành number 1 và string "1" convert thành number 1, dẫn tới result là true.

Strict equality operator (===)

Operator này sẽ chỉ compare 2 value, just it, không coercion, không convert type.

ther operator (+, -, *, /)

Trường hợp mà ta hay gặp nhất với các operator này thao tác với number, number và string. Với toàn number thì không nói làm gì. Nhưng giữa number với string, thì ngoài trừ toán tử + sẽ tiến hành chuyển đổi number thành string rồi tiến hành phép nối string, các toán tử khác (-, *, /) đều sẽ convert string thành number và tiến hành phép toán như thông thường, trong trường hợp không convert được thì các bạn biết điều gì xảy ra rồi đấy (NaN)

4 + "3"; // "43"
4 - "3"; // 1
"4" * "3"; //12
"4" / 3; //1.33333

4 + "a";
("4a");
4 - "a"; // NaN
4 * "a"; // NaN
4 / "a"; //NaN

Sự khác biệt giữa shim và polyfill trong Javascript là gì?


  • Một Shim là bất kỳ đoạn mã nào thực hiện việc chặn một lời gọi API và cung cấp một lớp trừu tượng. Nó không bị hạn chế đối với một ứng dụng web hay HTML5 / CSS3.
  • Một Polyfill là một loại Shim trang bị thêm cho các trình duyệt cũ với các tính năng HTML5 / CSS3 hiện đại, thường sử dụng Javascript hoặc Flash.
  • Một Shim là một thư viện mang một API mới đến một môi trường cũ, chỉ sử dụng các phương tiện của môi trường đó. Do đó, polyfill là một shim cho một API trình duyệt.

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

!!null;
!!"";
!!1;
  • A: false true false
  • B: false false true
  • C: false true true
  • D: true true false

Đáp án: B

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ề fase. !false trả về true.

Kết quả đoạn code sau là gì?

console.log(String.raw`Hello\nworld`);
  • A: Hello world!
  • B: Hello
         world
  • C: Hello\nworld
  • D: Hello\n
         world

Đáp án: C

String.raw trả về chuỗi nguyên bản, các ký tự (\n, \v, \t etc.) sẽ vẫn là nguyên bản và không biến thành xuống dòng hay khoảng trắng! Nếu ta không để là chuỗi nguyên bản, sẽ có trường hợp xảy ra lỗi không mong muốn, ví dụ với đường dẫn:

const path = `C:\Documents\Projects\table.html`

Sẽ cho ta chuỗi là:

"C:DocumentsProjects able.html"

Với String.raw, nó sẽ trả về là:

C:\Documents\Projects\table.html

Do đó, trong trường hợp này Hello\nworld sẽ được ghi ra.

Kết quả đoạn code sau là gì?

async function getData() {
  return await Promise.resolve("I made it!");
}

const data = getData();
console.log(data);
  • A: "I made it!"
  • B: Promise {<resolved>: "I made it!"}
  • C: Promise {<pending>}
  • D: undefined

Đáp án: C

Một hàm async luôn luôn trả về một promise. await sẽ chờ cho tới khi promise đó được hoàn thành: một pending promise sẽ được trả về khi ta gọi getData() bằng cách gán nó cho biến data.

Nếu ta muốn truy cập giá trị đã hoàn thành của promise, trong trường hợp này là "I made it", ta có thể sử dụng hàm .then() ngay sau data như sau:

data.then(res => console.log(res))

Khi này nó sẽ ghi ra "I made it!"

Kết quả đoạn code sau là gì?

function addToList(item, list) {
  return list.push(item);
}

const result = addToList("apple", ["banana"]);
console.log(result);
  • A: ['apple', 'banana']
  • B: 2
  • C: true
  • D: undefined

Đáp án: B

Hàm .push() trả về độ dài của mảng mới! Trước đó, mảng chỉ hồm một phần tử là "banana" và có độ dài là 1. Sau khi thêm chuỗi "apple" vào mảng, mảng lúc này có hai chuỗi và có độ dài là 2. Do đó hàm addToList sẽ trả về 2.

Hàm push sẽ thay đổi chính bản thân mảng truyền vào. Do đó nếu chúng ta muốn trả về mảng thay vì chỉ trả về độ dài, chúng ta nên trả về trực tiếp mảng list sau khi đã thêm item vào đó.

Kết quả đoạn code sau là gì?

const box = { x: 10, y: 20 };

Object.freeze(box);

const shape = box;
shape.x = 100;

console.log(shape);
  • A: { x: 100, y: 20 }
  • B: { x: 10, y: 20 }
  • C: { x: 100 }
  • D: ReferenceError

Đáp án: B

Object.freeze khiến cho chúng ta không thể thêm vào, xóa đi hay thay đổi bất kì thuộc tính nào của object (trừ phi giá trị của thuộc tính lại chính là một object khác).

Khi chúng ta tạo ra biến shape và set cho nó giá trị bằng với một object đã được đóng băng là box, thì shape cũng sẽ trỏ tới một object đã được đóng băng. Ta có thể check một object có đang bị đóng băng hay không bằng Object.isFrozen. Trong trường hợp này, Object.isFrozen(shape) trả về true, vì shape đang trỏ tới một object bị đóng băng.

Do đó, cộng với việc x không phải là object, ta sẽ không thể thay đổi giá trị của x. x sẽ vẫn là 10, và { x: 10, y: 20 } được ghi ra.

Avatar Techmely Team
VIẾT BỞI

Techmely Team