Подтвердить что ты не робот

Как написать метод расширения в JavaScript?

Мне нужно написать несколько методов расширения в JS. Я знаю, как это сделать на С#. Пример:

public static string SayHi(this Object name)
{
    return "Hi " + name + "!";
}

а затем вызывается:

string firstName = "Bob";
string hi = firstName.SayHi();

Как мне сделать что-то подобное в JavaScript?

4b9b3361

Ответ 1

У JavaScript нет точного аналога для методов расширения С#. JavaScript и С# - это совершенно разные языки.

Ближайшая похожая вещь - изменить объект-прототип всех строковых объектов: String.prototype. Как правило, рекомендуется не модифицировать прототипы встроенных объектов в коде библиотеки, предназначенном для объединения с другим кодом, который вы не контролируете. (Делать это в приложении, где вы контролируете, какой другой код включен в приложение, можно.)

Если вы изменяете прототип встроенного, лучше (на сегодняшний день) сделать это свойство не перечисляемым, используя Object.defineProperty (ES5+, то есть практически любую современную среду JavaScript, и не IE8¹ или ранее). Чтобы соответствовать перечислимости, возможности записи и конфигурирования других строковых методов, он должен выглядеть следующим образом:

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
        return "Hi " + this + "!";
    },
    writable: true,
    configurable: true
});

(по умолчанию для enumerable установлено false.)

Если вам нужно было поддерживать устаревшие среды, то для String.prototype, в частности, вы, вероятно, могли бы избежать создания перечисляемого свойства:

// Don't do this if you can use 'Object.defineProperty'
String.prototype.SayHi = function SayHi() {
    return "Hi " + this + "!";
};

Это не очень хорошая идея, но вам это может сойти с рук. Никогда не делайте этого с Array.prototype или Object.prototype; создание перечисляемых свойств для них - это плохая вещь ™.

Подробности:

JavaScript - это прототип языка. Это означает, что каждый объект поддерживается прототипом объекта. В JavaScript этот прототип назначается одним из четырех способов:

  • С помощью функции конструктора для объекта (например, new Foo создает объект с Foo.prototype в качестве прототипа)
  • С помощью функции Object.create, добавленной в ES5 (2009)
  • Свойство доступа __proto__ (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());