Есть ли разница в использовании конструктора для создания объекта по сравнению с возвратом объекта?
Есть ли разница в том, как работают эти функции? Первый типичнее того, о чем я думаю, когда думаю о конструкторе.
Пример 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
,
Вкратце, буквальный синтаксис объекта создает объект объекта.