Phạm vi đối tượng ECMAScript

Phạm vi là phạm vi áp dụng của biến.

Phạm vi công khai, riêng tư và bảo vệ

Khái niệm

Trong thiết kế chương trình hướng đối tượng truyền thống, chủ yếu tập trung vào phạm vi công khai và riêng tư. Các thuộc tính của đối tượng trong phạm vi công khai có thể được truy cập từ bên ngoài đối tượng, tức là sau khi nhà phát triển tạo ra bản sao của đối tượng, họ có thể sử dụng các thuộc tính công khai của nó. Các thuộc tính trong phạm vi riêng tư chỉ có thể được truy cập trong đối tượng, tức là đối với thế giới bên ngoài, các thuộc tính này không tồn tại. Điều này có nghĩa là nếu lớp định nghĩa các thuộc tính và phương thức riêng tư, thì các lớp con của nó cũng không thể truy cập các thuộc tính và phương thức này.

Phạm vi bảo vệ cũng được sử dụng để định nghĩa các thuộc tính và phương thức riêng tư, nhưng các thuộc tính và phương thức này vẫn có thể được truy cập bởi các lớp con.

ECMAScript chỉ có phạm vi công khai

Đề cập đến phạm vi của ECMAScript gần như không có ý nghĩa, vì trong ECMAScript chỉ có một phạm vi - phạm vi công khai. Tất cả các thuộc tính và phương thức của tất cả các đối tượng trong ECMAScript đều là công khai. Do đó, khi định nghĩa lớp và đối tượng của riêng mình, bạn cần phải hết sức cẩn thận. Hãy nhớ rằng, tất cả các thuộc tính và phương thức đều là công khai theo mặc định!

Giải pháp đề xuất

Nhiều nhà phát triển đã đề xuất các mẫu phạm vi thuộc tính hiệu quả trên mạng, giải quyết vấn đề này của ECMAScript.

Do thiếu phạm vi riêng tư, các nhà phát triển đã xác định một quy ước để xác định哪些 thuộc tính và phương thức nên được coi là riêng tư. Quy ước này quy định rằng thêm dấu gạch dưới trước và sau thuộc tính:

obj._color_ = "blue";

Trong đoạn mã này, thuộc tính color là riêng tư. Lưu ý, dấu gạch dưới không thay đổi thực tế rằng thuộc tính là thuộc tính công khai, nó chỉ thông báo cho các nhà phát triển khác rằng họ nên coi thuộc tính này là riêng tư.

Một số nhà phát triển còn thích sử dụng dấu gạch dưới để chỉ ra thành viên riêng tư, ví dụ: obj._color。

Khung truy cập tĩnh

Các thuộc tính và phương thức được định nghĩa trong khung truy cập tĩnh có thể được truy cập từ cùng một vị trí bất kỳ. Trong Java, lớp có thể có thuộc tính và phương thức mà không cần phải tạo đối tượng của lớp đó, ví dụ java.net.URLEncoder lớp, hàm encode() của nó là phương thức tĩnh.

ECMAScript không có khung truy cập tĩnh

Nghiêm ngặt hơn, ECMAScript không có khung truy cập tĩnh. Tuy nhiên, nó có thể cung cấp thuộc tính và phương thức cho hàm xây dựng. Bạn còn nhớ không, hàm xây dựng chỉ là hàm. Hàm là đối tượng, đối tượng có thể có thuộc tính và phương thức. Ví dụ:

function sayHello() {
  alert("hello");
}
sayHello.alternate = function() {
  alert("hi");
}
sayHello();            // Hiển thị "hello"
sayHello.alternate();    // Hiển thị "hi"

Thử ngay

Ở đây, phương thức alternate() thực chất là phương thức của hàm sayHello. Bạn có thể gọi hàm sayHello() như một hàm thông thường để hiển thị "hello", hoặc gọi sayHello.alternate() để hiển thị "hi". Mặc dù vậy, alternate() vẫn là phương thức trong khung truy cập công cộng của sayHello() chứ không phải là phương thức tĩnh.

Từ khóa this

Chức năng của this

Một trong những khái niệm quan trọng nhất cần phải hiểu trong ECMAScript là cách sử dụng từ khóa this, nó được sử dụng trong các phương thức của đối tượng. Từ khóa this luôn chỉ vào đối tượng gọi phương thức đó, ví dụ:

var oCar = new Object;
oCar.color = "red";
oCar.showColor = function() {
  alert(this.color);
};
oCar.showColor();        // Hiển thị "red"

Thử ngay

Trong đoạn mã trên, từ khóa this được sử dụng trong phương thức showColor() của đối tượng. Trong môi trường này, this bằng oCar. Mã dưới đây có cùng chức năng với mã trên:

var oCar = new Object;
oCar.color = "red";
oCar.showColor = function() {
  alert(oCar.color);
};
oCar.showColor();        // Hiển thị "red"

Thử ngay

Lý do sử dụng this

Tại sao sử dụng this vậy? Bởi vì khi tạo đối tượng, chúng ta luôn không thể chắc chắn rằng nhà phát triển sẽ sử dụng tên biến gì. Sử dụng this, bạn có thể tái sử dụng cùng một hàm ở nhiều nơi khác nhau. Hãy suy nghĩ về ví dụ sau đây:

function showColor() {
  alert(this.color);
};
var oCar1 = new Object;
oCar1.color = "red";
oCar1.showColor = showColor;
var oCar2 = new Object;
oCar2.color = "blue";
oCar2.showColor = showColor;
oCar1.showColor();		//Đầu ra "red"
oCar2.showColor();		//Đầu ra "blue"

Thử ngay

Trong mã trên, trước tiên định nghĩa hàm showColor() bằng từ khóa this, sau đó tạo hai đối tượng (oCar1 và oCar2), một đối tượng có thuộc tính color được đặt là "red", đối tượng còn lại có thuộc tính color được đặt là "blue". Cả hai đối tượng đều được gán thuộc tính showColor, chỉ đến hàm showColor () gốc (lưu ý rằng không có vấn đề về tên ở đây, vì một trong số đó là hàm toàn cục, còn một là thuộc tính của đối tượng). Gọi phương thức showColor() của mỗi đối tượng, đầu ra của oCar1 là "red", còn đầu ra của oCar2 là "blue". Đó là vì khi gọi oCar1.showColor(), từ khóa this trong hàm bằng oCar1. Khi gọi oCar2.showColor(), từ khóa this trong hàm bằng oCar2.

Lưu ý, khi tham chiếu thuộc tính của đối tượng, bạn phải sử dụng từ khóa this. Ví dụ, nếu sử dụng mã dưới đây, phương thức showColor() không thể chạy:

function showColor() {
  alert(color);
};

Nếu không sử dụng đối tượng hoặc từ khóa this để tham chiếu biến, ECMAScript sẽ coi nó là biến cục bộ hoặc biến toàn cục. Sau đó, hàm sẽ tìm kiếm biến cục bộ hoặc biến toàn cục có tên là color, nhưng sẽ không tìm thấy. Kết quả là gì? Hàm sẽ hiển thị "null" trong cảnh báo.