ฉันควรใช้อ็อบเจกต์ลิเทอรัลหรือฟังก์ชันคอนสตรัคเตอร์หรือไม่?


94

ฉันเริ่มสับสนว่าควรจะสร้างวัตถุในจาวาสคริปต์ด้วยวิธีใด ดูเหมือนว่ามีอย่างน้อยสองวิธี หนึ่งคือการใช้สัญกรณ์ตามตัวอักษรของวัตถุในขณะที่อีกอันใช้ฟังก์ชันการก่อสร้าง มีข้อได้เปรียบเหนือข้ออื่น ๆ หรือไม่?


1
คำตอบที่ดีที่สุด: stackoverflow.com/questions/4597926/… - โดยสรุปคุณสามารถตั้งค่าฟังก์ชันเพื่อสร้างอินสแตนซ์ในรูปแบบสัญกรณ์ตามตัวอักษรได้เช่นกัน การทำเช่นนี้แต่ละอินสแตนซ์มีวิธีการทั้งหมดในขณะที่ตัวสร้างอินสแตนซ์ทั้งหมดอ้างถึงเมธอดต้นแบบ ตัวสร้างคือมีประสิทธิภาพของหน่วยความจำที่ดีขึ้น
Federico

หากหน่วยความจำไม่ใช่ปัญหาการเข้าถึงคุณสมบัติตัวอักษรวัตถุจะเร็วขึ้นหลายขนาด - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

คำตอบ:


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
คำอธิบายที่ดี แต่สิ่งที่เกี่ยวกับการวางฟังก์ชันในตัวอักษรของวัตถุ ฉันเคยเห็นสิ่งนี้มาก่อน จริงๆแล้วโพสต์ด้านล่างมีตัวอย่างนี้
chobo

23
หากคุณรวมนิยามฟังก์ชันเป็นส่วนหนึ่งของตัวอักษรของอ็อบเจ็กต์หรือใช้this.fn = function ...วิธีการในตัวสร้างอินสแตนซ์อ็อบเจ็กต์แต่ละรายการของคุณจะมีสำเนาฟังก์ชัน เมื่อใช้แนวทางต้นแบบคุณจะแนบแต่ละฟังก์ชันเพียงครั้งเดียว: ฟังก์ชันเหล่านี้จะถูกสืบทอดโดยอินสแตนซ์ผ่านการสืบทอดต้นแบบ
Ates Goral

14
ฉันเชื่อว่าคุณพลาดสิ่งสำคัญ เฉพาะฟังก์ชันตัวสร้างเท่านั้นที่สามารถให้สมาชิกส่วนตัวเช่นเดียวกับสมาชิกสาธารณะ (การห่อหุ้ม) ในวัตถุตามตัวอักษร - ทั้งหมดเป็นแบบสาธารณะ
Royi Namir

อะไรจะเป็นวิธีที่ดีกว่าสำหรับเกมเอนจิ้น? ฉันใช้วิธีการสร้าง แต่ต้นแบบของฉันไม่สามารถเข้าถึงข้อมูลตัวสร้างได้
zachdyer

90

โดยพื้นฐานแล้วมันจะเดือดขึ้นถ้าคุณต้องการหลายอินสแตนซ์ของวัตถุของคุณหรือไม่ วัตถุที่กำหนดด้วยตัวสร้างช่วยให้คุณมีหลายอินสแตนซ์ของออบเจ็กต์นั้น โดยพื้นฐานแล้ว Object literals นั้นมีตัวแปร / วิธีการที่เป็นแบบสาธารณะทั้งหมด

// 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()ฟังก์ชั่นและสร้าง วากยสัมพันธ์ของ Object Literal นั้นสร้างและสร้างวัตถุได้ทันทีและด้วยเหตุ__prototype__นี้จึงเป็นObjectวัตถุและจะสามารถเข้าถึงคุณสมบัติและวิธีการทั้งหมดของObjectวัตถุและมันจะมีการเข้าถึงคุณสมบัติและวิธีการของจากมุมมองรูปแบบการออกแบบอย่างเคร่งครัดควรใช้ Object literal อย่างง่ายเพื่อจัดเก็บข้อมูลอินสแตนซ์เดียว

.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 ใช้ตัวแปรส่วนตัว อย่างหลังอาจมีประโยชน์ในบางกรณี บ่อยครั้งที่ Object literal เพียงพอและเป็นวิธีที่ดีและสะอาดในการสร้าง JS-object


อะไรคือความแตกต่างระหว่างฟังก์ชันและวิธีการ? ฉันมาจากพื้นหลัง ac # ดังนั้นสำหรับฉันฟังก์ชันจึงเป็นแบบสแตนด์อโลนและวิธีการเป็นเพียงฟังก์ชันที่เป็นส่วนหนึ่งของคลาส
chobo

1
มีไม่ได้ว่าแตกต่างกันมากดูตัวอย่างweb-source.net/javascript_tutorial/... จริงๆแล้วใน DOMscripting (ฝั่งไคลเอ็นต์ js ในเบราว์เซอร์) ฟังก์ชันทั้งหมดจะกลายเป็นเมธอดของ window-object (global namespace) ฉันจะบอกว่า (คุณสามารถระบุฟังก์ชัน 'แบบสแตนด์อโลน' ทั้งหมดเป็นหน้าต่างได้ [somefunction]
KooiInc

5

ป้อนคำอธิบายภาพที่นี่

คุณต้องการอินสแตนซ์เดียวของออบเจ็กต์สำหรับเพจ - Literal

คุณต้องการเพียงแค่ถ่ายโอนข้อมูลเช่น DTO ออบเจ็กต์ง่ายๆ GET SET: - Literal

คุณต้องการสร้างวัตถุจริงด้วยลักษณะการทำงานของวิธีการหลายอินสแตนซ์ - ฟังก์ชันตัวสร้างปฏิบัติตามหลักการ OOP การสืบทอด: - ฟังก์ชันตัวสร้าง

ด้านล่างนี้คือวิดีโอ youtube ซึ่งอธิบายรายละเอียดว่าอะไรคือตัวอักษรฟังก์ชันตัวสร้างคืออะไรและแตกต่างกันอย่างไร

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


1

ไปกับ object literal มันกระชับมากขึ้นและขยายได้ดีขึ้นด้วยการแนะนำค่าเริ่มต้น


คุณสร้างตัวแปรส่วนตัวในตัวอักษรของวัตถุได้อย่างไร?
EhevuTov

คุณทำไม่ได้จริงๆมันไม่เกี่ยวข้องกับคำถามเดิมดังนั้นฉันจะให้ลิงค์: javascript.crockford.com/private.html
ทอม

1
จริงๆแล้วมันมีความเกี่ยวข้องเนื่องจากมีความแตกต่างกันมีเหตุผลที่จะใช้อย่างใดอย่างหนึ่งขึ้นอยู่กับสถานการณ์บางอย่าง ในกรณีนี้คุณต้องการตัวแปรส่วนตัวหรือไม่ คุณสามารถสร้างตัวแปรส่วนตัวในลิเทอรัลได้โดยการสร้างฟังก์ชันปิดในลิเทอรัลของคุณก่อน แต่ในความคิดของฉันดูน่าเกลียดกว่ามากและอ่านยาก
EhevuTov

ฉันได้รับการแก้ไขการอ่านคำถามเดิมของฉันคือ chobo กำลังถามเกี่ยวกับวิธีการส่งผ่านตัวแปรไปยังตัวสร้างในรายการพารามิเตอร์เทียบกับพารามิเตอร์ลิเทอรัลออบเจ็กต์เดี่ยว
ทอม

1

ตามที่กล่าวไว้ในhttps://www.w3schools.com/js/js_object_definition.asp

การใช้ตัวอักษรวัตถุที่คุณทั้งสองกำหนดและสร้าง , หนึ่งวัตถุในหนึ่ง คำสั่ง

นอกจากนี้

Object literal จะสร้างวัตถุเดียวเท่านั้น บางครั้งเราชอบที่จะมีประเภทวัตถุที่สามารถใช้สร้างวัตถุประเภทเดียวได้หลายชิ้น


0

ฟังก์ชันตัวสร้าง Object () ช้าลงเล็กน้อยและมีรายละเอียดมากกว่า ด้วยเหตุนี้วิธีที่แนะนำในการสร้างวัตถุใหม่ใน JavaScript คือการใช้สัญกรณ์ตามตัวอักษร

Udacity JavaScript เชิงวัตถุ


0

ที่จริงแล้ว methinks เราสามารถมีเมธอดส่วนตัวในอ็อบเจกต์ลิเทอรัล พิจารณาโค้ดด้านล่าง:

var myObject = {

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

}

เรื่องของรสนิยม แต่ฉันชอบที่จะใช้ตัวอักษรที่เป็นไปได้


-1

// ตัวสร้าง Object Literal และ Object

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 literal ประกาศอยู่ที่ไหนในตัวอย่างของคุณ
JohnnyQ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.