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

JavaScript OOP: определение метода с помощью или без "prototype"

Этот код,

function Person() {
    function  myMethod() {
        alert ('hello');
    }
    this.method = myMethod;
}

эквивалентно:

function Person() {    }
Person.prototype.method2  = function() {
    alert ('hello');
};

Если да, какое определение метода следует использовать и почему?

4b9b3361

Ответ 1

Они функционально эквивалентны в вашем простом примере, но за кулисами работают совсем по-другому. Свойство prototype для функции действительно является "шаблоном прототипа". Он говорит: "Всякий раз, когда объект создается, и я использую его как конструктор объекта, дайте им этот объект в качестве своего прототипа".

Итак, все Person, созданные во втором примере, используют одну и ту же копию метода method2.

В первом примере каждый раз, когда интерпретатор встречает ключевое слово function, он создает новый объект функции. Поэтому в первом примере каждый экземпляр Person имеет свою собственную копию метода myMethod. Подавляющее большинство времени это не имеет значения. Но этот первый подход использует больше памяти, и иногда это имеет значение.

Они не функционально эквивалентны в более интересных случаях. В первом примере myMethod может обращаться к локальным переменным, определенным в Person, но второй пример не может, как одно отличие.

Ответ 2

В первом сценарии, когда вы создаете нового человека, var person1 = new Person();, он будет иметь свою собственную копию myMethod. Если вы создадите 100 объектов Person, каждая из них будет иметь свою собственную копию этого метода.

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

Если вы планируете иметь несколько объектов Person, второй способ лучше... но если есть только несколько объектов Person, это не имеет большого значения.

Ответ 3

Это не совсем эквивалентно.

В обоих случаях вы определяете функцию (конструктор) Person() в глобальном пространстве имен.

В первом случае вы определяете новую функцию myMethod() в замыкании внутри функции Person(). Обычно функция myMethod() недоступна после завершения функции/конструктора Person(). Однако в этом случае вы назначаете его this.method. Таким образом, при запуске конструктора

var myPerson = new Person();

Создается новый объект, затем функция Person() вызывается с this, установленным для нового объекта. Поэтому ваш новый объект получает поле method с функцией myMethod, привязанной к нему.

Во втором случае method2 определяется внутри Person.prototype. В этом случае, когда вы вызываете

var myPerson = new Person();

не будет поля, определенного непосредственно внутри вашего нового объекта (так как вы ничего не делаете с this в функции Person). Однако каждый объект содержит ссылку на его прототип. Если объект создается вызовом Person(), эта ссылка устанавливается на Person.prototype. Таким образом, ваш объект в конечном итоге будет содержать method2, хотя и не сам по себе, а в прототипе. Поэтому, когда вы вызываете

myPerson.method2();

интерпретатор ищет method2 внутри объекта myPerson и ничего не находит, затем он просматривает прототип myPerson, который Person.prototype и находит method2, поэтому он вызывает его.

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

Ответ 4

Нет, они не эквивалентны. Хотя, они похожи. Первый метод создаст новую функцию myMethod для каждого созданного new Person().

Второй метод будет иметь одну функцию method2, которая "разделяется" всеми Person's.

Ответ 5

У них аналогичная функциональность, но вы должны использовать второй подход (прототип), потому что, когда вы создадите объект с помощью new Person(), каждый объект будет иметь один и тот же method2, но с использованием первого подхода каждый новый объект будет иметь свой собственный myMethod(), который будет потреблять память moe.

Несколько дней назад я задал аналогичный вопрос и получил этот ответ.