Есть ли разница в использовании конструктора для создания объекта по сравнению с возвратом объекта?

Есть ли разница в том, как работают эти функции? Первый типичнее того, о чем я думаю, когда думаю о конструкторе.

Пример 1: использование этого для именования и установки свойств. Затем с помощью new создайте новый объект Book.

    function Book(name, numPages) {
        this.name = name;
        this.numPages = numPages;
    }

    var myBook = new Book('A Good Book', '500 pages');

Пример 2: возврат объекта с использованием new и просто вызов самой функции.

    function Movie(name, numMinutes) {
        return { name:name, numMinutes:numMinutes };
    }

    var best = new Movie('Forrest Gump', '150');

    var other = Movie('Gladiator', '180');

Я думаю, что я пытаюсь выяснить, если они отличаются в том, как они создают объект? Если так, то один лучше другого? Существуют ли разные ситуации, когда один будет работать лучше другого?

3 ответа

Первый является конструктором, и поэтому может быть расширен prototypeи вы можете проверить через instanceof В результате получается экземпляр этого типа. Недостаток: если вы забудете newключевое слово ваш код будет взорван (если вы не пишете обходной путь для этого в каждом constuctor)

И вы не можете использовать apply() с конструктором для передачи массива аргументов, когда вы создаете экземпляр нового объекта; с другой стороны, не делайте этого, даже если вы можете / могли.

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

Но вы не можете проверить, относятся ли они к одному и тому же типу, и у вас нет общего прототипа, который может повлиять на все экземпляры (возможно, "за" или "против").

Мой goto-подход Если мне нужно наследование, это своего рода сочетание обоих:
(если мне просто нужен объект данных, я обычно использую фабричные и простые объекты).

function Book(conf) {
    var book = Object.create(Book.prototype);
    //a book like this usually has multiple configs/properties
    if(typeof conf === "object"){
        for(var k in conf) book[k] = conf[k];
    }else if(conf){
        //assuming that I get at least the name passed
        book.name = String(conf);
    }
    return book;
}

//I have a prototype that can be extended
//with default-values for example; no idea for a good method 
//to add to the prototype in this example ;)
Book.prototype.numPages = 0;

//but I can also use it like a plain function; no error if you 
var myBook1 = Book("Peter Pan");
var myBook2 = Book({
    name: "American Gods",
    author: "Neil Gaiman"
});

Если я добавлю следующую строку в начало функции, я также смогу использовать ее как метод для преобразования чего-либо в экземпляр Book без клонирования уже существующих экземпляров

function Book(conf) {
    //with this simple line I can also use this as a function to cast anything into a "Book"
    if(conf instanceof Book) return conf;

    var book = Object.create(Book.prototype);
    //...
    return book;
}

var data = [
    "Peter Pan",
    {name: "American Gods"},
    //...
];

var books = data.map(Book);

По моему мнению, у меня есть преимущества обоих миров с этим подходом.

В основном, когда вы используете new, движок JS создает для вас совершенно новый объект и внедряет его как ценность this, Он также автоматически дает любые методы, прикрепленные к прототипу конструктора. Использование конструктора также позволяет проверить, является ли объект instanceof что-то более легко.

function MovieA(title) {
    this.title = title;
}
MovieA.prototype.getTitle = function() {
    return this.title;
};

function MovieB(title) {
    return {
    title: title
  };
}
MovieB.prototype.getTitle = function() {
    return this.title;
};

var a = new MovieA('A');
console.log(a instanceof MovieA); // true
console.log(a.getTitle()); // 'A'

var b = MovieB('B');
console.log(b instanceof MovieB); // false
console.log(b.getTitle()); // Uncaught TypeError: b.getTitle is not a function

Все что new предложения, которые вы можете получить с помощью других методов, но требует больше ручного труда.

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

var Factory = {
  makeThing: function() {
    return { name: 'thing' };
  }
};

// Want to test the case for if makeThing fails inside of some other code
var MockFactory = {
  makeThing: function() {
    return null;
  };
};

Что касается того, когда вы используете любой, все зависит. Некоторые люди не используют new совсем. Другие исключительно используют new, Все зависит от того, нужна ли вам какая-либо из перечисленных выше вещей, насколько вам нужен контроль над созданием объектов, когда вы хотите использовать this или нет и т. д. В конце концов, все зависит от предпочтений.

Разница в том, что конструктор используется для создания возвращаемого объекта.

new Book('A Good Book', '500 pages');

создает Book экземпляр объекта, с экземпляром, наследующим свойства от Book.prototypeв том числе constructor стоимость имущества Book, Book.prototype сам объект наследуется от Object.prototype,

var other = Movie('Gladiator', '180');

использования Movie как заводская функция (new не требуется) и возвращает экземпляр объекта Object, причем экземпляр наследует свойства непосредственно отObject.prototypeв том числе constructor стоимость имущества Object,

Вкратце, буквальный синтаксис объекта создает объект объекта.

Другие вопросы по тегам