Какой способ лучше всего подходит для создания объекта в JavaScript? Требуется ли var для свойства объекта?

177

До сих пор я видел три способа создания объекта в JavaScript. Какой способ лучше всего подходит для создания объекта и почему?

Я также видел, что во всех этих примерах ключевое слово varне используется перед свойством - почему? Не обязательно ли объявлять varперед именем свойства, так как упоминалось, что свойства являются переменными?

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

Первый способ:

function person(fname, lname, age, eyecolor){
  this.firstname = fname;
  this.lastname = lname;
  this.age = age;
  this.eyecolor = eyecolor;
}

myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");

Второй способ:

var Robot = {
  metal: "Titanium",
  killAllHumans: function(){
    alert("Exterminate!");
  }
};

Robot.killAllHumans();

Третий способ - объекты JavaScript, использующие синтаксис массива:

var NewObject = {};

NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }
Jamna
источник
2
«var» используется в зависимости от области видимости переменной, определяет глобальную или нет, найдите ее, и вы увидите разницу.
ДжекДжо,
80
если вы создаете роботов-убийц, всегда используйте var, пожалуйста .. опуская это делает их глобальными
mykhal
9
«var используется в зависимости от области видимости переменной» - это практика BAD - ее следует использовать независимо от того, в какой области видимости вы находитесь
treecoder
1
Как насчет метода Object.create():?
Макс
Было бы хорошо, если бы «как было сказано, свойства являются переменными», было бы разъяснено. Это кто"? Где это упоминается? Можете ли вы привести конкретную цитату?
user4642212

Ответы:

181

Нет лучшего способа, это зависит от вашего варианта использования.

  • Используйте способ 1, если вы хотите создать несколько похожих объектов. В вашем примере Person(имя следует начинать с заглавной буквы) называется функцией конструктора . Это похоже на классы на других языках ОО.
  • Используйте способ 2, если вам нужен только один объект (например, синглтон). Если вы хотите, чтобы этот объект наследовал от другого, тогда вы должны использовать функцию конструктора.
  • Используйте способ 3, если вы хотите инициализировать свойства объекта в зависимости от других его свойств или если у вас есть динамические имена свойств.

Обновление: как просили примеры для третьего способа.

Зависимые свойства:

Ниже не работает , как thisэто не относится к book. Невозможно инициализировать свойство значениями других свойств в литерале объекта:

var book = {
    price: somePrice * discount,
    pages: 500,
    pricePerPage: this.price / this.pages
};

вместо этого вы можете сделать:

var book = {
    price: somePrice * discount,
    pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;

Динамические имена свойств:

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

var name = 'propertyName';

// the property will be `name`, not `propertyName`
var obj = {
    name: 42
}; 

// same here
obj.name = 42;

// this works, it will set `propertyName`
obj[name] = 42;
Феликс Клинг
источник
1
спасибо за ваш ответ ... теперь я понял ваш первый пункт, мы можем использовать way1, если мы хотим что-то вроде этого myFather = new person ("John", "Doe", 50, "blue"); myMother = новый человек ("gazy", "Doe", 45, "brown"); myBrother = новый человек ("опрос", "Доу", 15, "синий");
Джамна
Я думаю, что вы имеете в виду obj [name] = 42. Верно?
Кит Пинсон
Я хотел бы отметить, что параметры 2 и 3 практически идентичны, просто вы назначаете свойства после создания объекта. Это то, что называется литеральной нотацией , потому что вы используете литерал объекта для создания своего объекта. Под капотом это на самом деле называется «новый объект ()». Вы можете прочитать больше об этом здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…
dudewad
Во втором случае, имеет ли смысл использовать оператор распространения ...для наследования от другого объекта?
упак. Ребенок
114

Существует несколько способов определения функции. Это полностью основано на вашем требовании. Ниже приведены несколько стилей:

  1. Конструктор объектов
  2. Литеральный конструктор
  3. Основанный на функции
  4. Основанный на прототипе
  5. Основанный на функции и прототипе
  6. На основе синглтона

Примеры:

  1. Конструктор объекта
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. Литеральный конструктор
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. Конструктор функций
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. Опытный образец
function Person(){};

Person.prototype.name = "Anand";
  1. Комбинация функция / прототип
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. одиночка
var person = new function(){
  this.name = "Anand"
} 

Вы можете попробовать это на консоли, если у вас есть путаница.

Ананд Дип Сингх
источник
Привет @Alex_Nabu - я уже поделился примерами в своем посте. Если вы все еще сталкиваетесь с какими-либо проблемами, пожалуйста, сообщите мне, я помогу вам.
Ананд Дип Сингх
1
не будет ли больше смысла строить каждый пример, дающий var personв конце один и тот же экземпляр? например, в конструкторе функции вы можете просто добавить var person = new Person("Anand"). и что случилось с на первый взгляд случайным использованием точки с запятой? : P
cregox
2
Это добавило бы ценность, объясняя плюсы и минусы каждого пути.
RayLoveless
10

Не существует «лучшего способа» создания объекта. Каждый способ имеет свои преимущества в зависимости от вашего варианта использования.

Шаблон конструктора (функция в паре с newоператором для его вызова) предоставляет возможность использования прототипного наследования, тогда как другие способы этого не делают. Так что, если вы хотите наследовать прототипы, тогда функция конструктора - отличный способ.

Однако, если вы хотите наследование прототипа, вы также можете использовать его Object.create, что делает наследование более очевидным.

Создание литерала объекта (ex var obj = {foo: "bar"};:) прекрасно работает, если у вас есть все свойства, которые вы хотите установить под рукой во время создания.

Для настройки свойств позже, NewObject.property1синтаксис, как правило, предпочтительнее, NewObject['property1']если вы знаете имя свойства. Но последнее полезно, когда у вас нет имени свойства заранее (например:) NewObject[someStringVar].

Надеюсь это поможет!

Джимбо
источник
6

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

Пример:

function Circle(radius) {
    this.radius = radius;
}
Circle.prototype.getCircumference = function() {
    return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
    return Math.PI * this.radius * this.radius;
}

Я не большой поклонник третьего метода, но он действительно полезен для динамического редактирования свойств, например var foo='bar'; var bar = someObject[foo];.

Даан Уилмер
источник
3

Есть много способов создать ваши объекты в JavaScript. Использование функции конструктора для создания объекта или буквенной нотации объекта использует много в JavaScript. Кроме того, создавая экземпляр Object, а затем добавляя к нему свойства и методы, существует три распространенных способа создания объектов в JavaScript.

Конструктивные функции

Существуют встроенные функции конструктора, которые мы все время от времени можем использовать, такие как Date (), Number (), Boolean () и т. Д., Все функции конструктора начинаются с заглавной буквы, в то же время мы можем создать собственную функцию конструктора в JavaScript как это:

function Box (Width, Height, fill) {  
  this.width = Width;  // The width of the box 
  this.height = Height;  // The height of the box 
  this.fill = true;  // Is it filled or not?
}  

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

var newBox = new Box(8, 12, true);  

Объектные литералы

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

var person = { 
    name: "Alireza",
    surname: "Dezfoolian"
    nose: 1,  
    feet: 2,  
    hands: 2,
    cash: null
};  

макетирования

После создания объекта вы можете создать для него больше членов, например, добавив цвет в наш бокс, мы можем сделать это:

Box.prototype.colour = 'red';
Алиреза
источник
2

В то время как многие люди здесь говорят, что нет лучшего способа создания объектов, существует разумное объяснение, почему существует так много способов создания объектов в JavaScript, начиная с 2019 года, и это связано с прогрессом JavaScript на разных итерациях. EcmaScript выпускает начиная с 1997 года.

До ECMAScript 5 существовало только два способа создания объектов: функция конструктора или литеральная запись (лучшая альтернатива new Object ()). С помощью функции конструктора нотации вы создаете объект, который может быть создан в нескольких экземплярах (с новым ключевым словом), в то время как буквенная нотация доставляет один объект, например, одиночный.

// constructor function
function Person() {};

// literal notation
var Person = {};

Независимо от используемого вами метода, объекты JavaScript являются просто свойствами пар ключ-значение:

// Method 1: dot notation
obj.firstName = 'Bob';

// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';

// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
    value: 'Bob',
    writable: true,
    configurable: true,
    enumerable: false
})

// Method 4: Object.defineProperties
Object.defineProperties(obj, {
  firstName: {
    value: 'Bob',
    writable: true
  },
  lastName: {
    value: 'Smith',
    writable: false
  }
});

В ранних версиях JavaScript единственным реальным способом имитации наследования на основе классов было использование функций конструктора. функция конструктора - это специальная функция, которая вызывается с ключевым словом 'new'. По соглашению, идентификатор функции пишется с заглавной буквы, но не требуется. Внутри конструктора мы ссылаемся на ключевое слово this, чтобы добавить свойства к объекту, который неявно создает функция конструктора. Функция конструктора неявно возвращает новый объект с заполненными свойствами обратно в вызывающую функцию неявно, если только вы явно не используете ключевое слово return и не возвращаете что-то еще.

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

    this.sayName = function(){
        return "My name is " + this.firstName + " " + this.lastName;
    }
} 

var bob = new Person("Bob", "Smith");
bob instanceOf Person // true

Существует проблема с методом sayName. Как правило, в языках программирования на основе объектно-ориентированных классов вы используете классы как фабрики для создания объектов. Каждый объект будет иметь свои собственные переменные экземпляра, но у него будет указатель на методы, определенные в проекте класса. К сожалению, при использовании функции конструктора JavaScript каждый раз, когда она вызывается, она определяет новое свойство sayName для вновь создаваемого объекта. Таким образом, у каждого объекта будет свое уникальное свойство sayName. Это будет потреблять больше ресурсов памяти.

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

Если у вас есть родительский объект, и родительский объект разделяет многие свойства дочернего элемента, тогда дочерний элемент должен наследовать эти свойства. До ES5 это было сделано следующим образом:

function Parent(eyeColor, hairColor) {
    this.eyeColor = eyeColor;
    this.hairColor = hairColor;
}

Parent.prototype.getEyeColor = function() {
  console.log('has ' + this.eyeColor);
}

Parent.prototype.getHairColor = function() {
  console.log('has ' + this.hairColor);
}

function Child(firstName, lastName) {
  Parent.call(this, arguments[2], arguments[3]);
  this.firstName = firstName;
  this.lastName = lastName;
}

Child.prototype = Parent.prototype;

var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair

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

ECMAScript 5 представил Object.create для решения вышеупомянутой ошибки в функции конструктора для создания объекта. Метод Object.create () СОЗДАЕТ новый объект, используя существующий объект в качестве прототипа вновь созданного объекта. Поскольку новый объект создан, у вас больше не возникает проблема, когда изменение дочернего свойства в цепочке прототипов изменит ссылку родителя на это свойство в цепочке.

var bobSmith = {
    firstName: "Bob",
    lastName: "Smith",
    sayName: function(){
      return "My name is " + this.firstName + " " + this.lastName;
    }
}

var janeSmith = Object.create(bobSmith, {
    firstName : {  value: "Jane" }
})

console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.

До ES6 здесь использовался общий шаблон для создания конструкторов функций и Object.create:

const View = function(element){
  this.element = element;
}

View.prototype = {
  getElement: function(){
    this.element
  }
}

const SubView = function(element){
  View.call(this, element);
}

SubView.prototype = Object.create(View.prototype);

Теперь Object.create в сочетании с функциями конструктора широко используются для создания и наследования объектов в JavaScript. Тем не менее, ES6 представил концепцию классов, которые в основном являются синтаксическим сахаром по сравнению с существующим наследованием на основе прототипов JavaScript. Синтаксис класса не вводит новую объектно-ориентированную модель наследования в JavaScript. Таким образом, JavaScript остается прототипом языка.

Классы ES6 значительно упрощают наследование. Нам больше не нужно вручную копировать функции-прототипы родительского класса и сбрасывать конструктор дочернего класса.

// create parent class
class Person {
  constructor (name) {
    this.name = name;
  }
}

// create child class and extend our parent class
class Boy extends Person {
  constructor (name, color) {
    // invoke our parent constructor function passing in any required parameters
    super(name);

    this.favoriteColor = color;
  }
}

const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue

В целом, эти 5 различных стратегий создания объектов в JavaScript совпали с развитием стандарта EcmaScript.

Донато
источник
0

Конечно, есть лучший способ. Объекты в javascript имеют перечисляемые и не перечисляемые свойства.

var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]

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

Хорошо, во-первых, давайте посмотрим, что является лучшим способом:

var new_object = Object.create(null)

new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc

console.log("toString" in new_object) //=> false

В приведенном выше примере журнал выдаст false.

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

//Object constructor
var object = new Object();

console.log("toString" in object); //=> true

//Literal constructor
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 

console.log("toString" in person); //=> true

//function Constructor
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
}

var person = new Person ('landi')

console.log("toString" in person); //=> true

//Prototype
function Person(){};

Person.prototype.name = "Anand";

console.log("toString" in person); //=> true

//Function/Prototype combination
function Person2(name){
  this.name = name;
} 

Person2.prototype.getName = function(){
  return this.name
}

var person2 = new Person2('Roland')

console.log("toString" in person2) //=> true

Как вы можете видеть выше, все примеры записывают в true. Что означает, что если у вас есть случай, когда у вас есть for inцикл, чтобы увидеть, есть ли у объекта свойство, это может привести к неправильным результатам.

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

 for (var property in new_object) {
  if (new_object.hasOwnProperty(property)) {
    // ... this is an own property
  }
 }
Роли Роли
источник
0

В основном есть 3 способа создания объектов:

Самый простой из них - использование литералов объектов .

const myObject = {}

Хотя этот метод самый простой, но имеет недостаток, т. Е. Если ваш объект имеет поведение (функции в нем), то в будущем, если вы захотите внести в него какие-либо изменения, вам придется изменить его во всех объектах. .

Так что в этом случае лучше использовать функции Factory или Constructor.

Фабричные функции - это те функции, которые возвращают object.eg-

function factoryFunc(exampleValue){
   return{
      exampleProperty: exampleValue 
   }
}

Функции конструктора - это те функции, которые присваивают свойства объектам с помощью ключевого слова this.

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
Шивам Бансал
источник