Tìm hiểu sâu hơn về scope Javascript (Phần 2)

Ở phần tìm hiểu về scope JS trước, tôi đã giới thiệu đến các bạn về các khái niệm về Scope, function scope, Lexical scope, Scope chain, Closures ... Hôm nay, tôi sẽ bình bày nốt phần còn lại của Scope trong Javascript.

Private and Public Scope

Trong rất nhiều các ngôn ngữ lập trình, bạn sẽ nghe đến public and privatescope, trong Javascript không có điều đó. Tuy nhiên, chúng ta có thể bắt chước public and private scope giống như closures. Bằng cách sử dụng Javascript design patterns, giống như ví dụ pattern Module , chúng ta có thể tạo được public and private scope. Một cách đơn giản để tạo private scope là wrapping các functions của chúng ta bên trong một function. Như chúng ta đã biết (Phần trước) function taọ nên scope, giữ mọi thứ từ global scope:

(function () {
  // private scope ở đây
})();

Chúng ta có thể add một số functions bên trong function ban đầu của chúng ta:

(function () {
  var myFunction = function () {
    // code thứ gì đó ở đây
  };
})();

Nhưng ta không thể gọi đến myFunction():

myFunction(); // Uncaught ReferenceError: myFunction is not defined

Xong! Ta vừa tạo được private scope đấy. Nhưng nếu ta muốn function được public? Dưới đây là Module Pattern, nó cho phép chúng ta định nghĩa scope của function một cách chính xác, sử dụng public và private scope với một Object. Ở đây, tôi lấy global namespace, gọi là Module, chứa tất cả code liên quan đến module đó:

// định nghĩa module
var Module = (function () {
  return {
    myMethod: function () {
      console.log('myMethod has been called.');
    }
  };
})();

// call module + methods
Module.myMethod();

return ở đoạn code trên chính là trả về các methods public, là các methods có thể truy cập được từ global scope - ở đây là namespaced. Điều đó có nghĩa là Module quan tâm đến namespace của chúng ta, và có thể chứa nhiều hơn một methods nếu chúng ta muốn. Chúng ta có thể extend Module nếu thích:

// định nghĩa module
var Module = (function () {
  return {
    myMethod: function () {

    },
    someOtherMethod: function () {

    }
  };
})();

// call module + methods
Module.myMethod();
Module.someOtherMethod();

Thế còn về private method? Đây là điểm mà rất nhiều các developers bị nhầm lẫn hoặc làm cho global scope rối tung lên bằng cách cho tất cả vào global scope. Các functions giúp code hoạt động không cần nằm trong global scope. Chỉ cần API gọi do - things những thứ cần truy cập và sắp xếp thứ tự hoạt động của chúng. Dưới đây, tôi sẽ tạo một private scope, không phải return function:

var Module = (function () {
  var privateMethod = function () {

  };
  return {
    publicMethod: function () {

    }
  };
})();

Điều đó có nghĩa là publicMethod có thể gọi được(từ global scope) còn privateMethod thì không, đây chính là private scope. Private scope mà chúng ta thường gặp như là helper, addClass, removeClass, Ajax/XHR calls, Arrays, Objects...

Mặc dù đây là suy nghĩ thú vị, bất cứ gì trong cùng một scope có thể truy cập đến bất cứ thứ gì khác trong scope đó, ngay cả sau khi function được return. Điều đó có nghĩa là public method có thể truy cập được đến private method, và chúng (private method) vấn có thể tương tác được đến, nhưng không thể được truy cập từ global scope.

var Module = (function () {
  var privateMethod = function () {
     console.log('private is doing');
  };
  return {
    publicMethod: function () {
      // có thể truy cập đến `privateMethod`, chúng ta có thể gọi hàm:
      // privateMethod();
    }
  };
})();

Điều này cho phép tương tác rất mạnh, cũng như bảo mật code. Một phần rất quan trọng của JS là đảm bảo bảo mật, đó chính là lí do tại sao chúng ta không đưa tất cả functions ra global scope, như vậy chúng sẽ public, điều đó đồng nghĩa với dễ dàng bị tấn công. Dưới đây là một ví dụ trả về một Object, sử dụng các methods publicprivate:

var Module = (function () {
  var myModule = {};
  var privateMethod = function () {

  };
  myModule.publicMethod = function () {

  };
  myModule.anotherPublicMethod = function () {

  };
  return myModule; // trả về Object với public methods
})();

// usage
Module.publicMethod();

Một quy ước đặt tên gọn gàng bằng cách đặt một dấu gạch dưới _ trước tên của method, một cách trực quan giúp bạn phân biệt giữa privatepublic:

var Module = (function () {
 var _privateMethod = function () {

 };
 var publicMethod = function () {

 };
})();

Điều này giúp ta khi trả về một anonymous Object, những object mà Module có thể sử dụng và chúng ta có thể dễ dàng assign tham chiếu hàm (function references):

var Module = (function () {
  var _privateMethod = function () {

  };
  var publicMethod = function () {

  };
  return {
    publicMethod: publicMethod,
    anotherPublicMethod: anotherPublicMethod
  }
})();

Cám ơn các bạn đã theo dõi bài viết! Happy coding!

Tài liệu tham khảo: Javascript scope