+4

Tìm hiểu Variable Scope và Hoisting JavaScript

1. Hoisting là gì?

Hoisting là khái niệm chỉ việc mọi khai báo biến (với từ khóa var) sẽ được chuyển lên trên cùng của hàm. Để chứng minh chúng ta sẽ thực hiện những ví dụ dưới đây: Ta có 1 function như sau:

(function(){
    console.log(x);
 })();

kết quả trả về là lỗi, điều này là đương nhiên vì function đâu hiểu x là gì, vậy thì viết như sau thì sao:

(function(){
      console.log(x);
      var x = ''abc"
   })();

kết quả trả về là undifined. Tại sao lại là undifined mà không phải là lỗi như trên, theo như ta hiểu thông thường thì console cũng không thể hiểu đc x là gì.

Nhưng thực tế, đoạn code trên sẽ chuyển thành như sau:

(function(){
    var x;
    console.log(x);
    x = "abc";
})();

Như vậy việc khai báo biến x đã được chuyển lên đầu hàm, nhưng giá trị của nó thì vẫn được khai báo ở vị trí cũ.

2. Scope

2.1. Khái niệm

Một tính chất quan trọng của hàm là biến được tạo ra bên trong hàm, kể cả các parameters, là biến cục bộ của hàm. scope là nơi mà biến hoặc hàm có thể truy cập vào và sử dụng/ tham chiếu được qua tên trực tiếp. Và ở ngoài scope đó thì biến hoặc hàm đó sẽ không thể nhìn được một cách trực tiếp nữa.

  • Ở dưới đây mình có liệt kê ra một số loại scope và cách dùng của từng loại như sau

2.2 Phân loại và chức năng từng loại

2.2.1 A globally-scoped variable

var x = 1;

// global scope
function one() {
  alert(x); // alerts '1'
}

điều này thấy là function f có thể hiểu được biến global x ở ngoài để trả về giá trị 1

2.2.2 Local scope

var a = 1;
function two(a) {
  alert(a); // alerts the given argument, not the global value of '1'
}
// local scope again
function three() {
  var a = 3;
  alert(a); // alerts '3'
}

Tạ hiểu rằng function two(a) {} và function two() { var a; } trả về kết quả hoàn toàn giống nhau, nhưng đối với function two thì ta mới chỉ khai báo biến a nhưng chưa set giá trị cho nó dẫn đến kết qủa trả về là undifined. Một câu hỏi đặt ra là tại sao function two, three lại không hiểu giá trị biến global a ở bên ngoài là 1? Là bởi vì: Hàm two, three đã tạo ra biến x mới và biến x này chỉ có giá trị bên trong thân hàm và do đó chỉ thay đổi biến x được tạo ra trong thân hàm.

2.2.3 Intermediate: No such thing as block scope in JavaScript (ES5; ES6 introduces let)

Có một ví dụ rất hay về việc sử dụng let thay về var để khai báo biến trong javascript như sau:

  • Sử dụng var
function four() {
   var x = 1;
   if (true) {
      var x = 2; // x ở đây cũng là x ở trên
      console.log(x); // in ra 2
   }
   console.log(x); // vẫn là 2
}
  • Sử dụng let:
function four() {
   let x = 1;
   if (true) {
      let x = 2; // x này là x khác rồi đấy
      console.log(x); // in ra 2
   }
   console.log(x); // in ra 1
}

Tại sao khi gọi x ở global tức là không trong function nào cả thì giá trị trả về 10, tại sao không phải là 20 (như những gì ta đã làm ở trên)? Cái này là bởi vì let thì tạo một biến chỉ có thể truy cập được trong block bao quanh nó, còn var thì tạo ra một biến có phạm vi global, xuyên suốt trong tất cả các function chứa nó.

2.2.4 Intermediate: Object properties

var a = 1;

function five() {
  this.a = 2;
  this.b = 3;
}

alert(new five().a); // alerts '2'
alert(new five().b); // alerts '3'

five() lúc này đóng vai trò là một object có các phần tử {a: 2, b: 3}

2.2.5 hoisting và scope

Như ví dụ hoisting ở trên và khái niệm scope thì theo các bạn kết quả trả về ở đây là gì?

var x = 5;
(function () {
    console.log(x);
    var x = 10;
    console.log(x);
    })();

đáp án là: undifined và 10 đơn giản cách viết trên sẽ được hiểu là:

var x = 5;
(function () {
    var x;
    console.log(x);
    x = 10;
    console.log(x);
    })();

và đó là lý do vì sao chúng ta có đáp án như vậy

3. Kết Luận

Scope, hoisting được sử dụng rất nhiều khi lập trình bằng ngôn ngữ javascript. Qua bài viết, chúng ta có thể nắm được một số khái niệm và cách dùng cơ bản về chúng. Để tìm hiểu chi tiết hơn, bạn có thể tham khảo ở những tài liệu: https://daynhauhoc.com/t/function-in-javascript-part-2-scope-and-nested-scope/14819 http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí