JavaScript не має точного аналога для методів розширення C #. JavaScript та C # - досить різні мови.
Найближча подібна річ, щоб змінити об'єкт - прототип всіх строкових об'єктів: String.prototype
. Загалом, найкраща практика - не змінювати прототипи вбудованих об’єктів у бібліотечному коді, призначеному для комбінування з іншим кодом, яким ви не керуєте. (Робити це в програмі, де ви контролюєте, який інший код входить до програми, це нормально.)
Якщо ви робите зміни прототипу вбудованої в, це краще за все (на сьогоднішній день) , щоб зробити це в незліченну властивість, використовуючи Object.defineProperty
(ES5 +, тому в основному будь-яку сучасну середу JavaScript, а не IE8¹ або раніше). Щоб відповідати перелічуваності, запису та настроюваності інших рядкових методів, це буде виглядати так:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(За замовчуванням для enumerable
IS false
) .
Якщо вам потрібно було підтримувати застарілі середовища, то String.prototype
, зокрема, ви, мабуть, могли б піти зі створенням переліченої властивості:
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
Це не гарна ідея, але ви можете з цим уникнути. Ніколи не робіть цього з Array.prototype
або Object.prototype
; створення незліченних властивостей на них - це погана річ ™.
Подробиці:
JavaScript є прототиповою мовою. Це означає, що кожен об’єкт підтримується об’єктом-прототипом . У JavaScript цей прототип призначається одним із чотирьох способів:
- За допомогою функції конструктора для об'єкта (наприклад,
new Foo
створює об'єкт з Foo.prototype
прототипом)
- За
Object.create
функцією, доданою в ES5 (2009)
- За
__proto__
властивістю accessor (ES2015 +, лише у веб-браузерах, існував у деяких середовищах до його стандартизації) або Object.setPrototypeOf
(ES2015 +)
- За допомогою механізму JavaScript під час створення об’єкта для примітиву, оскільки ви викликаєте на ньому метод (це іноді називають "просуванням")
Отже, у вашому прикладі, оскільки firstName
рядок є примітивним, він переходить у String
екземпляр кожного разу, коли ви викликаєте в ньому метод, а String
прототип цього екземпляра є String.prototype
. Отже, додавання властивості до String.prototype
посилань на вашу SayHi
функцію робить цю функцію доступною у всіх String
примірниках (і ефективно для примітивних рядків, оскільки вони отримують підвищення).
Приклад:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
console.log("Charlie".SayHi());
Існує кілька ключових відмінностей між цим та методами розширення C #:
(Як зазначив DougR у коментарі) Методи розширення C # можна використовувати для null
посилань . Якщо у вас є string
метод розширення, цей код:
string s = null;
s.YourExtensionMethod();
робіт. Це неправда з JavaScript; null
є своїм типом, і будь-яке посилання на властивість null
видає помилку. (І навіть якщо цього не сталося, прототипу, який можна розширити для типу Null, немає).
(Як зазначив ChrisW у коментарі) Методи розширення C # не є глобальними. Вони доступні лише в тому випадку, якщо простір імен, у якому вони визначені, використовується кодом за допомогою методу розширення. (Вони насправді є синтаксичним цукром для статичних викликів, саме тому вони працюють null
.) Це не відповідає дійсності в JavaScript: Якщо ви зміните прототип вбудованого, ця зміна бачиться у всьому коді у всій вашій області. зробіть це в (сфера - це глобальне середовище та пов'язані з ним внутрішні об'єкти тощо). Отже, якщо ви робите це на веб-сторінці, весь код, який ви завантажуєте на цю сторінку, бачить зміну. Якщо ви робите це в модулі Node.js, всекод, завантажений в ту ж область, що і цей модуль, побачить зміну. В обох випадках саме тому ви не робите цього в коді бібліотеки. (Веб-працівники та робочі потоки Node.js завантажуються у їх власному середовищі, тому вони мають інше глобальне середовище та інші властивості, ніж основний потік. Але ця сфера все ще спільна з будь-якими модулями, які вони завантажують.)
¹ IE8 дійсно має Object.defineProperty
, але він працює лише на об'єктах DOM, а не на об'єктах JavaScript. String.prototype
є об’єктом JavaScript.