Home / Lập Trình Front End / Front – End & Full-Stack javascript : Tổng hợp các bài phỏng vấn JavaScript cực chất Tiếng Việt và Tiếng Anh

Front – End & Full-Stack javascript : Tổng hợp các bài phỏng vấn JavaScript cực chất Tiếng Việt và Tiếng Anh

Đối với cả ngành công nghệ phần mềm hiện nay, thì số lượng việc làm có liên quan đến lĩnh vực web chiếm một tỉ trọng tương đối lớn. Lập trình viên có khả năng làm về web đang được săn tìm khá nhiều trên các trang tìm việc online đủ để minh chứng cho điều này. Và nếu đã làm web thì không thể không nhắc tới ngôn ngữ Javascript. Kĩ năng về Javascript không chỉ cần thiết cho công việc phát triển Client-side của hệ thống, ngoài ra với sự xuất hiện của NodeJS và nhiều Framework hỗ trợ khác, bạn có thể làm việc như một Fullstack developer với chỉ 1 ngôn ngữ duy nhất là Javascript, thậm chí là ứng dụng web của bạn còn có thể được mang lên cả các thiết bị di động cũng chỉ với Javascript, thật vi diệu ^^.

Tất cả những điều đó có đủ thuyết phục để bạn bỏ công sức ra tìm hiểu về Javascript chưa? Công việc có liên quan tới Javascript tràn ngập ngoài thị trường, và nếu bạn có ý định tìm một công việc nào đó có liên quan đến ngôn ngữ này, thì bạn cần phải xem lại các vấn đề cốt lõi sau đây để có thể vượt qua được vòng phỏng vấn của các công ty tuyển dụng. Càng nắm vững kiến thức, vượt qua được các câu hỏi phỏng vấn dễ dàng bao nhiêu thì cơ hội bạn nhận được mức lương tốt cũng sẽ cao tương ứng. Chúng ta cùng xem thử các vấn đề thường gặp phải trong các bài phỏng vấn Javascript thôi nào.

1. Vấn đề đầu tiên: Scope (tầm vực) của biến.

Scope trong Javascript có một chút khác biệt so với các ngôn ngữ lập trình khác, Scope trong Javascript có phạm vi nằm trong hàm (function scope):

  • Thứ 1: Biến được khai báo bên trong hàm sẽ là biến cục bộ, và biến cục bộ thì có thể được truy cập bên trong hàm (không có khái niệm scope trong 1 khối lệnh).
  • Thứ 2: Biến được khai báo bên ngoài hàm sẽ là biến toàn cục, và có thể được truy cập từ bất cứ đâu.

Chú ý: biến khai báo bên trong hàm mà không có từ khoá “var” cũng sẽ trở thành biến toàn cục. Ngoài ra, việc khai báo “var” mà lại không nằm trong function nào thì biến cũng sẽ mang tầm vực toàn cục.

Chúng ta kiểm chứng lại ngay sau đây, đầu tiên là khai báo một hàm trong Javascript

function testScope()
{
var local_var_1 = global_var_1 = "inside_function";
if(true){
var local_var_2 = "inside IF";
}
console.log("Test local_var_1 inside function: " + local_var_1);
console.log("Test local_var_2 inside function: " + local_var_2);
}

Mọi người thử trả lời xem kết quả của câu lệnh dưới đây là gì nào?

testScope();
console.log("Test local_var_1 outside function: " + local_var_1);
console.log("Test global_var_1 outside function: " + global_var_1);

Dưới đây là đáp án cho câu hỏi trên, các bạn nên thử tự mình trả lời rồi so sánh với kết quả bên dưới này xem như thế nào nhé:

Test local_var_1 inside function: inside_function
Test local_var_2 inside function: inside IF
undefined
Test global_var_1 outside function: inside_function

Bằng việc thực thi hàm testScope(), chúng ta sẽ kiểm tra được giá trị của biến “local_var_2” mặc dù được khai báo bên trong khối lệnh if() nhưng nó vẫn sẽ có tầm vực truy cập bên ngoài khối lệnh này. Tầm vực của biến “global_var_1” có giá trị toàn cục, do vậy ta vẫn có thể truy cập giá trị biến này bên ngoài hàm, lí do là ta đã không dùng từ khoá “var” khi khai báo biến này (chú ý là trong trường hợp này “var” chỉ có tác dụng khai báo với biến “local_var_1” mà thôi).

Vấn đề về scope trong Javascript có đôi chút nhập nhằng, do vậy mà mình khuyên mọi người luôn dùng từ khoá var để khai báo biến nhằm tránh các tình huống biến trở thành biến toàn cục có thể dẫn tới những lỗi rất khó để phát hiện. Ngoài ra nên dùng thêm từ khoá “use strict” để sử dụng Javascript với strict mode, mode này sẽ yêu cầu bạn phải khai báo tường minh tất cả mọi thứ để tránh các lỗi tiềm tàng có thể xảy ra.

2. Khái niệm hoisting

Khi code sử dụng javascript, có một khái niệm cũng khá là đặc biệt là hoisting. Với khái niệm này, javascript quy định, mọi khai báo biến đều được đưa lên trên cùng của một tầm vực. Tức là mặc kệ bạn khai báo biến ở vị trí nào trong 1 hàm, thì tự động nó sẽ kéo lên trên cùng của hàm để khai báo (javascript tự động thực hiện ngầm cho khái niệm này).

Khái niệm hoisting này cũng là một khái niệm khác biệt của Javascript, nhiều lập trình viên thường bỏ qua vấn đề này, và đây cũng là 1 trong những nguyên nhân gây ra lỗi rất khó phát hiện ở trong ngôn ngữ lập trình này. Chạy thử đoạn code sau để hiểu rõ hơn:

var hoisting_example = 'test_hoisting_AAA';
function explainHoisting(){
console.log(hoisting_example);
var hoisting_example = "testing_hoisting_BBB";
console.log(hoisting_example);
}

Chắc hẳn là nhiều người sẽ nghĩ rằng kết quả là thế này:

testing_hoisting_AAA
testing_hoisting_BBB

Tuy nhiên, đáp án ở trên là SAI. Kết quả đúng phải là:

undefined
testing_hoisting_BBB

Câu hỏi đặt ra là: tại sao ở lần đầu tiên in ra, thì biến “hoisting_example” lại không có giá trị? Câu trả lời là: chính việc hoisting trong Javascript làm như thế. Như đã nói ở trên, việc khai báo biến đã được Javascript ngầm thực hiện ở trên đầu hàm, chính điều này làm mất đi giá trị của biến “hoisting_example” đã được khai báo bên ngoài hàm. Tóm lại, đoạn code ở trên có thể được hiểu một cách tường minh như sau:

var hoisting_example = 'test_hoisting_AAA';
function explainHoisting(){
var hoisting_example;
console.log(hoisting_example);
hoisting_example = "testing_hoisting_BBB";
console.log(hoisting_example);
}

Ngoài ra, trong phiên bản ESMAScript 6, chúng ta có them từ khoá khai báo biến mới đó là “let”. Từ khoá “let” dung để khai báo 1 biến có tầm vực trong 1 block code, tứ là nó sẽ không ảnh hưởng bởi khái niệm hoisting, mọi người có thể tìm hiểu them trên google để hiểu rõ hơn về các đặc trưng mới của phiên bản ECMAScript 6. Và hãy nhớ, để ý vấn đề hoisting khi làm việc với Javascript nha mọi người!

3. Về Native method, khái niệm Object và Prototype của Object

Chúng ta thử chạy đoạn lệnh dưới đây và giải thích kết quả xem nào:

1
2
3
4
5
var num = 5;
typeof(num);          //”number”
//chạy lệnh lấy bình phương của số đó
num.square();        // Uncaught TypeError: num.square is not a function

Mọi người thử trả lời câu hỏi tại sao lệnh lấy bình phương square() lại báo lỗi? Nếu bạn cho rằng kiểu dữ liệu number không có sẵn phương thức square() thì bạn đã trả lời đúng rùi đấy. Vậy câu hỏi đặt ra tiếp theo là: làm thế nào để ta khiến cho câu lệnh đó thực thi đúng như mong đợi? 1p suy nghĩ bắt đầu ^^

… … … … Hết giờ … … …

Có thể là giải pháp của bạn trông giống như sau:

1
2
3
4
Number.prototype.square = Number.prototype.square || function(){return this*this;};
//Gọi thử lệnh để xem kết quả xem nào:
num.square();               //25

Công việc chúng ta vừa làm ở trên là: xây dựng thêm một native method cho kiểu dữ liệu number, đây thực chất là việc thêm một phương thức prototype cho đối tượng built-in là Number.

Như bạn đã thấy, để có thể đưa ra giải pháp ở trên, chúng ta cần các kiến thức về khái niệm Object và prototype của Object trong Javascript. Những thuộc tính và phương thức trong prototype của object sẽ được các object con kế thừa. Đây chính là 1 đặc điểm hết sức khác biệt nữa của Javascript: nó là một ngôn ngữ sử dụng kế thừa kiểu object-based (không giống class-based như các ngôn ngữ OOP truyền thống).

Các bạn cần phải chuẩn bị kĩ các kiến thức về Object và khái niệm prototype của object nếu muốn trở thành một lập trình viên Javascript tốt. Hôm nào có thời gian mình cũng sẽ ôn lại các kiến thức đó qua một bài viết mới. Các bạn nhớ đón xem nhé ^^

4. Con trỏ this

Con trỏ this được sử dụng rất nhiều trong các đoạn mã JS, và nó cũng là một trong những khái niệm gây ra nhiều sự hiểu lầm (dẫn đến bug) nhất trong ngôn ngữ này. Để lập trình tốt bằng Javascript thì người lập trình viên buộc phải hiểu rõ cách mà con trỏ this vận hành.

Trong các ngôn ngữ OOP điển hình như C++, PHP, Java, … khái niệm con trỏ “this” tương đối dễ hiểu, nó gắn liền với thực thể (instance) đang được kích hoạt. Ở javascript thì mọi chuyện có vẻ phức tạp hơn, giá trị của this gắn liền với context mà nó được gọi, xét thử đoạn code sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var name = "Peter";
var Hocsinh = {
    name: "John",
    printName: function(){
        console.log(this.name);
    }
};
//Lệnh gọi đầu tiên
var printHocsinhName = Hocsinh.printName;
printHocsinhName();                          // Peter
//Lệnh gọi thứ 2
Hocsinh.printName();                         // John

Như ta đã thấy, kết quả của 2 lần gọi hàm này cho ta 2 kết quả khác nhau. Tại sao lại như vậy? Thử đưa ra câu trả lời xem nào. Cho bạn 100 giây suy nghĩ: 1 … 2 …3 …4 … 5 … 100 … hết giờ =))

Ở lần gọi đầu tiên, hàm này được kích hoạt không bởi đối tượng cụ thể nào, tức là context của hàm printName được gán là biến toàn cục window, trong khi đó đối tượng gọi hàm ở lần chạy thứ 2 là đối tượng Hocsinh, do vậy mà giá trị của this sẽ có giá thị của đối tượng Hocsinh.

Sự nhập nhằng của giá trị this trong Javascript có thể khiến lập trình viên bối rối, và nếu bạn muốn vượt qua các buổi phỏng vấn cũng như nâng cao kĩ năng viết code Javascript của mình, thì nên đầu tư tìm hiểu khái niệm này kĩ hơn. Mình có chia sẻ về khái niệm con trỏ “this” ở đây (LINK), các bạn có thể tìm hiểu thêm.

Bind(), Call(), Apply()

Đi kèm với các hàm này là vấn đề liên quan tới giá trị của con trỏ “this”, ta xem lại ví dụ ở trên, lí do mà 2 lần gọi hàm ta được 2 kết quả khác nhau là bởi vì context của con trỏ this ở 2 tình huống là khác nhau. Nếu ta muốn kết quả in ra đúng với ý định của mình, thì ta có thể gán context cho con trỏ this một cách tường minh bằng các hàm bind(), call() hoặc apply().

Bây giờ thử trả lời câu hỏi: làm thế nào cả lệnh gọi printHocsinhName cho ta kết quả là “John”, và làm thế nào để ta có thể gọi hàm Hocsinh.printName mà lại có kết quả là “Peter”???

Chúng ta lại có thêm 100s suy nghĩ nữa nào: 1 … 2 … 3 … 99 … 100 … và … hết giờ ^^. Cùng thử so sánh đáp án xem nào:

1
2
3
4
5
6
7
8
9
10
//Cách thứ nhất
var printHocsinhName = Hocsinh.printName.bind(Hocsinh);
printHocsinhName();                                      // John
//Hoặc cách thứ 2
var printHocsinhName = Hocsinh.printName;
printHocsinhName.call(Hocsinh);                          // John
//Xử lí Hocsinh.printName
Hocsinh.printName.call(window);                           //Peter

Bản chất của câu hỏi này nhằm kiểm tra các kiến thức của bạn về khái niệm context của con trỏ this khi được gọi, và các cách thức để kiểm soát được giá trị này một cách chặt chẽ hơn. Cả 3 hàm này đều có ý nghĩa là gán giá trị của con trỏ this khi được chạy tới một giá trị cụ thể nào đó, và nếu bạn nắm được khái niệm context của con trỏ this, bạn sẽ giải quyết được câu hỏi này cách dễ dàng.

Nhắc lại 1 chút, bản thân một hàm (function) cũng là 1 object trong Javascript, vậy nên chúng ta sẽ rất hay bắt gặp các tình huống làm thay đổi context của hàm như: truyền qua object function, hàm mượn, callback, … Nắm được cách sử dụng các hàm bind(), call(), apply() sẽ giúp chúng ta kiểm soát tốt và đảm bảo được kết quả chạy của các hàm đúng với mong muốn. Mọi người có thể xem thêm chi tiết tại đây (LINK)

Ngoài ra, bạn cũng cần coi thêm các kiến thức về cơ chế xử lí bất đồng bộ như: các thao tác gọi xử lí AJAX, các kiểu Promise hỗ trợ thực thi bất đồng bộ và giúp tránh callback hell, v.v.v Nắm được hết các vấn đề này, thì bạn có thể tự tin là mình đã biết được khá rõ về Javascript rồi đó 🙂

Javascript Promise

Promise là gì?

Promise được sinh ra để thể hiện cho kết quả sau cùng của một tác vụ bất đồng bộ (asynchronous operation). Nó là một placeholder mà trong nó kết quả của việc thực thi tác vụ bất đồng bộ đó dù thành công hay thất bại sẽ được hiện thực.

Tại sao lại sử dụng Promise?

Nếu so sánh với các phướng thức callback-based truyền thống thì promise cung cấp một biện pháp thay thế đơn giản hơn trong việc thực thi, biên soạn và quản lý các tác vụ bất đồng bộ. Hơn cả, promise cho phép chúng ta handle các lỗi xảy ra khi thực thi tác vụ bất đồng bằng các sử dụng các phương thức tiếp cận tương tự với sử dụng try/catch trong các tác vụ đồng bộ (synchronous) thông thường.

Promise States

Promise có thể ở một trong ba trạng thái.

  • Pending – trang thái khởi tạo, lúc này kết quả của promise vẫn chưa được xác định, bởi vì tác vụ bất đồng bộ vẫn chưa hoàn thành.
  • Fulfilled – trạng thái hoàn thành, tác vụ bất đồng bộ đã hoàn thành, và promise đã có giá trị.
  • Rejected – trạng thái bị từ chối, tác vụ bất đồng bộ thực thi thất bại, và promise sẽ không bao giờ được hoàn thành (fulfilled). Trong trạng thái bị từ chối (rejected) một promise sẽ chứa một lý do (reason) để chỉ ra tại sao việc thực thi thất bại.

Khi một promise đang ở trạng thái khởi tạo (pending), nó có thể chuyển sang trạng thái hoàn thành (fulfilled) hoặc bị từ chối (rejected). Một khi promise được hoàn thành hoặc bị từ chối, thì đó sẽ là giá trị cuối cùng, promise đó sẽ không thể chuyển thành trạng thái khác được nữa, và vì thế giá trị của nó hoặc lý do thực hiện thất bại sẽ không thay đổi.

Sử dụng Promise

Điểm quan trọng nhất của một API cho promise chính là phương thức then(), đây chính là cái mà các callback đăng kí vào để nhận giá trị trả về hay lý do promise không thể hoàn thành. Dưới đây là một đoạn code “hello world” được viết dưới dạng thông thường (synchronous).

var greeting = sayHello();
console.log(greeting); // ‘hello world’
view rawpromise.js hosted with ❤ by GitHub

Tuy nhiên, nếu phương thức sayHello là một phương thức bất đồng bộ, và cần lấy dữ liệu từ một web service nào đó trả về, chúng ta có thể chuyển nó thành promise như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
console.log(greeting); // ‘hello world’
});
view rawpromise.js hosted with ❤ by GitHub

Message vẫn được in ra console, nhưng giờ đây, những block code khác có thể tiếp tục chạy khi lời chào đang được fetch.

Như tôi đã nói ở trên, một promise có thể đại diện cho một thất bại. Nếu như network có vấn đề và lời chào không thể được fetch từ web service, chúng ta có thể đăng kí một callback để giải quyết các lỗi bằng cách sử dụng tham số thứ hai của phương thức then như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
console.log(greeting); // ‘hello world’
}, function (error) {
console.error(something went wrong: , error); // ‘something went wrong: blabla’
});
view rawpromise.js hosted with ❤ by GitHub

Nếu sayHello thành công, lời chào sẽ được in ra console, nhưng nếu nó thất bại, thì lý do thất bại sẽ được in ra console bằng console.error.

Chuyển đổi giá trị trong tương lai

Một khía cạnh mạnh mẽ của promise là cho phép chúng ta có thể chuyển đổi giá trị trả về trong tương lai bằng việc trả về một giá trị mới trong callback và truyền nó vào trong phương thức then. Ví dụ.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
return greeting + !;
}).then(function (greeting) {
console.log(greeting); // ‘hello world!’
});
view rawpromise.js hosted with ❤ by GitHub

Chuỗi các tác vụ bất đồng bộ

Một function được truyền vào then có thể trả về giá trị là một promise khác. Điều này cho phép các tác vụ bất động bộ tạo thành một chuối mắt xích với nhau, cũng vì thế mà có thể dảm bảo rằng chúng xảy ra theo thứ tự đúng đắn. Lấy ví dụ, nếu hàm thêm dấu “!” (addExclamation) là một tác vụ bất đồng bộ và trả về một promise để các hàm gọi lời chào tiếp theo được thực hiện như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
return addExclamation(greeting); // addExclamation returns a promise
}).then(function (greeting) {
console.log(greeting); // ‘hello world!’
});
view rawpromise.js hosted with ❤ by GitHub

Thì chúng ta có thể viết một cách đơn giản hơn như sau.

var greetingPromise = sayHello();
greetingPromise
.then(addExclamation)
.then(function (greeting) {
console.log(greeting); // ‘hello world!’
});
view rawpromise.js hosted with ❤ by GitHub

Xử lý lỗi

Điều gì xảy ra nếu có lỗi trong khi thực hiện tác vụ bất đồng bộ? ví dụ như hàm sayHello, hoặc addExclamation bị fail?

Trong code synchronous, chúng ta sử dụng try/catch  and dựa vào exception để handle lỗi. Dưới đây sẽ là các code synchronous thông thường, dùng try/catch để xử lý lỗi. Nếu có lỗi xảy ra, thì catch block sẽ được thực thi, in lỗi ra console.

var greeting;
try {
greeting = sayHello();
greeting = addExclamation(greeting);
console.log(greeting); // ‘hello world!’
} catch(error) {
console.error(something went wrong: , error); // ‘something went wrong: blabla’
}
view rawpromise.js hosted with ❤ by GitHub

Khi thực hiện với các tác vụ bất đồng bộ, try/catch block ko thể sử dụng được nữa. Tuy nhiên, promise cho phép chúng ta handle lỗi của các tác vụ bất đồng bộ bằng cách đơn giản hơn, không chỉ cho phép chúng ta viết code asynchronous tương tự với style code synchronous, mà còn kiểm soát được flow và handle lỗi tương tự như synchronous code.

Dưới đây và phiên bản asynchronous dùng để handle lỗi.

var greetingPromise = sayHello();
greetingPromise
.then(addExclamation)
.then(function (greeting) {
console.log(greeting); // ‘hello world!’
}, function(error) {
console.error(something went wrong: , error); // ‘something went wrong: blabla’
});
view rawpromise.js hosted with ❤ by GitHub

 

JavaScript Closures

Closure là gì?

Closure thực chất là một khái niệm, nếu dịch sát nghĩa thì nó là thứ dùng để bao đóng một số thứ khác.

Ví dụ đơn giản thôi, nếu bạn có một cái thùng, đem con mèo của bạn cùng với mớ đồ chơi của nó quẳng hết vào trong thùng sau đó đóng thùng lại, ta có thể thấy cái thùng chính là Closure bao đóng con mèo và đồ chơi của nó. Và trong lúc đó, con mèo vẫn có thể sử dụng đồ chơi của nó bất kể khi nào nó muốn vì tất cả đều ở trong thùng cùng nó. Haha.

Silver_Tabby_Cat_In_A_Box_IMG_4451.jpg

Thế nào là Javascript Closure?

Từ ngữ cảnh con mèo, đồ chơi và cái thùng, đem hết tất cả vào trong Javascript ta sẽ có cái thùng là Closure. Thay vì quăng con mèo vào thùng thì ta quăng function vào đó, và thay vì đồ chơi ta đặt hết tất cả các biến vào trong tầm vực của fucntion kia.

9499522885_525b651880

Điều quan trọng là function nằm bên trong Closure vẫn có thể truy xuất được tất cả các biên nằm bên trong Closure. Miễn là function còn tồn tại thì các biến bên trong Closure sẽ không bị thu dọn, để cho function có thể truy xuất chúng bất cứ khi nào nó muốn.

Code Closure trong Javascript.

Diễn tả ngôn từ thế đủ rồi, cùng code nào. Cùng xem đoạn code dưới đây.

function sayHello(){
var message = Hello; // define a local variable
console.log(message); // print message, variable name message still in the scope
}
sayHello();
view rawhello.js hosted with ❤ by GitHub

Ta có thể thấy ý đồ là in dòng chữ ‘Hello’ ra console. Bây giờ, hãy tinh chỉnh đoạn code một xíu. Thay vì việc in biến ‘message’ ra console, thì chúng ta trả về một function mà trong function đó sẽ in ra biến ‘message’.

function sayHello(){
var message = Hello; // define a local variable.
return function(){ // return a function from sayHello.
console.log(message); // wanna know if ‘message’ still in scope?
}
}
var helloSayer = sayHello();
helloSayer(); // call the inner function returned from sayHello.
view rawhello.js hosted with ❤ by GitHub

Đầu tiên chúng ta khai báo biến ‘message’ là một biến local trong function ‘sayHello’ và chỉ có thể truy xuất được trong function này. Tiếp đó chúng ta khai báo một function và trả nó về trong ‘sayHello’. Theo kiến thức Javascript thông thường khi chúng ta return từ ham ‘sayHello’, tất cả các biến local bên trong function sẽ bị out of scope và được thu dọn. Vậy nó có xảy ra với biến ‘message’ trong ví dụ trên, để xem nào.

Khi ta gọi function được trả về từ function ‘sayHello’, thật ngạc nhiên, console in ra ‘Hello’, vậy điều kì diệu gì đã làm cho function nằm trong kết quả trả về của ‘sayHello’ có thể truy xuất được biến ‘message’.

Vâng điều kì diệu tôi đang muốn nói tới ở đây chính là Closure.

Trong Javascript, một Closure sẽ chứa function và những biến mà được khai báo trong tầm vực của function như tôi đã nói từ trước. Trong đoạn code ở trên, khi chúng ta khai báo inner function, Javascript sẽ tạo một Closure và cho function đó cũng như tất cả các biến mà function đó truy xuất vào. Vì thế khi chúng ta gọi function được trả về từ ‘sayHello’ nó vẫn có thể truy xuất được dữ liệu của biến ‘message’.

MỘT SỐ BÀI TIẾNG ANH CỰC HAY

  1. https://medium.com/front-end-hacking/callbacks-promises-and-async-await-ad4756e01d90
  2. https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261
  3. https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0
  4. KỸ NĂNG MỀM KHI PHỎNG VẤN : https://medium.com/javascript-scene/master-the-javascript-interview-soft-skills-a8a5fb02c466
  5. https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36

CÁC LINK GỐC TIẾNG VIỆT

[Javascript] Vượt qua các bài phòng vấn Javascript.

2. https://codeaholicguy.com/2016/01/26/tim-hieu-ve-javascript-promise/

3. https://codeaholicguy.com/2015/12/31/javascript-closures/


  • HỌC FULL – STACK JAVASCRIPT TẠI CYBERSOFT ACADEMY – CÓ VIỆC NGAY SAU KHI HỌC -> LINK ĐĂNG KÍ 
  • HỌC FRONT – END CHUYÊN NGHIỆP TẠI CYBERSOFT ACADEMY -> LINK ĐĂNG KÍ 
Bình luận

About CyberSoft Academy

Check Also

Cheat Sheet CSS – Hãy bỏ túi cuốn “Bí Kíp” này !!!

      Đây là những “bí kíp” bỏ túi về CSS, giúp bạn có …