Javascript создание объектов - несколько подходов, какие-то различия?

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

Подход 1

var obj = {
    prop: value,
    .
    .
    .
}

Подход один - стандартный подход, ничего нового :)

Подход 2

var obj = new function() {
    var prop1 = value1;
    var fn1 = function() {
    };
    .
    .
    .

    this.prop2 = value2;
    .
    .
    .
}();

Функциональный подход, я хотел сравнить этот подход с подходом 3. Функциональный подход в основном используется для инкапсуляции (правильно?)

Подход 3

var obj = (function() {
    var prop1 = value1;
    var fn1 = function() {
    };
    .
    .
    .

    return {
        prop2: value2,
        .
        .
        .
    }
})();

При таком подходе я не совсем вижу причину его использования. Чем он отличается от подхода 2? Оба могут использоваться для инкапсуляции логики.

Значит ли это, что мы можем передавать параметры, чтобы мы могли иметь дело с любыми потенциальными конфликтами?? Например, синтаксис jquery $, но вы также можете сделать это с подходом 2...

Спасибо.


Изменить:


Я знаю, что подход 1 и 3 похожи (в том, что они оба возвращают объекты), однако подход 3 также создает закрытие. Какой подход 2 также делает.

На самом деле это основа моего вопроса, и 2, и 3 создают замыкания, но в чем разница между ними.


person Umair    schedule 19.04.2013    source источник
comment
В подходе 2 не должно быть ключевого слова new.   -  person Halcyon    schedule 19.04.2013
comment
@FritsvanCampen - Да, должен. Это создает новый объект из (анонимной) функции-конструктора.   -  person Ted Hopp    schedule 19.04.2013
comment
если ключевого слова new нет, это будет класс.   -  person macool    schedule 19.04.2013
comment
во втором методе должен быть оператор ()   -  person Kamyar Nazeri    schedule 19.04.2013
comment
Я предполагаю, что это класс. Думаю, это не тогда. Немного странно использовать new без прототипов.   -  person Halcyon    schedule 19.04.2013
comment
@KamyarNazeri - Нет, оператор new позаботится о вызове функции.   -  person Ted Hopp    schedule 19.04.2013
comment
@Kamyar Nazeri - Не следуй. Почему должны быть скобки??   -  person Umair    schedule 19.04.2013
comment
Оператор new не нужен () только если конструктор не принимает никаких параметров, однако в вашем случае вы правы   -  person Kamyar Nazeri    schedule 19.04.2013
comment
О, я вижу. Да, вы правы, я обновлю :)   -  person Umair    schedule 19.04.2013
comment
Я думаю, что Алексей определил единственную реальную разницу между подходами 2 и 3.   -  person Ted Hopp    schedule 19.04.2013
comment
как бы вы создали новый obj с подходом 3?   -  person teewuane    schedule 30.04.2014


Ответы (9)


В подходах №2 и №3 свойство constructor результирующих объектов будет другим.

На практике это означает, что второй подход позволяет создавать более одного объекта с помощью функции анонимного конструктора:

x = new function() { alert(1) };
y = new x.constructor; // shows the message too

Лучший ответ на Шаблон модуля и экземпляр анонимного конструктора включает цитату Дугласа Крокфорда, в которой он объясняет, почему он считает, что подход №3 лучше, чем №2.

person Alexey Lebedev    schedule 19.04.2013
comment
Хороший. Я не думал о свойстве constructor. - person Ted Hopp; 19.04.2013

7 способов создания объектов в JavaScript:

<сильный>1. Конструктор объектов

Самый простой способ создать объект — использовать конструктор объектов: view plainprint?

var person = new Object();  
person.name = "Diego";  
person.getName = function(){  
    return this.name;  
}; 

<сильный>2. Буквенное обозначение

посмотреть расшифровку?

var person = {  
    person.name : "Diego",  
    person.getName : function(){  
        return this.name;  
    }  
} 

<сильный>3. Заводская функция

Функция Factory позволяет инкапсулировать и повторно использовать логику для создания подобных объектов. Для этого он использует любую из предыдущих конструкций. Либо: просмотреть открытый текст?

var newPerson=function(name){  
    var result = new Object();  
    result.name = name;  
    result.getName = function(){  
        return this.name;  
    };  
    return result;  
};  
var personOne = newPerson("Diego");  
var personTwo = newPerson("Gangelo");  
console.log(personOne.getName()); // prints Diego  
console.log(personTwo.getName()); // prints Gangelo

Or:

view plainprint?
var newPerson=function(name){  
    return {  
        person.name : name,  
        person.getName : function(){  
            return this.name;  
        };  
};  
var personOne = newPerson("Diego");  
var personTwo = newPerson("Gangelo");  
console.log(personOne.getName()); // prints Diego  
console.log(personTwo.getName()); // prints Gangelo  

<сильный>4. Конструктор функций

В Javascript можно вызвать любую функцию с оператором new перед ней. Учитывая функцию F, для новой F(): создается новый пустой объект X. X устанавливается в качестве контекста для F, что означает, что во всем F это указывает на X. X возвращается как результат открытого отпечатка представления F?

function Person(name){  
        this.name = name;  
        this.getName = function(){  
            return this.name;  
        };  
};  
var personOne = new Person("Diego");  
console.log(personOne.getName()); // prints Diego  
console.log(personOne instanceOf Person); // prints true  
console.log(personOne.constructor === Person); // prints true  
console.log(personOne instanceOf Object); // prints true  

<сильный>5. Прототип

Функции очень специфичны в Javascript. Это объекты, они могут создавать другие объекты и автоматически получают поле с именем прототип. Прототип — это простой объект с одним полем, называемым конструктором, указывающим на саму функцию. Что делает его особенным, так это то, что каждый объект, созданный с помощью функции, наследует прототип функции. посмотреть расшифровку?

function Person(){};  
Person.prototype.name = "Diego";  
var personOne = new Person();  
var personTwo = new Person();  
console.log(personOne.constructor == Person); // prints true  
console.log(personOne.name); // prints Diego  
console.log(personTwo.constructor == Person); // prints true  
console.log(personTwo.name); // prints Diego  

<сильный>6. Сочетание функции/прототипа

Комбинация функция/прототип, как вы понимаете, использует преимущества обоих подходов :)

function Person(name){  
        this.name = name;  
};  
Person.prototype.getName = function(){  
            return this.name;  
        };  
var personOne = new Person("Diego");  
var personTwo = new Person("Filippo");  
console.log(personOne.getName()); // prints Diego  
console.log(personTwo.getName()); // prints Filippo  
console.log(personOne.getName === personTwo.getName) //prints true 

<сильный>7. Синглтон

Иногда вам может понадобиться убедиться, что существует только один экземпляр определенного класса. Получить Singleton в Javascript так же просто, как определить и вызвать конструктор одновременно: просмотреть обычный отпечаток?

var singleton = new function(){  
    this.name = "ApplicationName";  
};  
person Community    schedule 10.12.2014
comment
что означает просмотр открытого текста? даже в смысле? - person doubleOrt; 12.09.2017

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

var obj = (function() {
    var prop = {};

    return {
        prop2: function(){ return prop };
    }
})();

С точки зрения производительности вы можете подумать, что третий подход создает закрытие, а первый - нет!

Однако во втором подходе вы просто создаете новый объект из анонимного класса, который не является прямым потомком класса Object.

Правильная форма второго подхода такова (по крайней мере, это стандарт ecma):

var obj = new function() {
    var prop1 = value1;

    this.prop2 = value2;
}();

Разница между подходом 2 и 3 заключается только в их цепочке наследования: (при условии, что obj2 - из 2-го подхода, а obj3 - из 3-го подхода)

obj2.__proto__ == Object.prototype;  // false
obj3.__proto__ == Object.prototype;  // true

obj2 создается из самого анонимного класса:

obj2.__proto__.__proto__ == Object.prototype;  // true (there's 2 level of inheritance here)
person Kamyar Nazeri    schedule 19.04.2013
comment
Что вы подразумеваете под прямым ребенком? - person Alexey Lebedev; 19.04.2013
comment
любой литерал объекта наследуется непосредственно от Object.prototype, что делает его прямым потомком класса Object: obj.__proto__ == Object.prototype - person Kamyar Nazeri; 19.04.2013

Подход 1
Это один объект, без класса, и вы не можете определить его проще, если он сложный

var obj = {
   prop: value
}

Подход 2
Неанонимная функция. Он создаст объект из «класса», обычно функция сохраняется как имя класса и может легко создавать несколько объектов одного типа, как показано ниже:

var Bycicle= function() {
    var prop1 = value1;

    this.prop2 = value2;
}
var obj1 = new Bycicle(),
    obj2 = new Bycicle();

Подход 3
Анонимная функция, переменные вне функции не могут мешать переменным внутри функции:

var a = 10;
var obj = (function() {
    alert(a); // Alerts undefined
    var prop1 = value1;
    alert(prop1); // alerts the value of value1
    return {
        prop2: value2;
    }
})(); // Within the () you can pass arguments to the anonymous function.

Подробнее об анонимных функциях: http://helephant.com/2008/08/23/javascript-anonymous-functions/

Другие подходы
Также есть Object.create() и new Object() для создания новых объектов, которые совпадают с подходом 1.

Заключение
В конце концов, объект всегда будет одним и тем же, за исключением третьего, потому что он анонимный.

person Niels    schedule 19.04.2013

Есть также:

var obj = Object.create({prop: ...});

Это работает путем установки прототипа. Гораздо эффективнее использовать прототип, если вы собираетесь иметь несколько объектов с общими свойствами или методами.

var proto = {foo: function() {}},
    obj1 = Object.create(proto),
    obj2 = Object.create(proto),
    obj3 = {foo: function() {}},
    obj4 = {foo: function() {}};

В этом примере obj1 и obj2 совместно используют функцию "foo", определенную в "proto". Между тем, obj3 и obj4 имеют свои собственные "foo". Если вы создаете много объектов с большим количеством свойств, это может иметь большое значение в потреблении памяти и даже в производительности.

Это преимущество используется при использовании ключевого слова «new», если вы используете именованную функцию и назначаете свойства прототипу функции (например, f.prototype.prop) перед использованием new.

person rich remer    schedule 09.12.2013

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

О разнице, когда вы создаете объект, подобный Подходу 1, вы можете думать об этом как об объекте только со статической функцией, как в java. поэтому он всегда жив, и вы не делаете из него экземпляр (аналогично синглтону) - поэтому, когда вы создаете этот объект:

var obj = {
    prop: value,
    func: function(){
     alert(this.prop);
    }
};

Вы можете вызвать его немедленно:

obj.prop = 'something else';
obj.func();

Подход 2 (без нового, такого как комментарий, который вы получили) — это классический объект, экземпляры которого вы можете создавать — делать наследование (с «трюками» js) и так далее:

function Person(firstName,lastName){ // or var Person = function(...
   this.firstName = firstName;
   this.lastName= lastName;

   this.getFullName = function(){
      return this.firstName + ' ' + this.lastName;
   }
}

//use
var person1 = new Person('yair','lapid');
var person2 = new Person('Naftali','Bennet');

you can put it in an array etc...
var arr = [person1,person2, new Person('shelly','yekimovits')];
person Adidi    schedule 19.04.2013
comment
Подход 3 создает замыкание; подход 1 нет. Это делает их совсем другими. - person Ted Hopp; 19.04.2013
comment
Но это не вопрос - вы также можете вызвать обычную функцию, которая возвращает объект или самолет, который возвращает объект - он спрашивает о разнице в создании объектов - и это не правильное определение закрытия между прочим... - person Adidi; 19.04.2013

Я немного поработал с JS и подумал о том, чтобы опубликовать какой-нибудь ответ, надеюсь, он тоже поможет кому-то еще:

1) Object Literal: вы буквально записали объект при его создании.

var person = {
  name: ['Bob', 'Smith'],
  age: 32,
  gender: 'male',
  interests: ['music', 'skiing'],
  bio: function() {
    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  },
  greeting: function() {
    alert('Hi! I\'m ' + this.name[0] + '.');
  }
};

Использование: Когда вы хотите передать данные на сервер

2) Функция конструктора: вы используете функцию конструктора, когда хотите создать несколько объектов одного вида.

function Vehicle(name, maker) {
  this.name = name;// Every function while executing has a reference         
            this.maker = maker;// to its current execution context called as this
}
let car1 = new Vehicle(’Fiesta’, 'Ford’);// New keyword with function turns function call into constructor call
let car2 = new Vehicle(’Santa Fe’, 'Hyundai’);

console.log(car1.name);    //Output: Fiesta
console.log(car2.name);    //Output: Santa Fe

3) Создать объект Javascript с помощью метода create

Object.create() позволяет создавать объекты с дополнительными параметрами атрибутов, такими как значение, настраиваемый, перечисляемый и доступный для записи. Создает новый объект, расширяющий объект-прототип, переданный в качестве параметра.

let car = Object.create(Object.prototype,{
   name:{
     value: 'Fiesta',
     configurable: true,
     writable: true,
     enumerable: false
   },
   maker:{
     value: 'Ford',
     configurable: true,
     writable: true,
     enumerable: true
   }});
console.log(car.name)    //Output: Fiesta

Прототип: каждый отдельный объект создается с помощью функции-конструктора. Функция конструктора связывает объект с его собственным прототипом. Прототип — это произвольная связь между конструктором и объектом.

4) Создать Javascript с помощью классов ES6

class Vehicle {
 constructor(name, maker, engine) {
   this.name = name;
   this.maker =  maker;
   this.engine = engine;
 }
}

let bike1 = new Vehicle('Hayabusa', 'Suzuki', '1340cc');
let bike2 = new Vehicle('Ninja', 'Kawasaki', '998cc');

console.log(bike1.name);    //Output: Hayabusa
console.log(bike2.maker);   //Output: Kawasaki

5) Использование конструктора объектов

var d = new Object();

Лучший способ создать пустые объекты.

Примечание. Я скомпилировал большую часть содержимого по этой ссылке https://codeburst.io/various-ways-to-create-javascript-object-9563c6887a47

person Apurva Pathak    schedule 07.01.2019

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

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

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

person Racheet    schedule 19.04.2013
comment
Сотрудник однажды удалил ключевое слово new из анонимного конструктора, потому что подумал, что это опечатка. - person Alexey Lebedev; 19.04.2013

Между подходами 2 и 3 для одноразовых объектов нет большой разницы. (Если бы вы назвали функцию, используемую в подходе 2, вы бы определили повторно используемый конструктор.) У меня сложилось впечатление, что подход 3 чаще используется для таких ситуаций, но я не вижу большой разницы между ними.

Следует отметить, что оба подхода 2 и 3 могут принимать аргументы:

var approach2Obj = new function(formalArg) {
    var privateProp = ...;
    this.publicProp = ...;
    // more constructor logic
)(actualArg);

var approach3Obj = (function(formalArg) {
    var privateProp = ...;
    // more creation logic
    return {
        publicProp : ...;
    };
}(actualArg));

P.S. Как указывает @Алексей Лебедев в своем ответе, одно различие между ними (возможно, единственное) заключается в том, что approach2Obj.constructor и approach3Obj.constructor будет другим. approach3Obj.constructor будет идентично Object, а approach2Obj.constructor будет анонимной функцией.

person Ted Hopp    schedule 19.04.2013
comment
Извините, в основном prop1 указывает на частные переменные. Логика функции может продолжаться и использовать эти переменные... Я обновлю, чтобы отразить это - person Umair; 19.04.2013
comment
@Umair - я не думаю, что мой ответ изменится. Подходы 2 и 3 в основном эквивалентны. - person Ted Hopp; 19.04.2013