Scope in javascript - 66 khái niệm cần hiểu khi học lập trình javascript

Nội dung bài viết

Scope in javascript. Đó là một khái niệm mà tôi không nghĩ những lập trình viên mới làm quen thì phạm vi trong javascript không hề dễ một chút nào? Và trước khi học những khái niệm như closure thì vì sao bạn phải học về scope trong javascript. Bài viết này sẽ cố gắng hết sức để giải thích phạm vi và chuỗi phạm vi một cách đơn giản nhất. Tips javascript hy vọng bạn có thể tiếp thu được cái gì đó trong những ví dụ cụ thể này.


Scope trong javascript là gì?


Hẳn là các bạn còn nhờ tôi đã nói rằng trước khi tìm hiểu closure là gì? Thì các bạn nên tìm hiểu về phạm vi trong javascript. Bởi vì khi bạn thực sự hiểu về scope javascript thì bạn mới có thể hiểu về những khái niệm khác nhanh nhất có thể. Thật ra, tôi cũng có tham khảo một số bài viết về Scope, thế nhưng tôi không hề hài lòng với cách lập luận và giải thích của họ. Hoặc có thể họ đi copy ở đâu đó mà thực sự không hiểu? Thứ hai, vì sao các bạn cần phải hiểu, đó chính là nó liên quan rất nhiều đến 66 khái niệm javascript mà ở bài viết 33 khái niệm cần phải học còn chưa nêu ra. 


Tiếp theo đó là có nhiều bạn đã nói rằng "Em học javascript xong rồi, bây giờ em muốn học back-end thì làm sao?" .Ồ không, nếu như bạn nói vậy thì e rằng, bạn chưa hiểu gì về ngôn ngữ lập trình javascript. Bạn đừng tự ái, ngay cả bản thân những chuyên gia, họ còn cảm thấy nó khỏ hiểu, chính vì vậy họ luôn tìm ra những phương án mới và nâng cấp từ từ từ ES6 đến ES12, đó là một ví dụ. Đây là một lời khuyên chân thành. Nên học mãi và tìm hiểu tiếp. 


Trước khi đi vào định nghĩa thì tôi với các bạn sẽ tìm hiểu trước, khi mình khai báo biến thì sự hình thành của biến đó như thế nào? Để có một sự giải thích dễ nhất và các bạn mới làm quen. Ngoài ra còn có một khái niệm nữa rất quan trọng nên tìm hiểu đó là "lexical scope là gì?"


Sự ra đời của một biến trong javascript


Đầu tiên một ví dụ gọn nhẹ:

var nameBlog = 'anonystick.com';

Nếu như bạn là một dev bình thường or mới làm quen với lập trình thì nhình vào chúng ta nghĩ rằng đó là một câu lệnh khai báo biến. Nó đúng với suy nghĩ ấy, không sai nhưng đối với một lập trình viên lão làng thì họ lại hiểu khác đấy. Đó là một quá trình biên dịch, được chia thành hai phần sau: 


1 - Khi gặp phải var nameBlog thì trình biên dịch sẽ hỏi rằng xem phạm vi biến có tên này đã tồn tại trong tập hợp cùng phạm vi hay chưa? Có hai trường hợp ở giai đoạn này, đó là nếu chưa tồn tại thì trình biên dịch sẽ bỏ qua phần khai báo và tiếp tục biên dịch. Ngược lại nếu đã tồn tại thì nó sẽ yêu cầu phạm vi khai báo một biến mới trong tập hợp của phạm vi hiện tại. Và có khi nó đặt lại tên mới luôn (ở chế độ "use strict"). 


2 - Tiến trình này gọi là biên dịch, đừng nghĩ javascript không có biên dịch. Đầu tiên nó sẽ hỏi công cụ xác định phạm vi đang chạy liệu có phạm vi được gọi là tập hợp các biến nameBlog hiện tại hay không. Nếu đúng, javascript engine sẽ sử dụng biến này, ngược lại, engine này sẽ tiếp tục tìm biến. Để chứng minh nhận định trên thì theo dõi code sau :

console.log(nameBlog); // undefined
var nameBlog = 'anonystick.com';

Như đã nói ở trên, từ cốt lõi của bài viết này về scope. Vậy scope trong javascript là gì? Và có bao nhiêu loại scope in javascript. Cùng tìm hiểu và chém tiếp.


Phạm vi trong javascript là gì?


Vân như cũ thay vì đọc thì đi review một code xem sao? 

# Ví dụ 1:

function getBlog() {
    var nameBlog = "anonystick.com";
}
getBlog(); //Bạn phải thực hiện chức năng này trước, nếu không bạn sẽ không biết nó là gì
console.log(nameBlog); // Uncaught ReferenceError: nameBlog is not defined

Từ ví dụ trên, bạn có thể dần dần hiểu khái niệm về phạm vi, biến nameBlog không được khai báo trong phạm vi toàn cục nên sẽ báo lỗi khi giá trị được lấy trong phạm vi toàn cục. Dừng, chưa vội kết luận định ngĩa của phạm vi, nhưng trong đầu bạn đã gật gù rồi. Tiếp xem một code nữa hêy 

Xem code này trước đi 

# Ví dụ 2

function fun() {
  var name = 'anonystick.com';
   console.log(name); 
}
fun();// "anonystick.com"

Khi fun() được thực thi, xuất một biến name, sau đó biến name này đến từ đâu? Chúng ta thấy dòng đầu tiên có một hàm của biến name xác định từ câu lệnh var name = 'anonystick.com'; Chính xác là nó lấy từ đó. 

Tiếp xem một mã nữa?

 # Ví dụ 3

var name2 = 'anonystick.com';
function fun() {
   console.log(name2);
}
fun(); // anonystick.com

Không cao siêu gì ở đây, vâng nó chả cao siêu bạn nào hiểu hết javascript thì thôi :D. Thay vì mình khai báo biến name2 trong function thì minh khai báo nó ở ngoài. Nhưng nó tìm ở trong không được, thì nó tự đi tìm bên ngoài thôi. Bạn có thể nhận thấy rằng ba đoạn mã trên có các biến để chúng ta đi tìm kiếm. ở ví dụ 1 thì tìm ko ra, lỗi. Ví dụ 2 tìm được trong hàm, và ví dụ 3 chúng ta tìm được ở toàn cục. bây giờ bạn quay lại những từ in đậm và gạch chân để chuẩn bị đi vào định nghĩa của phạm vi. 


Scope trong javascript là Phạm vi là khu vực nơi các biến được xác định. Nó có một tập hợp các quy tắc để truy cập các biến. Tập hợp các quy tắc này được sử dụng để quản lý cách công cụ trình duyệt tìm kiếm các biến dựa trên các biến trong phạm vi hiện tại và các phạm vi lồng nhau. 


Hay cách khác: Phạm vi trong javascript là một lãnh thổ độc lập, do đó các biến sẽ không bị rò rỉ hoặc lộ ra ngoài . Có nghĩa là, phạm vi sử dụng lớn nhất là để cô lập các biến. Các biến có cùng tên trong các phạm vi khác nhau sẽ không xung đột.


Có bao nhiêu scope trong javascript cần hiểu


Trước tiên học về javascript thì cần hiểu rằng trước ES6, JavaScript không có phạm vi cấp khối (block scope), chỉ có phạm vi toàn cục và phạm vi chức năng. Sự xuất hiện của ES6 cung cấp cho chúng ta một 'phạm vi khối', có thể được phản ánh bằng cách thêm các lệnh let và const mà trước đó chúng tôi đã giải thích. Có một loại mà chũng ta cần quan tâm đó "Lexical scope là gì?" Vì sao chúng ta cần quan tâm và Scope chain là gì? 

Mời các bạn theo dõi tiếp phần cập nhật của bài viết này or phần tiếp theo.


Câu hỏi cho bạn

var a = 1
function fn1(){  
  function fn2(){
    console.log(a)
  }
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2   
  return fn3   
}
var fn = fn1() 
fn() // Kết quả là gì?

Gợi ý: Đi từ phạm vi có nghĩa là là trong ra ngoài, dưới lên trên :D ... Xin chào và hẹn gặp lại... "lexical scope là gì?"

Có thể bạn đã bị missing