Hướng dẫn local scope javascript - javascript phạm vi cục bộ

Javascript có một vài khái niệm liên quan đến "Scope", không một khái niệm nào trong số chúng là dễ hiểu đối với một new JavaScript developer(JS dev), thậm chí là cả những JS dev đã có kinh nghiệm. Trong bài viết này, tôi sẽ cố gắng giải thích cặn kẽ nhất về các khái niệm liên quan đến Scope trong JS. Bài viết hướng tới những ai muốn tìm hiểu sâu hơn về các từ như là

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
3,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
4,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
6,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
7,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
8,
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
9 and
var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
0. Hi vọng sẽ giúp ích cho các bạn khi muốn giải đáp những câu hỏi:

  • What is Scope?
  • What is Global/Local Scope?
  • What is a Namespace and how does it differ to Scope?
  • What is the this keyword and how does Scope affect it?
  • What is Function/Lexical Scope?
  • What are Closures?
  • What is Public/Private Scope?
  • How can I understand/create/do all of the above?

Trước hết, ta sẽ bắt đầu với những khái niệm cơ bản:

What is Scope?

What is Global/Local Scope?

What is a Namespace and how does it differ to Scope?

What is the this keyword and how does Scope affect it?

// global scope
var name = 'Bap';

What is Function/Lexical Scope?

Hướng dẫn local scope javascript - javascript phạm vi cục bộ
). Bạn thường nghe mọi người than vãn " Global scope thật là tồi tệ ..", nhưng không bao giờ thực sự có lý do tại sao. Thực sự thì Global scope không phải là tồi tệ, bạn cần nó để tạo nên các Modules/ API truy cập thông qua các scopes. Bạn phải sử dụng nó như là lợi thế của mình và không có vấn đề trở ngại nào.

What are Closures?

jQuery('.myClass');

What is Public/Private Scope?

How can I understand/create/do all of the above?

Trước hết, ta sẽ bắt đầu với những khái niệm cơ bản:

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};

Trong JS, scope đề cập đến ngữ cảnh hiện tại trong code của bạn. Scope có thể được xác định trên

var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
1 hoặc
var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
2 . Hiểu về scope trong js là chìa khóa để viết code chống lỗi và trở thành developer tốt hơn. Bạn sẽ hiểu được ở đâu variables/functions có thể được truy cập, có thể thay đổi scope của ngữ cảnh trong code của bạn, nói nôm na là có thể viết code nhanh hơn và dễ maintain hơn, cũng như debug dễ dàng hơn. Suy nghĩ về scope thật dễ dàng, chúng ta đang trong
var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
3 hay
var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
4?

var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);

What is Global Scope?

Trước khi bạn viết một dòng code JS, bạn đang ở nơi mà chúng ta gọi là // Scope A: đây là global scope var myFunction = function () { // Scope B: đây là Local scope }; 8. Nếu chúng ta khai báo một biến, biến đó sẽ được hiểu là biến Global:

Global scope vừa là bạn tốt cũng vừa là cơn ác mộng tồi tệ đối với bạn, bạn sẽ chạy dòng code mà không có vấn đề gì với global scope (thường là đụng độ namespaces ). Bạn thường nghe mọi người than vãn " Global scope thật là tồi tệ ..", nhưng không bao giờ thực sự có lý do tại sao. Thực sự thì Global scope không phải là tồi tệ, bạn cần nó để tạo nên các Modules/ API truy cập thông qua các scopes. Bạn phải sử dụng nó như là lợi thế của mình và không có vấn đề trở ngại nào.

// Scope A
var myFunction = function () {
  // Scope B
  var myOtherFunction = function () {
    // Scope C
  };
};

Nếu bạn đã từng sử dụng JQuery trước đây, và ngay khi bạn làm thế này:

Bạn đang truy cập JQuery ở Global scope, chúng ta có thể tham khảo cách truy cập trong một namespace. Namespace đôi khi là một từ có thể hoán chuyển cho từ "scope", nhưng thường là đề cập đến scope mức cao nhất. Trong trường hợp này, JQuery nằm trong scope global và cũng là namespace của chúng ta. Namespace Jquery được định nghĩa trong global scope, hoạt động như một namespace cho JQuery như mọi thứ bên trong nó sẽ biến thành phần tử con bên trong namespace.

// Scope A
var myFunction = function () {
  // Scope B
  var name = 'Bap'; // định nghĩa trong Scope B
  var myOtherFunction = function () {
    // Scope C: `name` có thể được truy cập tại đây
  };
};

What is Local Scope?

var myFunction = function () {
  var name = 'Bap';
  var myOtherFunction = function () {
    console.log('My name is ' + name);
  };
  console.log(name);
  myOtherFunction(); // call function
  
 //  Log out:
// `Todd`
// `My name is Bap`
};

Local scope đề cập đến bất kỳ scope nào được xác định qua global scope. Có một global scope, và mỗi function định nghĩa bên trong chúng (nested) local scope. Bất cứ function nào được định nghĩa bên trong một function khác đều có local scope được kết nối với function bên ngoài. Nếu tôi định nghĩa một function và tạo các biến bên trong nó, các biến đấy trở thành local scope. Ví dụ:

var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};

Bất kỳ scope items nào cũng đều không tồn tại, hay nói cách khác là không hiểu được ở global scope - trừ khi được truyền ra ngoài, điều đó có nghĩa là nếu tôi định nghĩa một function hoặc một variable trong một scope mới, thì nó không thể được truy cập từ scope bên ngoài scope hiện tại (scope mới được tạo). Một ví dụ đơn giản:

// name = undefined
var scope1 = function () {
  // name = undefined
  var scope2 = function () {
    // name = undefined
    var scope3 = function () {
      var name = 'Bap'; // locally scoped
    };
  };
};

Bạn có thể return một tham chiếu đến biến

var myFunction = function () {
  var name = 'Bap';
  console.log(name); // Todd
};
// Uncaught ReferenceError: name is not defined
console.log(name);
6 chứ không thể là chính nó.

Scope Chain

Scope chain thiết lập cho mỗi scope một function nhất định. Mỗi function lại định nghĩa nested scope riêng như ta đã biết, và mỗi function được định nghĩa trong một function khác đều là local scope được liên kết với function bên ngoài - sự kết nối ấy được gọi là chain. Khi giải quyết một biến, JS bắt đầu với scope bên trong, sau đó tìm kiếm dần mở rộng ra bên ngoài cácbiến/object/function cho đến khi chúng được tìm thấy.

Closures

Closures có mối quan hệ râts chặt chẽ với Lexical scope. Một ví dụ tốt hơn của làm thế nào mọi thứ bên Closure hoạt động. Bạn có thể thấy khi quay lại function reference - một cách sử dụng thực tế hơn. Bên trong một scope, chúng ta có thể truy cập bất cứ gì đã khai báo ở scope cha:

var sayHello = function (name) {
  var text = 'Hello, ' + name;  // scope cha
  return function () {
    console.log(text);  // có thể truy cập từ scope con.
  };
};

Khái niệm closure chúng ta sử dụng ở đây để chỉ scope bên trong mà

// Scope A
var myFunction = function () {
  // Scope B
  var myOtherFunction = function () {
    // Scope C
  };
};
7 không thể truy cập từ scope public. Khi gọi function sẽ không trả về gì:

jQuery('.myClass');
0

kết quả khi gọi

// Scope A
var myFunction = function () {
  // Scope B
  var myOtherFunction = function () {
    // Scope C
  };
};
8 trả về 1 function, điều đó có nghĩa là nó cần được gán:

jQuery('.myClass');
1

Sau một hai lần gán vào biến

// Scope A
var myFunction = function () {
  // Scope B
  var myOtherFunction = function () {
    // Scope C
  };
};
7 và biến
// Scope A
var myFunction = function () {
  // Scope B
  var name = 'Bap'; // định nghĩa trong Scope B
  var myOtherFunction = function () {
    // Scope C: `name` có thể được truy cập tại đây
  };
};
0 thì ta cũng đã gọi được function bên trong. Cho nên ta sẽ gọi bằng cách:

jQuery('.myClass');
2

Scope and this

Mỗi scope sẽ hiểu với một biến

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 khác nhau phụ thuộc vào scope được gọi như thế nào. Có thể bạn đã từng dùng
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 rất nhiều lần, tuy nhiên không chắc bạn đã hiểu hết mỗi
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 khác nhau thế nào khi được gọi. Theo mặc định thì
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 là một biến thuộc global scope, đó là
// Scope A
var myFunction = function () {
  // Scope B
  var name = 'Bap'; // định nghĩa trong Scope B
  var myOtherFunction = function () {
    // Scope C: `name` có thể được truy cập tại đây
  };
};
5. Chúng ta có thể dễ dàng chỉ ra các functions được gọi thế nào theo nhiều cách liên kết khác nhau biến
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 có giá trị khác nhau:

jQuery('.myClass');
3

Cũng có một vài vấn đề ta phải đối mặt khi sử dụng

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5, trong trường hợp nếu tôi sử dụng
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5, thậm chí trong cùng function thì scope cũng có thể thay đổi, và giá trị
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 cũng thay đổi giá trị:

jQuery('.myClass');
4

Bạn có thể thấy

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 trong hai trường hợp, nếu nhìn qua thì có thể nói là "cùng scope", tuy nhiên, kết quả thật sự lại khác. Vậy chuyện gì đã làm thay đổi giá trị của
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5. Chúng ta đã tạo một new scope và nó không được gọi từ event handler của chungs ta, do đó mặc định là
// Scope A
var myFunction = function () {
  // Scope B
  var name = 'Bap'; // định nghĩa trong Scope B
  var myOtherFunction = function () {
    // Scope C: `name` có thể được truy cập tại đây
  };
};
5 Object. Ở đây có một vài điều ta có thể làm nếu muốn truy cập giá trị của
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 phù hợp mà không bị ảnh hưởng bới new scope. Bằng cách gán giá trị của
// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 ở thời điểm nào đó bằng một biến, ở đây tôi dùng
var myFunction = function () {
  var name = 'Bap';
  var myOtherFunction = function () {
    console.log('My name is ' + name);
  };
  console.log(name);
  myOtherFunction(); // call function
  
 //  Log out:
// `Todd`
// `My name is Bap`
};
5:

jQuery('.myClass');
5

Đây là cách có thể bạn đã thấy, bằng cách này, giá trị mang tính "tạm thời" của

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 đã được giải quyết.

Thay đổi scope với bind(), call(), apply()

Đôi khi bạn cần điều khiển các scope phụ thuộc vào những gì bạn đang tìm kiếm. Một ví dụ mô tả:

jQuery('.myClass');
6

Giá trị

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
5 ở đây không đề cập đến các phần tử của chúng ta, nó đang gọi đến object Windown. Để gọi được các element, ta phải thay đổi scope của chúng.

  • var myFunction = function () {
      var name = 'Bap';
      var myOtherFunction = function () {
        console.log('My name is ' + name);
      };
      console.log(name);
      myOtherFunction(); // call function
      
     //  Log out:
    // `Todd`
    // `My name is Bap`
    };
    
    8 and
    var myFunction = function () {
      var name = 'Bap';
      var myOtherFunction = function () {
        console.log('My name is ' + name);
      };
      console.log(name);
      myOtherFunction(); // call function
      
     //  Log out:
    // `Todd`
    // `My name is Bap`
    };
    
    9
    var name = 'Bap';
    var scope1 = function () {
      // name is available here
      var scope2 = function () {
        // name is available here too
        var scope3 = function () {
          // name is also available here!
        };
      };
    };
    
    0 và
    var name = 'Bap';
    var scope1 = function () {
      // name is available here
      var scope2 = function () {
        // name is available here too
        var scope3 = function () {
          // name is also available here!
        };
      };
    };
    
    1 cho phép chúng ta truyền một scope vào trong một function mà ràng buộc đúng giá trị
    // Scope A: đây là global scope 
    var myFunction = function () {
      // Scope B: đây là Local scope
    };
    
    5 này. Hãy vận dụng function bên trên để tạo biến
    // Scope A: đây là global scope 
    var myFunction = function () {
      // Scope B: đây là Local scope
    };
    
    5 của chúng ta:
jQuery('.myClass');
7

cách sử dụng

var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
0 và
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
1 khá giống nhau, tuy nhiên có một điểm khác đó là: các tham số truyền vào cho hàm
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
0 là từng biến riêng lẻ, còn đối với
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
1 thì ta có thể truyền theo mảng:
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
8,
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
9.

Điều quan trọng cần phải nhớ khi sử dụng

var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
0 và
var name = 'Bap';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};
1 đó là nó đã thực sự gọi function của bạn, thay cho câu lệnh goị function:

jQuery('.myClass');
8

Bạn sẽ để

var myFunction = function () {
  var name = 'Bap';
  var myOtherFunction = function () {
    console.log('My name is ' + name);
  };
  console.log(name);
  myOtherFunction(); // call function
  
 //  Log out:
// `Todd`
// `My name is Bap`
};
8 xử lý nó và chuỗi các method:

jQuery('.myClass');
9

.bind()

khi dùng

// name = undefined
var scope1 = function () {
  // name = undefined
  var scope2 = function () {
    // name = undefined
    var scope3 = function () {
      var name = 'Bap'; // locally scoped
    };
  };
};
3 sẽ không gọi (invoke) function của bạn, và nó cũng có tác dụng truyền vào các đối số. Như ví dụ dưới đây:

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
0

Ta có thể sửa lại để function không bị gọi ngay taị thời thời điểm nó được định nghĩa:

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
1

Nhưng với sự thay đổi như trên, thì ta lại tạo ra một function thực sự không cần thiết, điều này sẽ thực sự kém về performance nếu chúng ta đang ở trong một vòng lặp mà các sự kiện listener đang được ràng buộc. Để giải quyết thì ta sẽ vận dụng

// name = undefined
var scope1 = function () {
  // name = undefined
  var scope2 = function () {
    // name = undefined
    var scope3 = function () {
      var name = 'Bap'; // locally scoped
    };
  };
};
4:

// Scope A: đây là global scope 
var myFunction = function () {
  // Scope B: đây là Local scope
};
2

Bằng cách này, function sẽ không bị gọi ngay, các scopes cũng được thay đổi nếu cần, tuy nhiên, các đối số lại phải chờ để được duyệt đến.

Bài tham khảo: Javascipt scope