Чи повинен я використовувати об'єкти-літерали чи функції конструктора?


94

Я заплутався у тому, яким чином слід створювати об’єкт у javascript. Здається, існує як мінімум два способи. Один - використовувати буквальні нотації об’єкта, тоді як інший використовує конструктивні функції. Чи є перевага одного над іншим?


1
Найкраща відповідь: stackoverflow.com/questions/4597926/… - Таким чином, ви також можете налаштувати функцію для створення екземплярів із буквальних позначень. Виконуючи це, кожен екземпляр несе всі методи, тоді як у конструкторі всі екземпляри посилаються на методи-прототипи. Тобто конструктор має кращі показники пам'яті.
Федеріко

Якщо пам’ять не є проблемою об'єктного доступу до літеральних
Даніель Соколовський

Відповіді:


131

Якщо у вас немає поведінки, пов'язаної з об'єктом (тобто, якщо об'єкт - це просто контейнер для даних / стану), я б використав літерал об'єкта.

var data = {
    foo: 42,
    bar: 43
};

Застосовуйте принцип KISS . Якщо вам не потрібно нічого, крім простого контейнера даних, перейдіть з простим літералом.

Якщо ви хочете додати поведінку до свого об'єкта, ви можете піти з конструктором і додати методи до об'єкта під час побудови або надати своєму класу прототип.

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

Клас, подібний до цього, також діє як схема для вашого об'єкта даних: тепер у вас є якийсь договір (через конструктор), які властивості об'єкт ініціалізує / містить. Вільний літерал - це просто аморфний відтінок даних.

Ви також можете мати зовнішню verifyфункцію, яка діє на звичайний старий об'єкт даних:

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

Однак це не є сприятливим щодо інкапсуляції: в ідеалі всі дані + поведінка, пов'язані з суттю, повинні жити разом.


12
Чудове пояснення, але як бути з розміщенням функцій в буквальному об'єкті? Я бачив це раніше. Насправді приклад нижче є прикладом цього.
чобо

23
Якщо ви включите визначення функції як частину об’єкта-літералу або this.fn = function ...застосуєте підхід у конструкторі, кожен екземпляр об’єкта матиме власні копії функцій. Використовуючи підхід прототипу, ви приєднуєте кожну функцію один раз і лише один раз: вони успадковуватимуться екземплярами через прототипне успадкування.
Ates Goral

14
Я вірю, що ти пропустив важливу річ. лише функція конструктора може надавати приватних членів, а також загальнодоступних членів (інкапсуляція). в об’єктному буквалі - всі вони є загальнодоступними.
Рої Намір,

Що було б кращим способом вибрати ігровий движок? Я використовував метод конструктора, але мої прототипи не мають доступу до даних конструктора.
zachdyer

90

По суті, це зводиться до того, потрібні вам численні екземпляри вашого об’єкта чи ні; об'єкт, визначений конструктором, дозволяє мати кілька екземплярів цього об'єкта. Об’єктивні літерали - це в основному одиночні елементи зі змінними / методами, які є загальнодоступними.

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line

1
Це дуже хороший момент, про який слід пам’ятати, приймаючи рішення. Дякую.
zkent

З мого досвіду, саме це робить різницю. Чудовий наочний приклад.
Ефір

9

Інший спосіб створення об'єктів рівномірним способом - це використання функції, яка повертає об'єкт:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

Оскільки функції в JavaScript є закриттями, ми можемо використовувати приватні змінні та методи і уникати new.

Від http://javascript.crockford.com/private.html до приватних змінних у JavaScript.


7

У наведеному нижче коді показано три способи створення об’єкта, синтаксис літературного об'єкта, конструктор функцій та Object.create(). Об'єктний буквальний синтаксис просто створює та об'єктує на льоту і як такий __prototype__є Objectоб'єктом, і він матиме доступ до всіх властивостей та методівObject . Суворо з точки зору дизайну, для зберігання єдиного екземпляра даних слід використовувати простий літеральний об’єкт.

Конструктор функцій має спеціальну властивість з назвою .prototype. Це властивість стане __prototype__будь-яким об'єктом, створеним конструктором функції. Усі властивості та методи, додані до .prototypeвластивості конструктора функцій, будуть доступними для всіх створених ним об'єктів. Конструктор слід використовувати, якщо вам потрібні кілька примірників даних або вимагає поведінки від вашого об'єкта. Зверніть увагу, конструктор функцій також найкраще використовувати, коли ви хочете імітувати приватний / публічний шаблон розвитку. Не забудьте поставити всі спільні методи .prototypeтак, щоб вони не створювались у кожному екземплярі об'єкта.

Створення об'єктів за Object.create()допомогою об'єктного літералу використовується як __prototype__об'єктів, створених цим методом. Всі властивості та методи, додані до об’єкта-літералу, будуть доступні для всіх об’єктів, створених із нього через справжнє прототипне успадкування. Це мій найкращий метод.

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);

1
Оскільки ви оголосили функцію всередині літералу об'єкта. Чи означає це, що коли ви створюєте об'єкт за Object.createдопомогою функції всередині літералу, буде унікальним для кожного екземпляра?
JohnnyQ

6

Це залежить від того, що ви хочете зробити. Якщо ви хочете використовувати (напів-) приватні змінні або функції у своєму об'єкті, функція конструктора - це спосіб зробити це. Якщо ваш об’єкт містить лише властивості та методи, об’єктний літерал - це нормально.

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

Тепер метод multiply5в myObjі SomeLiteralробити те ж саме. Єдина відмінність полягає в тому, що myObj використовує приватну змінну. Останні можуть бути корисними в деяких випадках. У більшості випадків літералу Об’єкту є достатнім і приємним і чистим способом створення JS-об’єкта.


Яка різниця між функцією та методом? Я походжу з ac # background, тому для мене функція є автономною, а метод - це просто функція, яка є частиною класу.
chobo

1
Існує не така велика різниця, див., Наприклад, web-source.net/javascript_tutorial/… . Насправді, у DOMscripting (клієнтська сторона js у браузері), усі функції стають методами вікна-об’єкта (глобального простору імен), який я б сказав (ви можете адресувати всі «автономні» функції як вікно. [
Деяка

5

введіть тут опис зображення

Хочете одиничний екземпляр об’єкта для сторінки - буквальний.

Ви хочете просто передавати дані, такі як об'єкти DTO, просто GET SET: - Буквальний

Ви хочете створити реальні об'єкти з поведінкою методів, декількома екземплярами - функція конструктора, дотримуйтесь принципів ООП, успадкування: - функції конструктора.

Нижче наведено відео з YouTube, яке докладно пояснює, що таке літерал, що таке функції конструктора та чим вони відрізняються одна від одної.

https://www.youtube.com/watch?v=dVoAq2D3n44


1

Перейдіть з об'єктом буквально, він стає меншим і краще розширюється із введенням початкових значень.


Як ви створюєте приватні змінні в літералі об'єкта?
EhevuTov

Ви не можете на самому справі, це не має відношення до первісного питання , так що я просто хочу , щоб дати вам посилання: javascript.crockford.com/private.html
Том

1
Насправді це актуально, оскільки там, де є різниця, є причина використовувати ту чи іншу, залежно від певних ситуацій; у цьому випадку це було б ви хочете приватні змінні чи ні. Ви можете створити приватні змінні в літералі, спочатку створивши функцію закриття у вашому літералі, але це, на мій погляд, набагато потворніше і важко читається.
EhevuTov

Я стою виправлений, моє початкове прочитання запитання полягало в тому, що Чобо запитував про те, як передати змінні конструктору, як у списку параметрів проти одного літерального параметра об'єкта.
Том

1

Як згадано в https://www.w3schools.com/js/js_object_definition.asp

З допомогою литерала об'єкта, ви обидва визначити і створити , один об'єкт в одному заяві.

Також

Об'єкт буквально створює лише один об'єкт. Іноді нам подобається мати об’єктний тип, який можна використовувати для створення багатьох об’єктів одного типу.



0

Насправді, міркуючи, ми можемо мати приватні методи в об'єктних літералах. Розглянемо код нижче:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

Питання смаку, але я вважаю за краще використовувати об'єктивні літерали там, де це можливо.


-1

// Об’єктний літерал та конструктор об’єктів

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 

1
Де у вашому прикладі оголошено літерал Object?
JohnnyQ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.