В JavaScript метод — это функция, являющаяся свойством объекта. Другими словами, метод в JavaScript — это функция, а также свойство, находящееся в функции, потому что функция в JavaScript — это, по сути, особый тип объекта.

Тогда, если метод является функцией, может ли функция быть также и методом? Ответ положительный, потому что метод — это свойство, тип которого — функция.

В этой статье я покажу вам, как определить три типа методов и почему эти методы являются функциями.

Вся функция с методами выглядит следующим образом:

// Define function
function A(name, age) {
    this.name = name;
    this.age = age;
    // 1) define a property method
    this.getName = function() {
        return this.name;
    };
    this.getAge = function() {
        return this.age;
    };
}
// 2) define a prototype methood
A.prototype.getClassName = function() {
    return A.name;
}
// 3) define an static method
A.greeting = function() {
    return 'hello world';
}

Примечание: все функции были определены как объявления функций, потому что определение функции различными способами выходит за рамки нашей компетенции.

Метод свойства

В приведенном выше примере функция A была определена, где два метода с именами getName и getAge были определены следующим образом:

this.getName = function() {
    return this.name;
};
this.getAge = function() {
    return this.age;
};

Свойством может быть что угодно, включая метод. Итак, метод свойства — это свойство, которому присваивается функция. В этом примере анонимная функция function() { return this.name; }; была назначена свойству getName. Другими словами, метод свойства — это локальная анонимная функция, которая назначается свойству. Метод свойства создается всякий раз, когда в памяти создается новый экземпляр. Определение метода, который не является общим для объектов, может быть выгодным, если мы хотим выполнять отдельные операции для каждого экземпляра, но также может быть невыгодным, учитывая, что все экземпляры имеют свои собственные методы свойств, которые в результате могут потреблять слишком много памяти.

Метод прототипа

Прототип — это свойство, которое добавляется к функции. В приведенном выше примере мы можем получить доступ к прототипу функции A, вызвав A.prototype. Благодаря свойству прототипа мы можем не только получить доступ к свойству прототипа, но и добавить методы к прототипу, такие как:

A.prototype.getClassName = function() {
    return A.name;
}

В отличие от методов свойств, к методам-прототипам можно получить доступ во всех экземплярах, а это означает, что эти методы определены внутри прототипа, а не во всех экземплярах. В результате методы-прототипы будут потреблять меньше памяти по сравнению с методами свойств.

Статический метод

До es6 статические методы можно было определять непосредственно из Function. В приведенном выше примере это статический метод:

A.greeting = function() {
    return 'hello world';
}

Поскольку к greeting можно получить доступ из функции A, но нельзя получить доступ из экземпляров, статические методы могут быть полезны, если вы хотите определить методы, которые будут использоваться для всего объекта.

Преобразование функции в класс

Если мы преобразуем функцию A в класс, коды будут изменены следующим образом:

class A {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        this.getName = function () {
            return this.name;
        };
        this.getAge = function () {
            return this.age;
        };
    }
    getClassName() {
        return A.name;
    }
    static greeting() {
        return 'hello world';
    }
}

Как я объяснил, getName и getAge можно вызывать во всех экземплярах в нашей версии класса, поэтому getName и getAge будут создаваться всякий раз, когда создается экземпляр класса A.

С другой стороны, мы видим, что getClassName находится не внутри конструктора, а внутри объявления класса. Итак, мы можем вызвать getClassName либо из прототипа, либо из экземпляра.

Наконец, greeting теперь имеет префикс static, что означает, что greeting доступен классу A, а не экземплярам.

Таким образом, мы видим, что методы, определенные с помощью функции, эквивалентны методам класса в JavaScript.

Демонстрация

Чтобы продемонстрировать, как можно вызывать эти 3 типа методов, определенных с помощью function , я покажу вам несколько примеров, чтобы мы могли лучше понять, как можно вызывать методы в JavaScript.

Вызов метода свойства

Я уже упоминал, что методы свойств доступны только через экземпляры. Чтобы продемонстрировать это, если мы вызовем следующие коды в браузере Chrome:

const a = new A('Yoda', 233);
1) Call from the function A
console.log(A.getName())  // getName is not a function
console.log(A.getAge()) //  getAge is not a function
2) Call from prototype of the function A
console.log(A.prototype.getName())  // getName is not a function
console.log(A.prototype.getAge())  // getAge is not a function
3) Call from the instance of a
console.log(a.getName());  // Yoda
console.log(a.getAge());   // 233

мы увидим, что 1) и 2) будут утешать <function-name> is not a function, но 3) будут работать, потому что getName и getAge являются методами свойств, которые можно вызывать из экземпляров.

Вызов методов прототипа

Поскольку доступ к методам прототипа можно получить из свойства прототипа, которое является общим для всех экземпляров, мы можем вызвать метод прототипа либо из свойства прототипа, либо из экземпляров. Чтобы продемонстрировать это поведение, если мы выведем следующие коды:

1) Call from the function A
console.log(A.getClassName());  // getClassName is not a function
2) Call from the prototype of the function A
console.log(A.prototype.getClassName());  // A
3) Call from the instance of a
console.log(a.getClassName());  // A

мы увидим, что только 1) не будет работать, но оба 2) и 3) выведут имя функции A как A.

Вызов статических методов

Доступ к статическим методам возможен только из функции. Итак, если мы утешаем следующие коды:

1) Call from the function A
console.log(A.greeting());
2) Call from the prototype of the function A
console.log(A.prototype.greeting()); greeting is not a function
3) Call from the instance of a
console.log(a.greeting()); greeting is not a function

мы увидим, что только 1) напечатает hello world в консоли.

Преобразование методов в функции в методы на основе класса

Поскольку функции являются классами в JavaScript, методы, определенные в классе, могут вызываться таким же образом.

Заключение

Иногда разные термины, которые выглядят одинаково, сбивают нас с толку. Методы в JavaScript по сути являются функциями, поэтому нам нужно помнить о том, где методы определяются независимо от того, определены ли они с помощью функции или определены внутри класса. Когда методы определены внутри объявления функции, эти методы являются свойствами, которым присваиваются функции. Когда методы определены для прототипа, эти методы являются функциями, к которым можно получить доступ как из прототипа, так и из экземпляров. Наконец, когда методы определяются непосредственно из функции, эти методы являются функциями, доступными только из этой функции, а не из экземпляров.