Xoắn não với phỏng vấn JavaScript 4

Posted on May 31st, 2018

Xin chào bạn đến bài viết Xoắn não với phỏng vấn JavaScript 4, hôm nay mình lại tiếp tục chia sẻ với bạn những câu hỏi phỏng vấn JavaScript rất hay. Mời bạn theo dõi bài viết!

Xoắn não với phỏng vấn JavaScript 4 – Câu 1

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

let a = [3, 5, 7];
a.x = 'hello';

Object.defineProperty(a, 'y', {});
Object.defineProperty(a, 'z', {
  enumerable: true
});

for (let i of a) {
  console.log(i);
}

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// 3
// 5
// 7

Giải thích:

Trước tiên, mình muốn nhấn mạnh rằng: về bản chất Array được kế thừa từ prototype của Object. Đoạn code sau có thể chứng minh điều đó.

let a = [];
let p1 = Object.getPrototypeOf(a);
let p2 = Object.getPrototypeOf(p1);

console.log(p1 === Array.prototype);  // => true
console.log(p2 === Object.prototype); // => true

Cụ thể, Object.getPrototypeOf(a) trả về prototype của a là p1 – Array.prototype. Tiếp theo, Object.getPrototypeOf(p1) trả về prototype của p1 là p2 – Object.prototype.

Do đó, bạn hoàn toàn có thể thêm thuộc tính cho array giống trên object như các cách sau:

a.x = 'hello';

Object.defineProperty(a, 'y', {});
Object.defineProperty(a, 'z', {
  enumerable: true
});

Vì vậy, nếu bạn hiển thị mảng a trên console thì sẽ thấy giá trị của mảng a như sau:

console.log(a);
// => [3, 5, 7, x: "hello", z: undefined, y: undefined]

Tuy nhiên, mảng a vẫn có độ dài là 3.

console.log(a.length)
// => 3

Nghĩa là các phần tử của mảng a vẫn chỉ là: 3, 5, 7.

Đó là lý do dẫn đến kết quả trên.

Mở rộng:

Thoạt nhìn, bạn có thể thấy rằng for of chả khác gì forEach.

a.forEach(item => {
  console.log(item);
});
/*
* 3
* 5
* 7
*/

Nhưng thực tế, forEach sẽ khác for of ở chỗ là: for of cho phép bạn sử dụng break, continue hay return. Ngược lại, với forEach thì bạn không thể sử dụng các từ khoá này.

Nếu bạn chưa tin thì có thể tự thử nghiệm là sẽ thấy sự khác biệt. Mình chỉ gợi ý vậy thôi nhé!

Bây giờ mời bạn chuyển đến câu hỏi số 2.

Tham khảo:

Xoắn não với phỏng vấn JavaScript 4 – Câu 2

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

let a = [3, 5, 7];
a.x = 'hello';

Object.defineProperty(a, 'y', {});
Object.defineProperty(a, 'z', {
  enumerable: true
});

for (let i in a) {
  console.log(i);
}

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// 0
// 1
// 2
// x
// z
// arrCustom
// objCustom

Giải thích:

Câu 2 chỉ khác câu 1 ở chỗ là mình sử dụng for in thay vì for of. Vậy mà kết quả lại khác biệt như vậy, tại sao?

Bởi lẽ, for in sẽ duyệt hết tất cả các thuộc tính enumerable của bản thân object và những cái mà nó kế thừa từ prototype.

Trong đó:

  • 0, 1, 2 lần lượt là chỉ số các phần tử của mảng, đồng thời cũng là các thuộc tính enumerable.
  • x là thuộc tính định nghĩa thêm như vậy, nên cũng là enumerable.
  • yz định nghĩa bằng cách sử dụng Object.defineProperty nên mặc định giá trị của enumerablefalse – khi không chỉ rõ. Do đó, y thuộc loại non-enumerablezenumerable. Vì vậy, y sẽ không được in ra.
  • arrCustomobjCustom là các thuộc tính (phương thức) được định nghĩa thêm ở prototype của Array và Object. Chúng thuộc loại enumerable. Mà theo câu 1, Array có kế thừa prototype của Object, nên cả 2 thuộc tính này đều được in ra.

Tham khảo:

Xoắn não với phỏng vấn JavaScript 4 – Câu 3

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

let a = [3, 5, 7];
a.x = 'hello';

Object.defineProperty(a, 'y', {});
Object.defineProperty(a, 'z', {
  enumerable: true
});

for (let i in a) {
  if (a.hasOwnProperty(i)) console.log(i);
}

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// 0
// 1
// 2
// x
// z

Giải thích:

Câu 3 khác với câu 2 ở chỗ có sử dụng thêm phương thức Object.prototype.hasOwnProperty(). Phương thức này kiểm tra xem object có chứa một thuộc tính cho trước hay không.

Nếu đúng thì kết quả trả về là true. Ngược lại, nếu thuộc tính đó không tồn tại, hoặc nó là thuộc tính của prototype, hay nó được kế thừa từ prototype thì kết quả trả về là false.

Trong khi đó, arrCustomobjCustom lần lượt là thuộc tính của Array.prototypeObject.prototype nên chúng sẽ không được in ra.

Xoắn não với phỏng vấn JavaScript 4 – Câu 4

let obj = {
  x: 1,
  y: "hello",
  z: {a : 1},
  t: [1, 2]
};

Object.freeze(obj);

obj.x = 2;
obj.y = "bye";
obj.z.a = 2;
obj.t[0] = 3;
obj.t[1] = 4;

console.log(obj);

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// {x: 1, y: "hello", z: {a : 2}, t: [3, 4]}

Giải thích:

Trước tiên, bạn thấy rằng giá trị của x và y không đổi. Trong khi đó, giá trị của z và t đã thay đổi.

Vậy ý nghĩa của Object.freeze là gì?

Object.freeze sẽ không cho phép thêm, sửa và xoá thuộc tính. Tuy nhiên, nếu giá trị của thuộc tính là Object thì giá trị đó vẫn có thể thay đổi. Như trong câu hỏi, giá trị của z, t đều là Object (Array), nên giá trị của chúng vẫn thay đổi được.

Tuy nhiên, bạn sẽ không thể gán z, t cho Object (Array) mới như sau:

let obj = {
  x: 1,
  y: "hello",
  z: {a : 1},
  t: [1, 2]
};

Object.freeze(obj);

obj.x = 2;
obj.y = "bye";
obj.z = {a : 2};
obj.t = [3, 4];

console.log(obj);
// => {x: 1, y: "hello", z: {a : 1}, t: [1, 2]}

Xoắn não với phỏng vấn JavaScript 4 – Câu 5

let obj = {
  x : 1,
  y : "Hi",
  z : function() {
    console.log(this.x, this.y);
  }
};

let str = JSON.stringify(obj);
console.log(str);

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// {"x":1,"y":"Hi"}

Giải thích:

Phương thức JSON.stringify() sẽ convert mỗi giá trị JavaScript thành dạng JSON string.

Và giá trị JavaScript thường dùng nhất chính là object. Tuy nhiên, nếu giá trị của một thuộc tính là function thì JSON.stringify sẽ bỏ qua thuộc tính này.

Đó là lý do tại sao bạn không thấy thuộc tính z trong kết quả.

Xoắn não với phỏng vấn JavaScript 4 – Câu 6

let a = {y: 1};
a.x = a;

let str = JSON.stringify(a);
console.log(str);

Hỏi console in ra kết quả như thế nào, tại sao?

Đáp án:

// TypeError: Converting circular structure to JSON

Giải thích:

Bạn sẽ nhận được lỗi: TypeError: Converting circular structure to JSON. Bởi lẽ, object a ở trên có cấu trúc lặp vô hạn.

Xem thêm: Issue with JSON.stringify() when serializing circular references

Kết luận

Trên đây là 6 câu hỏi phỏng vấn JavaScript cũng rất hay. Nếu bạn có cùng nhận xét với mình thì vui lòng để lại bình luận xuống phía dưới nhé!

Xin chào và hẹn gặp lại bạn trong bài viết tiếp theo, thân ái!


★ Nếu bạn thấy bài viết này hay thì hãy theo dõi mình trên Facebook để nhận được thông báo khi có bài viết mới nhất nhé: