Tóm Tắt
Phỏng vấn JavaScript người ta hỏi gì? – Phần 1
Published: 2018-10-23 20:19:18
Hình trên mình lấy từ một video trên youtube. Cái background chỉ là minh họa cho đoạn tweet mà anh speaker trong video đó thêm vào thôi.
Tác giả của tweet đó là anh Ried Draper (một kỹ sư ở GitHub) sau khi ngồi trơ mắt ngó một ứng viên bỏ dở buổi interview và bước đi không ngoảnh lại. Mình tạm dịch là:
“Đoạn code Fizz Buzz ưa thích của tôi vừa bỏ ra ngoài [giữa] buổi phỏng vấn”
Nếu bạn biết về Fizz Buzz problem thì có lẽ sẽ hiểu vì sao anh chàng đó bỏ về. Mình cùng đoán nhé. Anh ta là một Front-end developer với 5 năm kinh nghiệm, full tự học và không có bằng Computer Science gì. Hoặc cũng có thể anh ta chỉ là một Junior Developer 🤔?! Nhưng rất có thể hằng ngày anh ta chủ yếu chỉ làm việc với lib và framework, và tạo ra những tuyệt tác trong khi không hoàn toàn nắm rõ hay hiểu bản chất của đống tools đó.
Giống như phần lớn dân dev chúng ta thôi. Nên gặp phải những câu hỏi khá là basic như thế, những vấn đề mà ta chẳng mấy lúc hoặc chả gặp trong khi hằng ngày vẫn code đẹp và app vẫn chạy mượt mà, thì phần đông ai cũng thấy hơi nản: “Thằng cha này hỏi toàn ba thứ linh tinh!” 😂.
Phần 1 này sẽ tập trung vào những câu hỏi kiểu như vậy.
Mục lục
Fizz Buzz
Cho i
chạy từ 1 tới 100. In fizz ra console
nếu i
chia hết cho 3, buzz nếu chia hết cho 5 và fizzbuzz nếu chia hết cho cả 3 và 5
Solution có thể tham khảo ở đây: https://gist.github.com/jaysonrowe/1592432.
Vậy mục đích của người phỏng vấn là gì? Bạn thấy đấy, câu hỏi tuy đơn giản nhưng có quá trời đáp án khác nhau. Quan điểm ở đây là Software Development không chỉ có cắm đầu code, mà còn nhiều thứ khác: clean code, optimization và quan trọng là cách giải quyết vấn đề.
Dạng câu hỏi này sẽ là chưa đủ để nhận diện một developer giỏi, nhưng nó sẽ nhận diện được những kẻ yếu. Vậy nên xài câu này là một hướng đi đúng đắn của nhà tuyển dụng để phân loại ứng viên. Càng rõ hơn khi yêu cầu họ viết code ra giấy và giới hạn chỉ trong 2-3 phút.
for
(i=0
; i<100
; ) console
.log
((++i%3
?''
:'Fizz'
) + (i%5
?''
:'Buzz'
) || i)
JavaScript Hoisting
Về cơ bản, khi code được compile, tất cả variable khai báo sau từ khóa var
sẽ được “hoiste” lên phía trên cùng của file .js (global) hay trên cùng của function (local). Bất kể bạn khai báo đống varibale đó ở đâu.
console
.log
(myName);
var
myName = "Lemon'"
;
var
myName;
console
.log
(myName);
myName = "Lemon'"
;
Vậy, hỏi câu này làm gì? Nếu chăm đọc code người khác, bạn hẳn sẽ thấy nhiều người có thói quen declare biến trên cùng rồi phía dưới mới assign value sau. Đó là một best practice (maybe) trước cái concept “hoisting” này.
Lưu ý rằng “hoisting” cũng áp dụng cho cả let
và const
. Bạn có thể xem chi tiết ở bài viết này.
==
vs ===
Javascript bà điên có hai kiểu so sánh bằng: ===
(!==
) and the evil ==
(!=
). ===
là toán tử so sánh rất bình thường và an toàn: cùng type cùng value thì true
không thì false
. ==
thì đôi lúc sẽ giết ta khi 2 toán hạng khác type, bằng cách cố gắng ép về cùng 1 type để so sánh.
''
== '0'
0
== ''
0
== '0'
false
== 'false'
false
== '0'
false
== undefined
false
== null
null
== undefined
' \t\r\n '
== 0
Vậy làm sao cho nó an toàn? Theo mình thì nên xài ===
là an toàn nhất vì nó rõ ràng. Team đông thì nên xài một linter, thống nhất và đặt ra các rule để tránh các rủi ro chết chóc do JS si đa gây nên.
Undeclared vs undefined vs null
undeclared
Không khai báo trước khi xài
const
bar = foo + 5
;
undefined
- Khai báo nhưng không có value nào cả (nhưng mà
const a;
thì báo lỗi chứa
không phải làundefined
nhé). - Function không trả về gì hết
- Truy xuất value của một property không có trong object hay tại một index vượt quá length của array.
const
foo = {xx
:1
}; foo.xxx
;const
bars = [1
,2
]; bars[2
];
null
null
là một value. Value đó không là gì cả, nhưng nó là một value 😖.
Kiểm tra undefined và null
let
foo;
console
.log
(typeof
foo);
console
.log
(typeof
bar):
console
.log
(foo === undefined
);
const
baz = 'undefined'
;
console
.log
(baz === undefined
);
const
foo = null
;
console
.log
(typeof
foo);
console
.log
(foo === null
);
if
(!foo) {
Kiểm tra một array có tồn tại hoặc empty không
if
(!Array
.isArray
(array) || !array.length
) {
}
Trình bày về Scope và Context trong JavaScript
Scope
Scope trong JS cũng như các ngôn ngữ khác, có Global và Local scope. Global scope tồn tại cho đến khi ứng dụng bị tắt. Local scope tồn tại cho đến khi function chạy xong. ES6 giới thiệu let
và const
mang local scope đến với block statement
.
if
(true
) {
var
name = 'Lemon'
;
let
likes = 'Coding'
;
const
skills = 'JavaScript and C#'
;
}
console
.log
(name);
console
.log
(likes);
console
.log
(skills);
Context
Context! Hmm, là một khái niệm rất quan trọng cần phải nắm nếu không muốn sấp mặt với Javascript. Về cơ bản thì context là value của this
. Trong “global scope” thì context luôn là window
object.
class
User
{
logName
() {
console
.log
(this
);
}
}
(new
User
).logName
();
function
logFunction
() {
console
.log
(this
);
}
new
logFunction
();
Phải cẩn thận với arrow function nhé.
const
foo = {
a
: function
() { console
.log
(this
); },
b
: () =>
{ console
.log
(this
); }
}
foo.a
();
foo.b
();
Đọc thêm về Scope và Context ở đây.
Closure là gì?
Hãy bắt đầu với một ví dụ (được lấy từ một bài viết trên Kipalog), từ đó bạn sẽ dễ trình bày hơn với interviewer.
function
outer
(x
) {
function
inner
(y
) {
return
x + y;
}
return
inner;
}
fn_inner = outer
(3
);
result = fn_inner
(5
);
result1 = outer
(3
)(5
);
Về cơ bản, sau khi execute xong, outer()
trả về một function fn_inner()
và đồng thời một bao đóng (closure) được tạo ra gói cái context bao gồm con số 3
đó lại. Hay nói cách khác là đóng gói biến x
tại thời điểm outer()
được gọi.
Vậy khi nào thì xài closure? Trường hợp tiêu biểu nhất là khi cần assign các hàm eventHandler cho nhiều element một lúc.
const
addHandlers = function
(nodes
) {
const
helper = function
(i
) {
return
function
(e
) {
alert
(i);
};
};
for
(let
i = 0
; i < nodes.length
; ++i) {
nodes[i].onclick
= helper
(i);
}
};
Nói một cách hàn lâm hơn: Một trong những ứng dụng mạnh mẽ của closure là sử dụng hàm outer()
như một “function factory”.
Bind, Call và Apply
Tôi đi code dạo đã viết về 3 thứ đó khá là thú vị và sinh động dễ hiểu rồi. Mình chỉ muốn lưu ý một chút là cái bind
đó rất quan trọng khi bạn code ReactJS. Nó đảm bảo value của this
là đúng trong callback khi handle event, chi tiết ở đây.
Event Loop, Call Stack và Callback Queue là gì?
Riêng câu này xứng đáng có một bài viết riêng. Và nó đây: Javascript hoạt động như thế nào?
Lời kết
Dù bạn không thể trả lời hay chỉ trả lời được phần nào đó thôi trong mớ câu hỏi trên, thì mình tin rằng, những kiến thức đó rất bổ ích. Chúng sẽ giúp bạn tránh những lỗi ngớ ngẩn hay gặp và thiết kế chương trình được tốt hơn.
Phần 1 tới đây thôi. Mời các bạn ghé đọc tiếp phần 2.