ทำความเข้าใจกับความแตกต่างระหว่าง Object.create () และ SomeFunction ใหม่ ()


392

ฉันเพิ่งสะดุดกับObject.create()วิธีการใน JavaScript และฉันพยายามที่จะอนุมานว่ามันแตกต่างจากการสร้างตัวอย่างใหม่ของวัตถุด้วยnew SomeFunction()และเมื่อคุณต้องการใช้หนึ่งเหนืออื่น ๆ

ลองพิจารณาตัวอย่างต่อไปนี้:

var test = {
  val: 1,
  func: function() {
    return this.val;
  }
};
var testA = Object.create(test);

testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2

console.log('other test');
var otherTest = function() {
  this.val = 1;
  this.func = function() {
    return this.val;
  };
};

var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1 
console.log(otherTestB.val); // 2

console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2

โปรดสังเกตว่ามีการสังเกตพฤติกรรมเดียวกันในทั้งสองกรณี สำหรับฉันแล้วความแตกต่างหลักระหว่างสองสถานการณ์นี้คือ:

  • วัตถุที่ใช้ในObject.create()รูปแบบต้นแบบของวัตถุใหม่จริง ๆ ในขณะที่new Function()จากคุณสมบัติ / ฟังก์ชั่นที่ประกาศไว้ไม่ได้สร้างต้นแบบ
  • คุณไม่สามารถสร้างการปิดด้วยObject.create()ไวยากรณ์เช่นเดียวกับที่คุณใช้กับไวยากรณ์การทำงาน นี่เป็นตรรกะที่กำหนดขอบเขตประเภท lexical (vs block) ของ JavaScript

ข้อความข้างต้นถูกต้องหรือไม่ และฉันก็ขาดอะไรไป? เมื่อไหร่ที่คุณจะใช้อันอื่น

แก้ไข: ลิงก์ไปยังรุ่น jsfiddle ของตัวอย่างโค้ดด้านบน: http://jsfiddle.net/rZfYL/


2
ดูเพิ่มเติมที่การใช้“ Object.create” แทน“ new”
Bergi

คำตอบ:


247

วัตถุที่ใช้ใน Object.create จะสร้างต้นแบบของวัตถุใหม่โดยที่ในรูปแบบ Function () ใหม่นั้นคุณสมบัติ / หน้าที่ที่ประกาศไว้จะไม่ได้สร้างต้นแบบขึ้นมา

ใช่Object.createสร้างวัตถุที่สืบทอดโดยตรงจากสิ่งที่ส่งผ่านเป็นอาร์กิวเมนต์แรก

ด้วยฟังก์ชั่นคอนสตรัควัตถุที่สร้างขึ้นใหม่จะสืบทอดมาจากต้นแบบของคอนสตรัคเตอร์เช่น

var o = new SomeConstructor();

ในตัวอย่างข้างต้นสืบทอดโดยตรงจากoSomeConstructor.prototype

มีความแตกต่างอยู่ที่นี่กับObject.createคุณสามารถสร้างวัตถุที่ไม่ได้รับมรดกจากสิ่งที่Object.create(null);ในมืออื่น ๆ ถ้าคุณตั้งค่าวัตถุที่สร้างขึ้นใหม่จะได้รับมรดกจากSomeConstructor.prototype = null;Object.prototype

คุณไม่สามารถสร้างการปิดด้วยไวยากรณ์ Object.create เช่นเดียวกับที่คุณใช้กับไวยากรณ์การทำงาน นี่เป็นตรรกะที่กำหนดขอบเขตประเภท lexical (vs block) ของ JavaScript

คุณสามารถสร้างการปิดเช่นใช้อาร์กิวเมนต์ตัวอธิบายคุณสมบัติ:

var o = Object.create({inherited: 1}, {
  foo: {
    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
  }
});

o.foo; // "foobar"

โปรดทราบว่าฉันกำลังพูดถึงวิธี ECMAScript 5th Edition Object.createไม่ใช่ shim ของ Crockford

วิธีการเริ่มต้นที่จะนำมาใช้ในเบราว์เซอร์ล่าสุดตรวจสอบตารางความเข้ากันได้นี้


2
@CMS 2 คำถาม 1) ห่วงโซ่ขอบเขตบน Object.create (null) ยังคงสิ้นสุดที่ขอบเขตส่วนกลาง (เช่น 'หน้าต่าง' ในเบราว์เซอร์) หรือไม่หรือสิ้นสุดเอง 2) มันยังไม่ชัดเจนสำหรับฉันว่าทำไม Object.create ถูกนำเสนอ (เช่นคุณลักษณะที่ขาดหายไปซึ่งสิ่งนี้ได้รับการแก้ไขแล้ว) และทำไมเราจึงใช้มันแทน Function ใหม่ ();
Matt

9
@ Matt, 1) ห่วงโซ่ขอบเขตไม่ได้จริงๆที่เกี่ยวข้องกับแนวคิดที่นี่โซ่ขอบเขตที่เกี่ยวข้องกับความละเอียดระบุเช่น: วิธีfoo;การแก้ไขในปัจจุบันสภาพแวดล้อมคำศัพท์ 2) เพื่อให้วิธีง่าย ๆ ในการใช้การสืบทอดมันเป็นโครงสร้างที่ทรงพลังจริงๆ IMO ฉันจะใช้เพราะมันเรียบง่ายและมีน้ำหนักเบา แต่สำหรับรหัสการผลิตเรายังคงต้องรอสักครู่จนกว่า ES5 จะรองรับอย่างกว้างขวาง เกี่ยวกับคุณลักษณะที่หายไปความเป็นจริงของการสร้าง "เก่าแก่" วัตถุที่Object.create(null);หายไปก็มีประโยชน์จริงๆที่จะใช้ความน่าเชื่อถือกัญชาเหมือนตารางวัตถุ ...
CMS

@CMS ขอบคุณ ดังนั้นเมื่อคุณสร้างวัตถุโดยใช้ 'Object.create' คุณจะสามารถเลือกวัตถุที่ควรเป็นต้นแบบได้
Anshul

@CMS ตกลงดังนั้นObject.create(null)หมายความว่าคุณไม่จำเป็นต้องใช้hasOwnProperty()อึเมื่อทำซ้ำเพราะทำให้ไม่ได้รับมรดกเลย ??? ฉันชอบที่ - ขอบคุณ แน่นอนว่าทุกคนจะยังคงทำhasOwnPropertyเพราะไม่ใช่ทุกคนที่จะใช้Object.create(null)ดังนั้นฉันไม่แน่ใจว่ามันเป็นผลประโยชน์ที่แท้จริง ... จนถึงตอนนี้ฉันก็พบว่า "ผลประโยชน์" อื่น ๆ ที่Object.create()ไม่น่าเชื่อถืออย่างสมบูรณ์
949300

425

พูดง่าย ๆ ก็new XคือการObject.create(X.prototype)ใช้งานconstructorฟังก์ชั่นเพิ่มเติม (และให้constructorโอกาสกับreturnวัตถุจริงที่ควรเป็นผลลัพธ์ของการแสดงออกแทนthis)

แค่นั้นแหละ. :)

คำตอบที่เหลือแค่สับสนเพราะเห็นได้ชัดว่าไม่มีใครอ่านคำนิยามของnewทั้งสอง ;)


23
+1 เรียบง่ายและชัดเจน! (แม้ว่า Object.create (null) ดูเหมือนจะเป็นตัวเลือกที่ดี - น่าจะพูดถึงเรื่องนั้น)
949300

ทำให้มันง่ายนั่นคือหนทางที่จะไป
Bill

นั่นเป็นเพียงคำถาม "รอดังนั้นฟังก์ชั่นจึงมีต้นแบบเช่นกันความสัมพันธ์ระหว่างสิ่งเหล่านั้นกับต้นแบบวัตถุคืออะไร"
Qwertie

3
@Qwertie: ใน JS ทุกอย่างเป็นวัตถุ :) พวกเขาคัดลอกมาจาก Java ที่คัดลอกมาจาก SmallTalk ที่ไปจนสุดด้วย มันเป็นกรณีที่ดีของ“ การเกิดขึ้น” ทำให้ชีวิตง่ายขึ้นโดยทั่วไป
Evi1M4chine

@ Evi1M4chine จริง ๆ ใน Java ฟังก์ชั่นไม่ใช่วัตถุ (และไม่ใช่แบบดั้งเดิมสำหรับเรื่องนั้น) ... และวัตถุไม่มีต้นแบบดังนั้นการเปรียบเทียบจึงดูไม่เหมาะสม ความจริงที่ว่า JS ทำงานแตกต่างจากภาษา OO ยอดนิยมอื่น ๆ เป็นแหล่งของความสับสนที่สำคัญ (และไม่ได้ช่วยให้เบราว์เซอร์ไม่ได้ให้วิธีที่ง่ายในการมองเห็นเครือข่ายของวัตถุรวมถึงฟังก์ชั่นและต้นแบบ) PS ฉันพบว่าลิงก์นี้มีประโยชน์: davidwalsh.name/javascript-objects-deconstruction
Qwertie

204

นี่คือขั้นตอนที่เกิดขึ้นภายในสำหรับการโทรทั้งสอง:
(คำแนะนำ: ความแตกต่างเพียงอย่างเดียวคือในขั้นตอนที่ 3)


new Test():

  1. สร้างnew Object()obj
  2. กำหนดobj.__proto__เป็นTest.prototype
  3. return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value

Object.create( Test.prototype )

  1. สร้างnew Object()obj
  2. กำหนดobj.__proto__เป็นTest.prototype
  3. return obj;

ดังนั้นโดยทั่วไปObject.createจะไม่เรียกใช้ตัวสร้าง


@ เรย์ดังนั้นการใช้ object.create เราตัวอักษรมีคุณสมบัติของฟังก์ชั่นที่กล่าวถึงในฟังก์ชั่นการสร้าง?

@sortnoun ตราบใดที่คุณสมบัติเป็นแบบส่วนตัวและไม่ได้ระบุไว้ในต้นแบบใช่พวกเขาจะไม่ถูกสืบทอดและคุณจะไม่มีพวกเขาในวัตถุใหม่ (และฉันจะเพิ่มคุณสามารถคาดหวังว่าจะได้รับคุณสมบัติต้นแบบในที่สุด จากผู้ปกครองเพียงเมื่อผู้สร้างผู้ปกครองได้รับการดำเนินการอย่างน้อยหนึ่งครั้ง)
Kamafeather

เช่นเดียวกับฟังก์ชั่นคอนสตรัคเตอร์ส่วนใหญ่วิธีการที่กำหนดไว้ภายในวัตถุที่ส่งคืนnewโดยทั่วไปมีฟังก์ชั่นทั้งหมดที่ซ้ำกันในขณะที่Object.createไม่ได้
SparK

61

ให้ฉันพยายามอธิบาย (เพิ่มเติมเกี่ยวกับบล็อก ):

  1. เมื่อคุณเขียนCarคอนสตรัคvar Car = function(){}นี้เป็นวิธีที่สิ่งที่อยู่ภายใน: แผนภาพของโซ่ต้นแบบเมื่อสร้างวัตถุจาวาสคริปต์ เรามีหนึ่ง{prototype}ลิงค์ที่ซ่อนอยู่Function.prototypeซึ่งไม่สามารถเข้าถึงและเป็นหนึ่งในprototypeการเชื่อมโยงไปCar.prototypeซึ่งสามารถเข้าถึงได้และมีที่เกิดขึ้นจริงของconstructor Carทั้งสอง Function.prototype และ Car.prototype Object.prototypeได้ซ่อนเชื่อมโยงไปยัง
  2. เมื่อเราต้องการที่จะสร้างวัตถุสองเทียบเท่าโดยใช้การnewดำเนินการและcreateวิธีการแล้วที่เราต้องทำเช่นนี้และHonda = new Car(); เกิดอะไรขึ้น?Maruti = Object.create(Car.prototype)แผนภาพของโซ่ต้นแบบสำหรับวิธีการสร้างวัตถุที่แตกต่างกัน

    Honda = new Car();- เมื่อคุณสร้างวัตถุเช่นนั้นซ่อนนี้คุณสมบัติคือชี้ไปที่{prototype} Car.prototypeดังนั้นที่นี่{prototype}วัตถุของฮอนด้าจะเป็นเสมอCar.prototype- เราไม่มีตัวเลือกในการเปลี่ยนแปลง{prototype}คุณสมบัติของวัตถุ ถ้าฉันต้องการเปลี่ยนต้นแบบของวัตถุที่สร้างขึ้นใหม่ของเรา
    Maruti = Object.create(Car.prototype)- เมื่อคุณสร้างวัตถุเช่นนี้คุณจะมีตัวเลือกพิเศษในการเลือก{prototype}คุณสมบัติของวัตถุ ถ้าคุณต้องการให้ Car.prototype เป็นเครื่องหมาย{prototype}ก็ให้ส่งผ่านพารามิเตอร์ในฟังก์ชัน หากคุณไม่ต้องการใด ๆ{prototype}สำหรับวัตถุของคุณแล้วคุณสามารถส่งผ่านไปเช่นนี้nullMaruti = Object.create(null)

สรุป - โดยใช้วิธีการที่Object.createคุณมีอิสระในการเลือก{prototype}คุณสมบัติวัตถุของคุณ ในnew Car();คุณไม่มีอิสระ

วิธีที่ต้องการใน JavaScript OO:

สมมติว่าเรามีสองวัตถุและab

var a = new Object();
var b = new Object();

ตอนนี้สมมติว่าaมีวิธีการบางอย่างที่bต้องการเข้าถึงด้วย สำหรับสิ่งนั้นเราต้องการการสืบทอดวัตถุ ( aควรเป็นต้นแบบของbเฉพาะเมื่อเราต้องการเข้าถึงวิธีการเหล่านั้น) หากเราตรวจสอบต้นแบบของaและแล้วเราจะพบว่าพวกเขาแบ่งปันต้นแบบbObject.prototype

Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).

ปัญหา -เราต้องการวัตถุaเป็นเครื่องต้นแบบของbแต่ที่นี่เราได้สร้างวัตถุกับต้นแบบ b โซลูชัน -แนะนำ ECMAScript 5 เพื่อให้สามารถรับมรดกดังกล่าวได้อย่างง่ายดาย ถ้าเราสร้างวัตถุเช่นนี้:Object.prototypeObject.create()b

var b = Object.create(a);

แล้ว

a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)

ดังนั้นหากคุณกำลังทำสคริปต์เชิงวัตถุนั้นObject.create()มีประโยชน์มากสำหรับการสืบทอด


ดังนั้นมันค่อนข้างคล้ายกับการสร้างวัตถุโดยไม่มีการเรียกใช้ตัวสร้าง เราจะเพลิดเพลินไปกับผลประโยชน์ทั้งหมดของชั้นเรียน อินสแตนซ์ obj ของ Class จะเป็นจริงเช่นกัน แต่เราไม่ได้เรียกใช้ฟังก์ชัน Class ผ่านทางใหม่
Praveen

@Anshul คุณพูดว่าa.isPrototypeOf(b);จะคืนfalseสิ่งที่ถูกต้องเพราะวัตถุทั้งสองแตกต่างกันและชี้ไปยังหน่วยความจำที่แตกต่างกัน วิธีที่ถูกต้องในการทำเช่นนี้กับnewผู้ดำเนินการอยู่ที่นี่ - jsfiddle.net/167onunp
Sagar Karira

ทำไมคุณไม่ตั้งค่าคุณสมบัติต้นแบบของ b เป็น a แทนที่จะทำเช่นนี้?
Amnestic

ชอบบทความในบล็อกของคุณด้วย ช่วยให้ฉันเข้าใจแนวคิดที่ดีขึ้นมาก ขอบคุณ.
steady_daddy

1
ข้อสรุปบอกว่ามันทั้งหมด
kushalvm

44

นี้:

var foo = new Foo();

และ

var foo = Object.create(Foo.prototype);

ค่อนข้างคล้ายกัน ความแตกต่างที่สำคัญอย่างหนึ่งคือการnew Fooใช้งานโค้ดคอนสตรัคเตอร์ในขณะที่Object.createจะไม่รันโค้ดเช่น

function Foo() {
    alert("This constructor does not run with Object.create");
}

โปรดทราบว่าหากคุณใช้เวอร์ชันสองพารามิเตอร์Object.create()คุณสามารถทำสิ่งที่ทรงพลังมากขึ้นได้


1
คำอธิบายที่ดี ฉันอาจเพิ่มโดยใช้Object.createในรูปแบบที่ง่ายที่สุดเช่นนี้ช่วยให้คุณละเว้นฟังก์ชันตัวสร้างจากรหัสของคุณในขณะที่ใช้ประโยชน์จากการสืบทอดต้นแบบ
Ricky Boyce

23

ความแตกต่างคือสิ่งที่เรียกว่า "การสืบทอด pseudoclassical กับต้นแบบ" ข้อเสนอแนะคือการใช้เพียงหนึ่งประเภทในรหัสของคุณไม่ใช่การผสมทั้งสอง

ในการสืบทอดแบบเทียม (ด้วยโอเปอเรเตอร์ "ใหม่") ให้จินตนาการว่าคุณกำหนดคลาสหลอกก่อนแล้วจึงสร้างวัตถุจากคลาสนั้น ตัวอย่างเช่นกำหนด pseudo-class "Person" แล้วสร้าง "Alice" และ "Bob" จาก "Person"

ในการสืบทอดต้นแบบ (โดยใช้ Object.create) คุณสร้างบุคคลที่ระบุ "อลิซ" โดยตรงจากนั้นสร้างบุคคลอื่น "บ๊อบ" โดยใช้ "อลิซ" เป็นต้นแบบ ไม่มี "คลาส" ที่นี่; ทั้งหมดเป็นวัตถุ

ภายในจาวาสคริปต์ใช้ "มรดกต้นแบบ"; วิธี "pseudoclassical" เป็นเพียงน้ำตาล

ดูลิงค์นี้เพื่อเปรียบเทียบสองวิธี


21
function Test(){
    this.prop1 = 'prop1';
    this.prop2 = 'prop2';
    this.func1 = function(){
        return this.prop1 + this.prop2;
    }
};

Test.prototype.protoProp1 = 'protoProp1';
Test.prototype.protoProp2 = 'protoProp2';
var newKeywordTest = new Test();
var objectCreateTest = Object.create(Test.prototype);

/* Object.create   */
console.log(objectCreateTest.prop1); // undefined
console.log(objectCreateTest.protoProp1); // protoProp1 
console.log(objectCreateTest.__proto__.protoProp1); // protoProp1

/* new    */
console.log(newKeywordTest.prop1); // prop1
console.log(newKeywordTest.__proto__.protoProp1); // protoProp1

สรุป:

1) ด้วยnewคำสำคัญมีสองสิ่งที่ควรทราบ;

ก) ฟังก์ชั่นจะใช้เป็นตัวสร้าง

b) function.prototypeวัตถุถูกส่งผ่านไปยัง__proto__คุณสมบัติ ... หรือที่__proto__ไม่ได้รับการสนับสนุนมันเป็นสถานที่ที่สองที่วัตถุใหม่ดูเพื่อค้นหาคุณสมบัติ

2) เมื่อObject.create(obj.prototype)คุณสร้างวัตถุ ( obj.prototype) และส่งไปยังวัตถุที่ต้องการ .. ด้วยความแตกต่างที่ตอนนี้วัตถุใหม่__proto__ก็ชี้ไปที่ obj.prototype (โปรดอ้างอิง an โดย xj9 สำหรับสิ่งนั้น)


15

ตัวแปรการสร้างวัตถุ


ชุดที่ 1 : ' new Object () ' -> ตัวสร้างวัตถุโดยไม่มีข้อโต้แย้ง

var p1 = new Object(); // 'new Object()' create and return empty object -> {}

var p2 = new Object(); // 'new Object()' create and return empty object -> {}

console.log(p1); // empty object -> {}

console.log(p2); // empty object -> {}

// p1 and p2 are pointers to different objects
console.log(p1 === p2); // false

console.log(p1.prototype); // undefined

// empty object which is in fact Object.prototype
console.log(p1.__proto__); // {}

// empty object to which p1.__proto__ points
console.log(Object.prototype); // {}

console.log(p1.__proto__ === Object.prototype); // true

// null, which is in fact Object.prototype.__proto__
console.log(p1.__proto__.__proto__); // null

console.log(Object.prototype.__proto__); // null

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


ชุดตัวเลือกที่ 2 : ' วัตถุใหม่ (คน) ' -> ตัวสร้างวัตถุพร้อมอาร์กิวเมนต์

const person = {
    name: 'no name',
    lastName: 'no lastName',
    age: -1
}

// 'new Object(person)' return 'person', which is pointer to the object ->
//  -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p1 = new Object(person);

// 'new Object(person)' return 'person', which is pointer to the object ->
//  -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p2 = new Object(person);

// person, p1 and p2 are pointers to the same object
console.log(p1 === p2); // true
console.log(p1 === person); // true
console.log(p2 === person); // true

p1.name = 'John'; // change 'name' by 'p1'
p2.lastName = 'Doe'; // change 'lastName' by 'p2'
person.age = 25; // change 'age' by 'person'

// when print 'p1', 'p2' and 'person', it's the same result,
// because the object they points is the same
console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(person); // { name: 'John', lastName: 'Doe', age: 25 }

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


ตัวแปร 3.1 : ' Object.create (person) ' ใช้ Object.create กับ 'person' อย่างง่าย 'Object.create (person)' จะสร้าง (และส่งคืน) วัตถุว่างเปล่าใหม่และเพิ่มคุณสมบัติ '__proto__' ลงในวัตถุว่างเปล่าใหม่เดียวกัน คุณสมบัตินี้ '__proto__' จะชี้ไปที่วัตถุ 'person'

const person = {
        name: 'no name',
        lastName: 'no lastName',
        age: -1,
        getInfo: function getName() {
           return `${this.name} ${this.lastName}, ${this.age}!`;
    }
}

var p1 = Object.create(person);

var p2 = Object.create(person);

// 'p1.__proto__' and 'p2.__proto__' points to
// the same object -> 'person'
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(p1.__proto__);
console.log(p2.__proto__);
console.log(p1.__proto__ === p2.__proto__); // true

console.log(person.__proto__); // {}(which is the Object.prototype)

// 'person', 'p1' and 'p2' are different
console.log(p1 === person); // false
console.log(p1 === p2); // false
console.log(p2 === person); // false

// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);

console.log(p1); // empty object - {}

console.log(p2); // empty object - {}

// add properties to object 'p1'
// (properties with the same names like in object 'person')
p1.name = 'John';
p1.lastName = 'Doe';
p1.age = 25;

// add properties to object 'p2'
// (properties with the same names like in object 'person')
p2.name = 'Tom';
p2.lastName = 'Harrison';
p2.age = 38;

// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);

// { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);

// { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);

// use by '__proto__'(link from 'p1' to 'person'),
// person's function 'getInfo'
console.log(p1.getInfo()); // John Doe, 25!

// use by '__proto__'(link from 'p2' to 'person'),
// person's function 'getInfo'
console.log(p2.getInfo()); // Tom Harrison, 38!

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


ชุดตัวเลือก 3.2 : ' Object.create (Object.prototype) ' ใช้ Object.create กับวัตถุในตัว -> 'Object.prototype' 'Object.create (Object.prototype)' จะสร้าง (และส่งคืน) วัตถุเปล่าใหม่และเพิ่มคุณสมบัติ '__proto__' ลงในวัตถุว่างเปล่าใหม่เดียวกัน คุณสมบัตินี้ '__proto__' จะชี้ไปที่วัตถุ 'Object.prototype'

// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p1' property '__proto__', which is link to 'Object.prototype'
var p1 = Object.create(Object.prototype);

// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p2' property '__proto__', which is link to 'Object.prototype'
var p2 = Object.create(Object.prototype);

console.log(p1); // {}

console.log(p2); // {}

console.log(p1 === p2); // false

console.log(p1.prototype); // undefined

console.log(p2.prototype); // undefined

console.log(p1.__proto__ === Object.prototype); // true

console.log(p2.__proto__ === Object.prototype); // true

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


ตัวแปร 4 : ' someFunction ใหม่ () '

// 'this' in constructor-function 'Person'
// represents a new instace,
// that will be created by 'new Person(...)'
// and returned implicitly
function Person(name, lastName, age) {

    this.name = name;
    this.lastName = lastName;
    this.age = age;

    //-----------------------------------------------------------------
    // !--- only for demonstration ---
    // if add function 'getInfo' into
    // constructor-function 'Person',
    // then all instances will have a copy of the function 'getInfo'!
    //
    // this.getInfo: function getInfo() {
    //  return this.name + " " + this.lastName + ", " + this.age + "!";
    // }
    //-----------------------------------------------------------------
}

// 'Person.prototype' is an empty object
// (before add function 'getInfo')
console.log(Person.prototype); // Person {}

// With 'getInfo' added to 'Person.prototype',
// instances by their properties '__proto__',
// will have access to the function 'getInfo'.
// With this approach, instances not need
// a copy of the function 'getInfo' for every instance.
Person.prototype.getInfo = function getInfo() {
    return this.name + " " + this.lastName + ", " + this.age + "!";
}

// after function 'getInfo' is added to 'Person.prototype'
console.log(Person.prototype); // Person { getInfo: [Function: getInfo] }

// create instance 'p1'
var p1 = new Person('John', 'Doe', 25);

// create instance 'p2'
var p2 = new Person('Tom', 'Harrison', 38);

// Person { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);

// Person { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);

// 'p1.__proto__' points to 'Person.prototype'
console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] }

// 'p2.__proto__' points to 'Person.prototype'
console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] }

console.log(p1.__proto__ === p2.__proto__); // true

// 'p1' and 'p2' points to different objects(instaces of 'Person')
console.log(p1 === p2); // false

// 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo' 
// and use 'getInfo' with 'p1'-instance's data
console.log(p1.getInfo()); // John Doe, 25!

// 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo' 
// and use 'getInfo' with 'p2'-instance's data
console.log(p2.getInfo()); // Tom Harrison, 38!

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


บทสรุปที่ดี ขอบคุณ มันช่วยฉันวันนี้ !!
Anandaraja_Srinivasan

11

ภายในObject.createทำสิ่งนี้:

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};

ไวยากรณ์เพียงนำภาพลวงตาที่ JavaScript ใช้การสืบทอดแบบคลาสสิกมาใช้


25
วิธี ECMAScript 5 Object.createทำมากกว่านั้นคุณสามารถกำหนดคุณสมบัติตามตัวบอกคุณสมบัติและคุณสามารถสร้างวัตถุที่ไม่ได้รับมรดกจากสิ่งใด ( Object.create(null);) ควรหลีกเลี่ยง shims ประเภทนี้เพราะคุณไม่สามารถเลียนแบบได้ พฤติกรรมบน ES3 ข้อมูลเพิ่มเติม
CMS

เห็นด้วยกับ @CMS แต่โดยทั่วไปก็เป็น polyfill Object.createง่ายสำหรับ
V. Kovpak

10

ตามคำตอบนี้และคำหลักวิดีโอนี้ newทำสิ่งต่อไป:

  1. สร้างวัตถุใหม่

  2. เชื่อมโยงวัตถุใหม่กับฟังก์ชันตัวสร้าง ( prototype)

  3. ทำให้thisตัวแปรชี้ไปที่วัตถุใหม่

  4. ดำเนินการฟังก์ชั่นการสร้างโดยใช้วัตถุใหม่และดำเนินการโดยนัยreturn this;

  5. constructorกำหนดชื่อฟังก์ชั่นคอนสตรัคคุณสมบัติวัตถุใหม่

Object.createดำเนินการเท่านั้น1stและ2ndขั้นตอน !!!

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