Hướng dẫn cơ bản về Getters và Setters trong JavaScript
Getters và setters là các hàm hoặc phương thức được sử dụng để được và bộ các giá trị của biến. Khái niệm getter-setter là phổ biến trong lập trình máy tính: hầu như tất cả các ngôn ngữ lập trình cấp cao đều đi kèm với một tập hợp cú pháp để triển khai getters và setters, bao gồm JavaScipt.
Trong bài đăng này, chúng tôi sẽ xem setters getters là gì và làm thế nào để tạo và sử dụng chúng trong JavaScript.
Getters-setters và đóng gói
Ý tưởng về getters và setters luôn được đề cập kết hợp với đóng gói. Đóng gói có thể được hiểu theo hai cách.
Thứ nhất, đó là việc thiết lập dữ liệu-getters-setters bộ ba để truy cập và sửa đổi dữ liệu đó. Định nghĩa này hữu ích khi một số hoạt động, chẳng hạn như xác nhận, phải thực hiện trên dữ liệu trước khi lưu hoặc xem nó - getters và setters cung cấp ngôi nhà hoàn hảo cho nó.
Thứ hai, có một định nghĩa chặt chẽ hơn theo đó đóng gói được thực hiện để ẩn dữ liệu, để làm cho nó không thể truy cập từ mã khác, ngoại trừ thông qua các getters và setters. Bằng cách này, chúng tôi không kết thúc vô tình ghi đè dữ liệu quan trọng với một số mã khác trong chương trình.
Tạo getters và setters
1. Với phương pháp
Vì getters và setters là về cơ bản là các chức năng tìm nạp / thay đổi một giá trị, có nhiều hơn một cách để tạo và sử dụng chúng. Cách đầu tiên là:
var obj = foo: 'đây là giá trị của foo', getFoo: function () return this.foo; , setFoo: function (val) this.foo = val; console.log (obj.getFoo ()); // "đây là giá trị của foo" obj.setFoo ('xin chào'); console.log (obj.getFoo ()); // "xin chào"
Đây là cách đơn giản nhất để tạo ra getters và setters. Có một tài sản foo
và có hai phương pháp: có được
và setFoo
đến trả lại và gán một giá trị đến tài sản đó.
2. Với các từ khóa
Thêm “chính thức” và cách mạnh mẽ để tạo ra getters và setters là bằng cách sử dụng được
và bộ
từ khóa.
Đến tạo ra một getter, đặt được
từ khóa ở phía trước một khai báo hàm sẽ đóng vai trò là phương thức getter và sử dụng bộ
từ khóa theo cùng một cách để tạo một setter. Cú pháp như sau:
var obj = fooVal: 'đây là giá trị của foo', get foo () return this.fooVal; , đặt foo (val) this.fooVal = val; console.log (obj.foo); // "đây là giá trị của foo" obj.foo = 'xin chào'; console.log (obj.foo); // "xin chào"
Lưu ý rằng dữ liệu chỉ có thể là được lưu trữ dưới tên tài sản (fooVal
) đó là khác nhau từ tên của các phương thức getter-setter (foo
) bởi vì một thuộc tính giữ getter-setter không thể giữ dữ liệu cũng.
Cách nào tốt hơn?
Nếu bạn chọn tạo getters và setters với từ khóa, bạn có thể sử dụng toán tử gán để thiết lập dữ liệu và toán tử chấm để lấy dữ liệu, giống như cách bạn truy cập / đặt giá trị của một tài sản thông thường.
Tuy nhiên, nếu bạn chọn cách đầu tiên của mã hóa getters và setters, bạn phải gọi các phương thức setter và getter sử dụng cú pháp gọi hàm bởi vì chúng là các hàm điển hình (không có gì đặc biệt như các hàm được tạo bằng được
và bộ
từ khóa).
Ngoài ra, có khả năng bạn sẽ vô tình kết thúc gán một số giá trị khác đến các thuộc tính giữ các phương thức getter-setter đó và mất chúng hoàn toàn! Một cái gì đó bạn không phải lo lắng trong phương pháp sau.
Vì vậy, bạn có thể thấy lý do tại sao tôi nói kỹ thuật thứ hai mạnh mẽ hơn.
Ghi đè phòng ngừa
Nếu vì lý do nào đó bạn thích kỹ thuật đầu tiên, hãy tạo các thuộc tính giữ các phương thức getter-setter chỉ đọc bằng cách tạo ra chúng sử dụng Object.defineProperies
. Thuộc tính được tạo thông qua Object.defineProperies
, Object.defineProperty
và Reflect.defineProperty
tự động cấu hình đến có thể ghi: sai
nghĩa là chỉ đọc:
/ * Ngăn chặn ghi đè * / var obj = foo: 'đây là giá trị của foo'; Object.defineProperIES (obj, 'getFoo': value: function () return this.foo;, 'setFoo': value: function (val) this.foo = val;); obj.getFoo = 66; // getFoo sẽ không bị ghi đè! console.log (obj.getFoo ()); // "đây là giá trị của foo"
Hoạt động bên trong getters và setters
Khi bạn đã giới thiệu getters và setters, bạn có thể tiếp tục và thực hiện các thao tác trên dữ liệu trước khi thay đổi hoặc trả lại.
Trong đoạn mã dưới đây, trong hàm getter, dữ liệu là nối với một chuỗi trước khi được trả về và trong hàm setter, xác nhận giá trị có phải là số hay không được thực hiện trước khi cập nhật n
.
var obj = n: 67, get id () return 'ID là:' + this.n; , đặt id (val) if (typeof val === 'number') this.n = val; console.log (obj.id); // "ID là: 67" obj.id = 893; console.log (obj.id); // "ID là: 893" obj.id = 'xin chào'; console.log (obj.id); // "ID là: 893"
Bảo vệ dữ liệu với getters và setters
Cho đến nay, chúng tôi đã đề cập đến việc sử dụng getters và setters trong bối cảnh đầu tiên của đóng gói. Hãy chuyển sang phần thứ hai, tức là làm thế nào để ẩn dữ liệu từ mã bên ngoài với sự giúp đỡ của getters và setters.
Dữ liệu không được bảo vệ
Việc thiết lập getters và setters không có nghĩa là dữ liệu chỉ có thể được truy cập và thay đổi thông qua các phương thức đó. Trong ví dụ sau, nó thay đổi trực tiếp không chạm vào các phương thức getter và setter:
var obj = fooVal: 'đây là giá trị của foo', get foo () return this.fooVal; , đặt foo (val) this.fooVal = val; obj.fooVal = 'xin chào'; console.log (obj.foo); // "xin chào"
Chúng tôi đã không sử dụng setter nhưng trực tiếp thay đổi dữ liệu (fooVal
). Dữ liệu ban đầu chúng tôi đặt bên trong obj
đã biến mất Để ngăn chặn điều này xảy ra (vô tình), bạn cần một số bảo vệ cho dữ liệu của bạn. Bạn có thể thêm nó bằng cách giới hạn phạm vi nơi dữ liệu của bạn có sẵn. Bạn có thể làm điều đó bằng một trong hai khối phạm vi hoặc là chức năng phạm vi.
1. Phạm vi khối
Một cách là sử dụng phạm vi khối bên trong đó dữ liệu sẽ được xác định bằng cách sử dụng để cho
từ khóa nào giới hạn phạm vi của nó đến khối đó.
Một phạm vi khối có thể được tạo bằng cách đặt mã của bạn bên trong một cặp niềng răng xoăn. Bất cứ khi nào bạn tạo một phạm vi khối, hãy đảm bảo để lại một bình luận ở trên nó yêu cầu niềng răng để lại một mình, để không ai tháo niềng răng do nhầm lẫn, họ là một số dấu ngoặc thừa trong mã hoặc thêm một nhãn đến phạm vi khối.
/ * BLOCK PHẠM VI, để yên niềng răng! * / let fooVal = 'đây là giá trị của foo'; var obj = get foo () return fooVal; , đặt foo (val) fooVal = val fooVal = 'xin chào'; // sẽ không ảnh hưởng đến fooVal bên trong khối console.log (obj.foo); // "đây là giá trị của foo"
Thay đổi / tạo fooVal
ngoài khối sẽ không ảnh hưởng các fooVal
được đề cập bên trong setters getters.
2. Phạm vi chức năng
Cách phổ biến hơn để bảo vệ dữ liệu với phạm vi là giữ dữ liệu bên trong một chức năng và trả lại một đối tượng với các getters và setters từ chức năng đó.
hàm myobj () var fooVal = 'đây là giá trị của foo'; return get foo () return fooVal; , đặt foo (val) fooVal = val fooVal = 'xin chào'; // sẽ không ảnh hưởng đến fooVal var obj = myobj (); console.log (obj.foo); // "đây là giá trị của foo"
Đối tượng (với foo ()
getter-setter bên trong nó) được trả về bởi myobj ()
chức năng là lưu trong obj
, và sau đó obj
đã từng gọi getter và setter.
3. Bảo vệ dữ liệu mà không có phạm vi
Ngoài ra còn có một cách khác để bạn có thể bảo vệ dữ liệu của mình khỏi bị ghi đè mà không giới hạn phạm vi của nó. Logic đằng sau nó diễn ra như sau: làm thế nào bạn có thể thay đổi một phần dữ liệu nếu bạn không biết cái gì được gọi là?
Nếu dữ liệu có một tên biến / thuộc tính không dễ tái sản xuất, rất có thể không ai (ngay cả chính chúng ta) sẽ kết thúc việc ghi đè lên nó bằng cách gán một số giá trị cho tên biến / thuộc tính đó.
var obj = s89274934764: 'đây là giá trị của foo', get foo () return this.s89274934764; , đặt foo (val) this.s89274934764 = val; console.log (obj.foo); // "đây là giá trị của foo"
Hãy xem, đó là một cách để làm việc ra. Mặc dù tên tôi chọn không phải là một tên thực sự tốt, bạn cũng có thể sử dụng các giá trị hoặc ký hiệu ngẫu nhiên để tạo tên tài sản theo đề xuất của Derick Bailey trong bài đăng trên blog này. Mục tiêu chính là giữ dữ liệu ẩn từ mã khác và để một cặp getter-setter truy cập / cập nhật nó.
Khi nào bạn nên sử dụng getters và setters?
Bây giờ đến câu hỏi lớn: bạn có bắt đầu gán getters và setters cho tất cả dữ liệu của bạn hiện nay?
Nếu bạn ẩn dữ liệu, sau đó có không còn lựa chọn nào khác.
Nhưng nếu dữ liệu của bạn được xem bởi mã khác là tốt, bạn vẫn cần sử dụng getters setters chỉ để gói nó với mã thực hiện một số thao tác trên nó? tôi sẽ nói Vâng. Mã xuất hiện rất sớm. Tạo các đơn vị vi mô của dữ liệu riêng lẻ với trình thiết lập getter của riêng nó cung cấp cho bạn một sự độc lập nhất định để làm việc trên dữ liệu đã nói mà không ảnh hưởng đến các phần khác của mã.