JavaScript không có một tương tự chính xác cho các phương thức mở rộng của C #. JavaScript và C # là những ngôn ngữ khá khác nhau.
Điều tương tự gần nhất là cải tiến đối tượng nguyên mẫu của tất cả các đối tượng chuỗi: String.prototype
. Nói chung, cách tốt nhất là không sửa đổi nguyên mẫu của các đối tượng tích hợp sẵn trong mã thư viện được kết hợp với mã khác mà bạn không kiểm soát. (Làm điều đó trong một ứng dụng mà bạn kiểm soát mã nào khác được đưa vào ứng dụng là được.)
Nếu bạn thực sự sửa đổi nguyên mẫu của một bản cài sẵn, thì tốt nhất (cho đến nay) hãy biến nó thành một thuộc tính không liệt kê bằng cách sử dụng Object.defineProperty
(ES5 +, về cơ bản là bất kỳ môi trường JavaScript hiện đại nào chứ không phải IE8¹ hoặc phiên bản cũ hơn). Để phù hợp với khả năng liệt kê, khả năng ghi và khả năng cấu hình của các phương thức chuỗi khác, nó sẽ giống như sau:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(Giá trị mặc định enumerable
là false
.)
Nếu bạn cần hỗ trợ các môi trường lỗi thời, thì String.prototype
đặc biệt, bạn có thể bỏ qua việc tạo thuộc tính enumerable:
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
Đó không phải là một ý kiến hay, nhưng bạn có thể bỏ qua nó. Không bao giờ làm điều đó với Array.prototype
hoặc Object.prototype
; tạo ra các thuộc tính có thể liệt kê trên đó là một Bad Thing ™.
Chi tiết:
JavaScript là một ngôn ngữ nguyên mẫu. Điều đó có nghĩa là mọi đối tượng đều được hỗ trợ bởi một đối tượng nguyên mẫu . Trong JavaScript, nguyên mẫu đó được chỉ định theo một trong bốn cách:
- Bằng hàm khởi tạo cho đối tượng (ví dụ:
new Foo
tạo một đối tượng Foo.prototype
làm nguyên mẫu của nó)
- Bởi
Object.create
chức năng được thêm vào trong ES5 (2009)
- Bởi thuộc
__proto__
tính trình truy cập (ES2015 +, chỉ trên trình duyệt web, tồn tại trong một số môi trường trước khi nó được chuẩn hóa) hoặc Object.setPrototypeOf
(ES2015 +)
- Bằng công cụ JavaScript khi tạo một đối tượng cho nguyên thủy vì bạn đang gọi một phương thức trên đó (điều này đôi khi được gọi là "quảng cáo")
Vì vậy, trong ví dụ của bạn, vì firstName
là một chuỗi nguyên thủy, nó được thăng cấp thành một String
cá thể bất cứ khi nào bạn gọi một phương thức trên đó và String
nguyên mẫu của cá thể đó là như vậy String.prototype
. Vì vậy, việc thêm một thuộc tính String.prototype
tham chiếu đến SayHi
hàm của bạn sẽ làm cho hàm đó khả dụng trên tất cả các String
trường hợp (và hiệu quả trên các nguyên thủy của chuỗi, vì chúng được thăng cấp).
Thí dụ:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
console.log("Charlie".SayHi());
Có một số khác biệt chính giữa phương thức này và phương thức mở rộng C #:
(Như DougR đã chỉ ra trong một bình luận) Các phương thức mở rộng của C # có thể được gọi trên các null
tham chiếu . Nếu bạn có một string
phương thức mở rộng, mã này:
string s = null;
s.YourExtensionMethod();
làm. Điều đó không đúng với JavaScript; null
là kiểu riêng của nó và bất kỳ tham chiếu thuộc tính nào trên đều null
tạo ra lỗi. (Và ngay cả khi nó không, không có nguyên mẫu nào để mở rộng cho kiểu Null.)
(Như ChrisW đã chỉ ra trong một bình luận) Các phương thức mở rộng của C # không mang tính toàn cầu. Chúng chỉ có thể truy cập nếu không gian tên mà chúng được xác định được mã sử dụng bằng phương thức mở rộng. (Chúng thực sự là đường cú pháp cho các cuộc gọi tĩnh, đó là lý do tại sao chúng hoạt động trên đó null
.) Điều đó không đúng trong JavaScript: Nếu bạn thay đổi nguyên mẫu của một cài sẵn, thay đổi đó sẽ được nhìn thấy bởi tất cả mã trong toàn bộ lĩnh vực của bạn. làm điều đó trong (một lĩnh vực là môi trường toàn cầu và các đối tượng nội tại liên quan của nó, v.v.). Vì vậy, nếu bạn làm điều này trong một trang web, tất cả mã bạn tải trên trang đó sẽ thấy sự thay đổi. Nếu bạn làm điều này trong mô-đun Node.js, tất cảmã được tải trong cùng lĩnh vực với mô-đun đó sẽ thấy sự thay đổi. Trong cả hai trường hợp, đó là lý do tại sao bạn không làm điều này trong mã thư viện. (Các luồng nhân viên web và công nhân Node.js được tải trong lĩnh vực riêng của chúng, vì vậy chúng có môi trường toàn cầu khác và bản chất khác với chủ đề chính. Nhưng lĩnh vực đó vẫn được chia sẻ với bất kỳ mô-đun nào mà chúng tải.)
¹ IE8 có Object.defineProperty
, nhưng nó chỉ hoạt động trên các đối tượng DOM, không phải các đối tượng JavaScript. String.prototype
là một đối tượng JavaScript.