Với việc giới thiệu Lớp trong TypeScript và ES6, hiện đã tồn tại một số tình huống nhất định yêu cầu các tính năng bổ sung để hỗ trợ chú thích hoặc sửa đổi lớp và thành viên lớp. Trình trang trí cung cấp một cách để thêm cả chú thích và cú pháp lập trình meta cho các khai báo và thành viên lớp. Trang trí là một đề xuất giai đoạn 2 cho JavaScript và có sẵn như một tính năng thử nghiệm của TypeScript LƯU Ý Trang trí là một tính năng thử nghiệm có thể thay đổi trong các bản phát hành trong tương lai
Để bật hỗ trợ thử nghiệm cho trình trang trí, bạn phải bật tùy chọn trình biên dịch trên dòng lệnh hoặc trong ts function sealed(target) { // do something with 'target' ... }
5 của bạnDòng lệnh shell tsc --target ES5 --experimentalDecorators
tsconfig. json { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
người trang tríTrình trang trí là một loại khai báo đặc biệt có thể được đính kèm với một , , , hoặc. Người trang trí sử dụng biểu mẫu ts function sealed(target) { // do something with 'target' ... }
6, trong đó ts function sealed(target) { // do something with 'target' ... }
7 phải đánh giá một hàm sẽ được gọi trong thời gian chạy với thông tin về khai báo được trang tríVí dụ, với decorator ts function sealed(target) { // do something with 'target' ... }
8, chúng ta có thể viết hàm ts function sealed(target) { // do something with 'target' ... }
9 như sauts function sealed(target) { // do something with 'target' ... }
nhà máy trang tríNếu chúng ta muốn tùy chỉnh cách một trình trang trí được áp dụng cho một khai báo, chúng ta có thể viết một nhà máy trang trí. Nhà máy trang trí chỉ đơn giản là một hàm trả về biểu thức sẽ được gọi bởi trình trang trí khi chạy Chúng ta có thể viết một nhà máy trang trí theo cách sau ________số 8_______Thành phần trang tríNhiều trình trang trí có thể được áp dụng cho một khai báo, ví dụ như trên một dòng ts @f @g x Try
Trên nhiều dòng ts @f @g x Try
Khi nhiều bộ trang trí áp dụng cho một khai báo, việc đánh giá chúng tương tự như thành phần hàm trong toán học. Trong mô hình này, khi lập các hàm f và g, hợp số thu được (f ∘ g)(x) tương đương với f(g(x)) Như vậy, các bước sau đây được thực hiện khi đánh giá nhiều trình trang trí trên một khai báo trong TypeScript - Các biểu thức cho mỗi trình trang trí được đánh giá từ trên xuống dưới
- Các kết quả sau đó được gọi là các hàm từ dưới lên trên
Nếu chúng ta sử dụng , chúng ta có thể quan sát thứ tự đánh giá này với ví dụ sau ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
Cái nào sẽ in đầu ra này ra bàn điều khiển shell first(): factory evaluated second(): factory evaluated second(): called first(): called
Đánh giá trang tríCó một thứ tự được xác định rõ ràng về cách áp dụng các trình trang trí cho các khai báo khác nhau bên trong một lớp. - Trình trang trí tham số, theo sau là Phương thức, Trình truy cập hoặc Trình trang trí thuộc tính được áp dụng cho từng thành viên phiên bản
- Trình trang trí tham số, theo sau là Phương thức, Trình truy cập hoặc Trình trang trí thuộc tính được áp dụng cho từng thành viên tĩnh
- Trình trang trí tham số được áp dụng cho hàm tạo
- Class Decorators được áp dụng cho lớp
Trang trí lớp họcTrình trang trí lớp được khai báo ngay trước khi khai báo lớp. Trình trang trí lớp được áp dụng cho hàm tạo của lớp và có thể được sử dụng để quan sát, sửa đổi hoặc thay thế một định nghĩa lớp. Không thể sử dụng trình trang trí lớp trong tệp khai báo hoặc trong bất kỳ ngữ cảnh xung quanh nào khác (chẳng hạn như trên lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
0)Biểu thức cho trình trang trí lớp sẽ được gọi là một hàm trong thời gian chạy, với hàm tạo của lớp được trang trí làm đối số duy nhất của nó Nếu trình trang trí lớp trả về một giá trị, nó sẽ thay thế khai báo lớp bằng hàm tạo được cung cấp LƯU Ý Nếu chọn trả về một hàm tạo mới, bạn phải cẩn thận để duy trì nguyên mẫu ban đầu. Logic áp dụng các trình trang trí trong thời gian chạy sẽ không làm điều này cho bạn
Sau đây là một ví dụ về trang trí lớp (_______0_______8) được áp dụng cho lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
2ts @sealed class BugReport { type = "report"; title: string; constructor(t: string) { this.title = t; } } Try
Chúng ta có thể định nghĩa trình trang trí ts function sealed(target) { // do something with 'target' ... }
8 bằng cách sử dụng khai báo hàm sauts function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); }
Khi ts function sealed(target) { // do something with 'target' ... }
8 được thực thi, nó sẽ niêm phong cả hàm tạo và nguyên mẫu của nó, và do đó sẽ ngăn không cho bất kỳ chức năng nào khác được thêm vào hoặc xóa khỏi lớp này trong thời gian chạy bằng cách truy cập ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator
// do something with 'target' and 'value'... }; } 5 hoặc bằng cách xác định các thuộc tính trên chính ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
2 (lưu ý rằng các lớp ES2015 thực sự . Trình trang trí này không ngăn các lớp phân lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
2Tiếp theo, chúng ta có một ví dụ về cách ghi đè hàm tạo để đặt giá trị mặc định mới { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
0phương pháp trang tríTrình trang trí phương thức được khai báo ngay trước khi khai báo phương thức. Trình trang trí được áp dụng cho Trình mô tả thuộc tính cho phương thức và có thể được sử dụng để quan sát, sửa đổi hoặc thay thế định nghĩa phương thức. Không thể sử dụng trình trang trí phương thức trong tệp khai báo, khi quá tải hoặc trong bất kỳ ngữ cảnh xung quanh nào khác (chẳng hạn như trong lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
0)Biểu thức cho trình trang trí phương thức sẽ được gọi là một hàm trong thời gian chạy, với ba đối số sau - Hàm khởi tạo của lớp đối với thành viên tĩnh hoặc nguyên mẫu của lớp đối với thành viên thể hiện
- Tên của thành viên
- Bộ mô tả thuộc tính cho thành viên
LƯU Ý Bộ mô tả thuộc tính sẽ là ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
9 nếu mục tiêu tập lệnh của bạn nhỏ hơn ts @f @g x Try
0
Nếu trình trang trí phương thức trả về một giá trị, nó sẽ được sử dụng làm Mô tả thuộc tính cho phương thức LƯU Ý Giá trị trả về bị bỏ qua nếu mục tiêu tập lệnh của bạn nhỏ hơn ts @f @g x Try
0
Sau đây là một ví dụ về một trình trang trí phương thức (_______9_______2) được áp dụng cho một phương thức trên lớp ts @f @g x Try
3{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
1Chúng ta có thể định nghĩa trình trang trí ts @f @g x Try
2 bằng cách sử dụng khai báo hàm sau{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
2Người trang trí ts @f @g x Try
5 ở đây là một. Khi trình trang trí ts @f @g x Try
5 được gọi, nó sẽ sửa đổi thuộc tính ts @f @g x Try
7 của trình mô tả thuộc tínhPhụ kiện trang tríMột Accessor Decorator được khai báo ngay trước một khai báo accessor. Trình trang trí bộ truy cập được áp dụng cho Bộ mô tả thuộc tính cho bộ truy cập và có thể được sử dụng để quan sát, sửa đổi hoặc thay thế các định nghĩa của bộ truy cập. Không thể sử dụng bộ trang trí bộ truy cập trong tệp khai báo hoặc trong bất kỳ ngữ cảnh xung quanh nào khác (chẳng hạn như trong lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
0)LƯU Ý TypeScript không cho phép trang trí cả trình truy cập ts @f @g x Try
9 và ts @f @g x Try
0 cho một thành viên. Thay vào đó, tất cả các trình trang trí cho thành viên phải được áp dụng cho trình truy cập đầu tiên được chỉ định theo thứ tự tài liệu. Điều này là do các bộ trang trí áp dụng cho Bộ mô tả thuộc tính, kết hợp cả bộ truy cập ts @f @g x Try
9 và ts @f @g x Try
0, không phải mỗi khai báo riêng biệt
Biểu thức cho trình trang trí trình truy cập sẽ được gọi là một hàm trong thời gian chạy, với ba đối số sau - Hàm khởi tạo của lớp đối với thành viên tĩnh hoặc nguyên mẫu của lớp đối với thành viên thể hiện
- Tên của thành viên
- Bộ mô tả thuộc tính cho thành viên
LƯU Ý Bộ mô tả thuộc tính sẽ là ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
9 nếu mục tiêu tập lệnh của bạn nhỏ hơn ts @f @g x Try
0
Nếu trình trang trí trình truy cập trả về một giá trị, nó sẽ được sử dụng làm Trình mô tả thuộc tính cho thành viên LƯU Ý Giá trị trả về bị bỏ qua nếu mục tiêu tập lệnh của bạn nhỏ hơn ts @f @g x Try
0
Sau đây là một ví dụ về một bộ trang trí phụ ( ts @f @g x Try
6) được áp dụng cho một thành viên của lớp ts @f @g x Try
7{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
3Chúng ta có thể định nghĩa trình trang trí ts @f @g x Try
6 bằng cách sử dụng khai báo hàm sau{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
4trang trí tài sảnTrình trang trí thuộc tính được khai báo ngay trước khi khai báo thuộc tính. Không thể sử dụng trình trang trí thuộc tính trong tệp khai báo hoặc trong bất kỳ ngữ cảnh xung quanh nào khác (chẳng hạn như trong lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
0)Biểu thức cho trình trang trí thuộc tính sẽ được gọi là một hàm trong thời gian chạy, với hai đối số sau - Hàm khởi tạo của lớp đối với thành viên tĩnh hoặc nguyên mẫu của lớp đối với thành viên thể hiện
- Tên của thành viên
LƯU Ý Bộ mô tả thuộc tính không được cung cấp làm đối số cho bộ trang trí thuộc tính do cách khởi tạo bộ trang trí thuộc tính trong TypeScript. Điều này là do hiện tại không có cơ chế nào để mô tả thuộc tính thể hiện khi xác định các thành viên của nguyên mẫu và không có cách nào để quan sát hoặc sửa đổi trình khởi tạo cho thuộc tính. Giá trị trả về cũng bị bỏ qua. Như vậy, một trình trang trí thuộc tính chỉ có thể được sử dụng để quan sát rằng một thuộc tính của một tên cụ thể đã được khai báo cho một lớp
Chúng tôi có thể sử dụng thông tin này để ghi lại siêu dữ liệu về thuộc tính, như trong ví dụ sau { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
5Sau đó, chúng ta có thể xác định hàm trang trí ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
0 và hàm ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
1 bằng cách sử dụng các khai báo hàm sau{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
6Người trang trí ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
2 ở đây là một. Khi ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
2 được gọi, nó sẽ thêm một mục nhập siêu dữ liệu cho thuộc tính bằng cách sử dụng hàm ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called");
}; } class ExampleClass { @first() @second() method() {} } Try 4 từ thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5. Khi ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
1 được gọi, nó sẽ đọc giá trị siêu dữ liệu cho định dạngLƯU Ý Ví dụ này yêu cầu thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5. Xem để biết thêm thông tin về thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5
Trình trang trí thông sốTrình trang trí tham số được khai báo ngay trước khi khai báo tham số. Trình trang trí tham số được áp dụng cho hàm cho hàm tạo lớp hoặc khai báo phương thức. Không thể sử dụng trình trang trí tham số trong tệp khai báo, quá tải hoặc trong bất kỳ ngữ cảnh xung quanh nào khác (chẳng hạn như trong lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
0)Biểu thức cho trình trang trí tham số sẽ được gọi là một hàm trong thời gian chạy, với ba đối số sau - Hàm khởi tạo của lớp đối với thành viên tĩnh hoặc nguyên mẫu của lớp đối với thành viên thể hiện
- Tên của thành viên
- Chỉ số thứ tự của tham số trong danh sách tham số của hàm
LƯU Ý Chỉ có thể sử dụng một trình trang trí tham số để quan sát xem một tham số đã được khai báo trên một phương thức hay chưa
Giá trị trả về của trình trang trí tham số bị bỏ qua Sau đây là một ví dụ về trình trang trí tham số (_______12_______0) được áp dụng cho tham số của một thành viên của lớp ts function color(value: string) { // this is the decorator factory, it sets up // the returned decorator function return function (target) { // this is the decorator // do something with 'target' and 'value'... }; }
2{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
7Sau đó, chúng ta có thể xác định các trình trang trí shell first(): factory evaluated second(): factory evaluated second(): called first(): called
0 và shell first(): factory evaluated second(): factory evaluated second(): called first(): called
3 bằng cách sử dụng các khai báo hàm sau{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
8Trình trang trí shell first(): factory evaluated second(): factory evaluated
second(): called first(): called 0 thêm mục nhập siêu dữ liệu đánh dấu tham số theo yêu cầu. Trình trang trí shell first(): factory evaluated second(): factory evaluated second(): called first(): called
3 sau đó bao bọc phương thức shell first(): factory evaluated second(): factory evaluated second(): called first(): called
6 hiện có trong một hàm xác thực các đối số trước khi gọi phương thức ban đầuLƯU Ý Ví dụ này yêu cầu thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5. Xem để biết thêm thông tin về thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5
MetadataMột số ví dụ sử dụng thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5 bổ sung một polyfill cho API siêu dữ liệu thử nghiệm. Thư viện này chưa phải là một phần của tiêu chuẩn ECMAScript (JavaScript). Tuy nhiên, khi các công cụ trang trí được chính thức áp dụng như một phần của tiêu chuẩn ECMAScript, các tiện ích mở rộng này sẽ được đề xuất áp dụngBạn có thể cài đặt thư viện này qua npm { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
9TypeScript bao gồm hỗ trợ thử nghiệm để phát ra một số loại siêu dữ liệu nhất định cho các khai báo có trang trí. Để kích hoạt hỗ trợ thử nghiệm này, bạn phải đặt tùy chọn trình biên dịch trên dòng lệnh hoặc trong ts function sealed(target) { // do something with 'target' ... }
5 của mìnhDòng lệnh ts function sealed(target) { // do something with 'target' ... }
0tsconfig. json ts function sealed(target) { // do something with 'target' ... }
1Khi được bật, miễn là thư viện ts function first() { console.log("first(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("first(): called"); }; } function second() { console.log("second(): factory evaluated"); return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { console.log("second(): called"); }; } class ExampleClass { @first() @second() method() {} } Try
5 đã được nhập, thông tin loại thời gian thiết kế bổ sung sẽ được hiển thị khi chạyChúng ta có thể thấy điều này trong hành động trong ví dụ sau ts function sealed(target) { // do something with 'target' ... }
2Trình biên dịch TypeScript sẽ đưa thông tin loại thời gian thiết kế bằng cách sử dụng trình trang trí ts @sealed class BugReport { type = "report"; title: string; constructor(t: string) { this.title = t; } } Try
3. Bạn có thể coi nó tương đương với TypeScript sauts function sealed(target) { // do something with 'target' ... }
3LƯU Ý Siêu dữ liệu của Trình trang trí là một tính năng thử nghiệm và có thể giới thiệu những thay đổi đột phá trong các bản phát hành trong tương lai
Một người trang trí có thể ở trong một lớp không?
Chúng ta có thể dễ dàng tạo các công cụ trang trí bên trong một lớp và nó có thể dễ dàng truy cập đối với các lớp con của nó.
Chúng ta có thể sử dụng trình trang trí trên lớp trong Python không?
Trong Python, bộ trang trí có thể là hàm hoặc lớp . Trong cả hai trường hợp, trang trí thêm chức năng cho các chức năng hiện có. Khi chúng ta trang trí một hàm với một lớp, thì hàm đó sẽ trở thành một thể hiện của lớp.
Bạn có thể chuyển đối số cho trình trang trí Python không?
Các loại trang trí khác nhau trong Python là gì?
Trên thực tế, có hai loại trình trang trí trong Python — trình trang trí lớp và trình trang trí chức năng — nhưng tôi sẽ tập trung vào trình trang trí chức năng ở đây.
|