ใช้ 'prototype' vs. 'this' ใน JavaScript หรือไม่


776

ความแตกต่างระหว่างอะไร

var A = function () {
    this.x = function () {
        //do something
    };
};

และ

var A = function () { };
A.prototype.x = function () {
    //do something
};


แนวคิดของคำหลักนี้มีการอธิบายอย่างชัดเจนที่นี่scotch.io/@alZami/understanding-this-in-javascript
AL-zami

1
การอ่านเธรด "this" นี้แสดงให้เห็นว่า JS นั้นน่ากลัวแค่ไหนและหลักการของมันยังไม่ชัดเจนสำหรับนักพัฒนาหลาย ๆ คน เกิดอะไรขึ้นกับภาษาที่เข้าใจง่ายกว่า ฉันคิดว่ามันเป็นเวลาที่นักพัฒนายกระดับเสียงของพวกเขาที่จะปฏิเสธเทคโนโลยีที่สับสนซึ่งให้บริการไม่ว่าจะมีมูลค่าน้อยหรือน้อยสำหรับงานธุรกิจหรือการพัฒนา
NoChance

บนวัตถุ: a1.x !== a2.x; ในต้นแบบ:a1.x === a2.x
Juan Mendes

คำตอบ:


467

ตัวอย่างมีผลลัพธ์ที่แตกต่างกันมาก

ก่อนที่จะดูความแตกต่างควรสังเกตสิ่งต่อไปนี้:

  • ต้นแบบของคอนสตรัคเตอร์ให้วิธีการแบ่งปันวิธีการและค่าระหว่างอินสแตนซ์ผ่าน[[Prototype]]คุณสมบัติส่วนตัวของอินสแตนซ์
  • ฟังก์ชั่นของสิ่งนี้ถูกตั้งค่าโดยวิธีการเรียกฟังก์ชั่นหรือโดยการใช้ผูก (ไม่กล่าวถึงที่นี่) เมื่อมีการเรียกใช้ฟังก์ชันบนวัตถุ (เช่นmyObj.method()) สิ่งนี้ภายในวิธีการอ้างอิงถึงวัตถุ ที่นี่ไม่ได้ตั้งค่าโดยการโทรหรือโดยการใช้ผูกมันเริ่มต้นที่วัตถุระดับโลก (หน้าต่างในเบราว์เซอร์) หรือในโหมดเข้มงวดยังคงไม่ได้กำหนด
  • JavaScript เป็นภาษาเชิงวัตถุเช่นค่าส่วนใหญ่เป็นวัตถุรวมถึงฟังก์ชั่น (สตริงตัวเลขและบูลีนไม่ใช่วัตถุ)

ดังนั้นนี่คือตัวอย่างที่เป็นปัญหา:

var A = function () {
    this.x = function () {
        //do something
    };
};

ในกรณีนี้ตัวแปรAถูกกำหนดค่าที่อ้างอิงถึงฟังก์ชัน เมื่อฟังก์ชั่นที่เรียกว่าการใช้A()ฟังก์ชั่นเป็นนี้ไม่ได้ถูกกำหนดโดยการเรียกเพื่อให้ค่าเริ่มต้นของมันไปยังวัตถุโลกและการแสดงออกที่มีประสิทธิภาพthis.x ผลที่ได้คือการอ้างอิงถึงการแสดงออกของฟังก์ชั่นทางด้านขวามือได้รับมอบหมายให้window.xwindow.x

ในกรณีของ:

var A = function () { };
A.prototype.x = function () {
    //do something
};

สิ่งที่แตกต่างกันมากเกิดขึ้น ในบรรทัดแรกตัวแปรAถูกกำหนดการอ้างอิงไปยังฟังก์ชัน ใน JavaScript วัตถุฟังก์ชั่นทั้งหมดมีคุณสมบัติต้นแบบตามค่าเริ่มต้นดังนั้นจึงไม่มีรหัสแยกต่างหากเพื่อสร้างวัตถุA.prototype

ในบรรทัดที่สองA.prototype.xได้รับการอ้างอิงไปยังฟังก์ชั่น สิ่งนี้จะสร้างคุณสมบัติxหากไม่มีอยู่หรือกำหนดค่าใหม่หากมี ดังนั้นความแตกต่างกับตัวอย่างแรกที่คุณสมบัติxของวัตถุนั้นเกี่ยวข้องกับการแสดงออก

ตัวอย่างอื่นอยู่ด้านล่าง มันคล้ายกับอันแรก (และอาจเป็นสิ่งที่คุณตั้งใจจะถาม):

var A = new function () {
    this.x = function () {
        //do something
    };
};

ในตัวอย่างนี้ตัวnewดำเนินการถูกเพิ่มก่อนนิพจน์ฟังก์ชันเพื่อให้เรียกใช้ฟังก์ชันเป็นตัวสร้าง เมื่อเรียกว่ามีnewฟังก์ชั่นเป็นนี้จะถูกตั้งค่าการอ้างอิงวัตถุใหม่ซึ่งส่วนตัว[[Prototype]]ตั้งค่าคุณสมบัติการอ้างอิงสาธารณะคอนสตรัคของต้นแบบ ดังนั้นในคำสั่งการมอบหมายxคุณสมบัติจะถูกสร้างขึ้นบนวัตถุใหม่นี้ เมื่อเรียกว่าเป็นตัวสร้างฟังก์ชั่นจะคืนค่าวัตถุนี้เป็นค่าเริ่มต้นดังนั้นจึงไม่จำเป็นต้องมีreturn this;คำสั่งแยกต่างหาก

วิธีตรวจสอบว่าAมีคุณสมบัติx :

console.log(A.x) // function () {
                 //   //do something
                 // };

นี่คือการใช้งานที่ผิดปกติของใหม่ตั้งแต่วิธีเดียวที่จะอ้างอิงสร้างผ่านA.constructor มันจะเป็นเรื่องธรรมดามากที่จะทำ:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

อีกวิธีหนึ่งในการบรรลุผลลัพธ์ที่คล้ายกันคือใช้นิพจน์ฟังก์ชันที่เรียกใช้ทันที:

var A = (function () {
    this.x = function () {
        //do something
    };
}());

ในกรณีนี้Aกำหนดค่าส่งคืนของการเรียกใช้ฟังก์ชันทางด้านขวามือ ที่นี่อีกครั้งตั้งแต่นี้ไม่ได้ตั้งค่าในการเรียกก็จะอ้างอิงวัตถุทั่วโลกและมีประสิทธิภาพthis.x window.xตั้งแต่ฟังก์ชั่นไม่ได้กลับอะไรจะมีค่าของAundefined

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

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

คำถามที่เกี่ยวข้อง :

Sidenote:อาจไม่มีการประหยัดหน่วยความจำที่สำคัญระหว่างสองวิธีอย่างไรก็ตามการใช้ต้นแบบเพื่อแบ่งปันวิธีการและคุณสมบัติน่าจะใช้หน่วยความจำน้อยกว่าแต่ละตัวอย่างมีสำเนาของตัวเอง

JavaScript ไม่ใช่ภาษาระดับต่ำ การคิดต้นแบบหรือรูปแบบการสืบทอดอื่น ๆ อาจไม่คุ้มค่านักที่จะเปลี่ยนวิธีจัดสรรหน่วยความจำอย่างชัดเจน


49
@keparo: คุณผิด วัตถุทุกคนมี [ภายใน] ต้นแบบวัตถุ (ซึ่งอาจจะเป็นnull) แต่นี่คือความแตกต่างจากprototypeทรัพย์สิน - newซึ่งเป็นฟังก์ชั่นและที่เป็นต้นแบบของทุกกรณีที่มีการตั้งค่าเมื่อมีการสร้างด้วย ไม่อยากเชื่อเลยว่านี่จะมีผู้
โหวต

8
"The language is functional"คุณแน่ใจหรือว่านี่คือความหมายของหน้าที่
phant0m

23
ฉันสองสิ่งที่ @Bergi พูดเกี่ยวกับต้นแบบ ฟังก์ชั่นมีคุณสมบัติต้นแบบ วัตถุทั้งหมดรวมถึงฟังก์ชั่นมีคุณสมบัติภายในอื่นซึ่งสามารถเข้าถึงได้ด้วย Object.getPrototypeOf (myObject) หรือกับ myObject .__ proto__ ในเบราว์เซอร์บางตัว โปรคุณสมบัติบ่งชี้ว่าผู้ปกครองของวัตถุในห่วงโซ่ต้นแบบ (หรือวัตถุจากการที่วัตถุนี้สืบทอด) คุณสมบัติต้นแบบ (ซึ่งมีเฉพาะในฟังก์ชัน) ระบุวัตถุที่จะเป็นพาเรนต์ของวัตถุใด ๆ ที่ใช้ฟังก์ชันเพื่อสร้างวัตถุใหม่โดยใช้คำหลักใหม่
Jim Cooper

11
บทความนี้จะเข้าใจผิดมากและสับสนวิธีนี้เป็นชุด ทำงานบน re-write
RobG

37
คำตอบนี้ค่อนข้างแปลกและดูเหมือนจะพลาดประเด็นทั้งหมด คำถามดูเหมือนจะเป็นเรื่องธรรมดามากเกี่ยวกับการกำหนดคุณสมบัติประเภทภายในนวกรรมิกกับ protoype แต่ครึ่งหนึ่งของคำตอบคือสิ่งที่จะเกิดขึ้นหากคุณใช้Aเป็นฟังก์ชันและอีกครึ่งหนึ่งเกี่ยวกับวิธีคลุมเครือ บางสิ่งบางอย่างตรงไปตรงมา
JLRishe

235

ดังที่คนอื่น ๆ บอกไว้ในเวอร์ชั่นแรกการใช้ "นี่" จะส่งผลให้เกิดทุกตัวอย่างของคลาส A ที่มีสำเนาของฟังก์ชั่นอิสระ "x" ในขณะที่ใช้ "ต้นกำเนิด" จะหมายถึงแต่ละอินสแตนซ์ของคลาส A จะใช้สำเนาวิธีการเดียวกัน "x"

นี่คือรหัสเพื่อแสดงความแตกต่างที่ลึกซึ้งนี้:

// x is a method assigned to the object using "this"
var A = function () {
    this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
    this.x = function() { alert( value ); }
};

var a1 = new A();
var a2 = new A();
a1.x();  // Displays 'A'
a2.x();  // Also displays 'A'
a1.updateX('Z');
a1.x();  // Displays 'Z'
a2.x();  // Still displays 'A'

// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };

B.prototype.updateX = function( value ) {
    B.prototype.x = function() { alert( value ); }
}

var b1 = new B();
var b2 = new B();
b1.x();  // Displays 'B'
b2.x();  // Also displays 'B'
b1.updateX('Y');
b1.x();  // Displays 'Y'
b2.x();  // Also displays 'Y' because by using prototype we have changed it for all instances

ตามที่คนอื่น ๆ กล่าวถึงมีหลายเหตุผลที่จะเลือกวิธีหนึ่งหรืออื่น ๆ ตัวอย่างของฉันมีไว้เพื่อแสดงความแตกต่างอย่างชัดเจน


5
นี่คือสิ่งที่ฉันคาดว่าจะเกิดขึ้น แต่เมื่อฉันสร้างวัตถุใหม่หลังจากเปลี่ยน Axe เช่นด้านบนฉันยังคงแสดง 'A' ยกเว้นว่าฉันใช้ A เช่น singleton jsbin.com/omida4/2/edit
jellyfishtree

19
นั่นเป็นเพราะตัวอย่างของฉันผิด มันผิดแค่สองปีเท่านั้น ถอนหายใจ แต่ประเด็นก็ยังคงใช้ได้ ฉันอัปเดตตัวอย่างด้วยอันที่ใช้งานได้จริง ขอบคุณที่ชี้นำ
Benry

4
มันเป็นวิธีคงที่! : D

6
ใช่ ... 'prototype' หมายถึงระดับคงที่หรือระดับ .. ซึ่งจะถูกแบ่งปันโดยอินสแตนซ์ทั้งหมดที่สร้างขึ้น ... ในขณะที่ 'this' เป็นวิธีการอินสแตนซ์ซึ่งแต่ละอินสแตนซ์จะมีสำเนาของตัวเอง
Aneer Dev

7
มันไม่คงที่ คงที่ตามที่ใช้ในภาษา OO ส่วนใหญ่หมายความว่าไม่มีการพึ่งพาthisวัตถุซึ่งเป็นเจ้าของวิธีการ เช่นวิธีการไม่มีวัตถุที่เป็นเจ้าของ ในกรณีนี้มีthisวัตถุดังแสดงในคลาส A ในตัวอย่าง
CJStuarte

152

นำตัวอย่าง 2 ตัวอย่างนี้:

var A = function() { this.hey = function() { alert('from A') } };

เมื่อเทียบกับ

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

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

a) ฟังก์ชั่นเป็นวัตถุใน JavaScript วัตถุทุกอย่างใน JavaScript ได้รับคุณสมบัติภายใน (หมายถึงคุณไม่สามารถเข้าถึงได้เช่นเดียวกับคุณสมบัติอื่น ๆ ยกเว้นในเบราว์เซอร์เช่น Chrome) ซึ่งมักเรียกว่า__proto__(คุณสามารถพิมพ์anyObject.__proto__ใน Chrome จริงเพื่อดูว่ามันอ้างอิงอะไร คุณสมบัติไม่มีอะไรเพิ่มเติมคุณสมบัติใน JavaScript = ตัวแปรภายในวัตถุไม่มีอะไรเพิ่มเติมตัวแปรทำอะไรได้บ้างพวกเขาชี้ไปยังสิ่งต่าง ๆ

ดังนั้น__proto__คุณสมบัตินี้ชี้ไปที่อะไร? ปกติแล้ววัตถุอื่น (เราจะอธิบายว่าทำไมในภายหลัง) วิธีเดียวที่จะบังคับใช้ JavaScript สำหรับสถานที่ให้บริการไปยังจุดไม่ถึงวัตถุอื่นคือการใช้งาน__proto__ var newObj = Object.create(null)แม้ว่าคุณจะทำเช่นนี้สถานที่ให้บริการยังคงมีอยู่เป็นทรัพย์สินของวัตถุเพียงมันไม่ได้ชี้ไปที่วัตถุอื่นก็ชี้ไปที่__proto__null

ที่นี่คนส่วนใหญ่สับสน:

เมื่อคุณสร้างฟังก์ชั่นใหม่ใน JavaScript (ซึ่งเป็นวัตถุเช่นกันจำได้ไหม?) ช่วงเวลาที่มันถูกกำหนดไว้, JavaScript prototypeจะสร้างสถานที่ให้บริการใหม่ในฟังก์ชั่นที่เรียกว่า ลองมัน:

var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined

A.prototypeแตกต่างจาก__proto__ทรัพย์สินโดยสิ้นเชิง ในตัวอย่างของเรา 'A' ตอนนี้มีสองคุณสมบัติที่เรียกว่า 'ต้นแบบ' __proto__และ นี่เป็นความสับสนครั้งใหญ่สำหรับผู้คน prototypeและ__proto__คุณสมบัติไม่เกี่ยวข้องกันพวกมันแยกสิ่งต่าง ๆ ที่ชี้ไปที่ค่าต่างกัน

คุณอาจสงสัยว่า: ทำไม JavaScript มี__proto__คุณสมบัติสร้างขึ้นในทุก ๆ วัตถุ? ดีหนึ่งคำ: คณะผู้แทน เมื่อคุณเรียกคุณสมบัติบนวัตถุและวัตถุนั้นไม่มีอยู่ JavaScript จะค้นหาวัตถุที่อ้างอิงโดย__proto__เพื่อดูว่าอาจมีหรือไม่ ถ้ามันไม่มีมันก็จะดูที่__proto__คุณสมบัติของวัตถุนั้นและอื่น ๆ ... จนกระทั่งโซ่จบ ดังนั้นชื่อของห่วงโซ่ต้นแบบ แน่นอนถ้า__proto__ไม่ชี้ไปที่วัตถุและแทนที่จะชี้ไปnullที่โชคดีอย่างยิ่ง JavaScript ตระหนักดีว่าและจะส่งคืนคุณundefinedสำหรับคุณสมบัติ

คุณอาจสงสัยว่าทำไม JavaScript จึงสร้างคุณสมบัติที่เรียกว่าprototypeฟังก์ชันเมื่อคุณกำหนดฟังก์ชัน เพราะมันพยายามหลอกคุณใช่หลอกคุณว่ามันใช้งานได้เหมือนภาษาที่ใช้ในห้องเรียน

ลองดูตัวอย่างของเราและสร้าง "วัตถุ" จากA:

var a1 = new A();

มีบางอย่างเกิดขึ้นในพื้นหลังเมื่อสิ่งนี้เกิดขึ้น a1เป็นตัวแปรธรรมดาที่ได้รับมอบหมายวัตถุใหม่ที่ว่างเปล่า

ความจริงที่ว่าคุณใช้โอเปอเรเตอร์newก่อนที่การเรียกใช้ฟังก์ชันA()จะทำบางสิ่งเพิ่มเติมในพื้นหลัง newคำหลักสร้างวัตถุใหม่ซึ่งขณะนี้การอ้างอิงa1และวัตถุที่เป็นที่ว่างเปล่า นี่คือสิ่งที่เกิดขึ้นนอกจากนี้:

เราบอกว่าในแต่ละคำนิยามฟังก์ชั่นมีคุณสมบัติใหม่ที่สร้างขึ้นเรียกว่าprototype(ซึ่งคุณสามารถเข้าถึงได้ซึ่งแตกต่างจาก__proto__คุณสมบัติ) สร้างขึ้น? ตอนนี้กำลังใช้คุณสมบัตินี้อยู่

ดังนั้นตอนนี้เราถึงจุดที่เรามีa1วัตถุเปล่าอบสดใหม่ เราบอกว่าวัตถุทั้งหมดใน JavaScript มี__proto__คุณสมบัติภายในที่ชี้ไปยังบางสิ่ง ( a1เช่นมี) ไม่ว่าจะเป็นวัตถุว่างเปล่าหรือวัตถุอื่น สิ่งที่newผู้ประกอบการทำคือมันตั้งค่า__proto__คุณสมบัตินั้นให้ชี้ไปที่prototypeคุณสมบัติของฟังก์ชัน อ่านอีกครั้ง มันเป็นแบบนี้:

a1.__proto__ = A.prototype;

เราบอกว่าA.prototypeไม่มีอะไรมากไปกว่าวัตถุเปล่า (เว้นแต่เราจะเปลี่ยนเป็นสิ่งอื่นก่อนกำหนดa1) ตอนนี้โดยทั่วไปแล้วa1.__proto__ชี้ไปที่สิ่งเดียวกันA.prototypeซึ่งเป็นวัตถุที่ว่างเปล่า พวกเขาทั้งสองชี้ไปที่วัตถุเดียวกันซึ่งสร้างขึ้นเมื่อสายนี้เกิดขึ้น:

A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}

ตอนนี้มีสิ่งอื่นเกิดขึ้นเมื่อvar a1 = new A()ประมวลผลคำสั่ง โดยพื้นฐานแล้วA()จะถูกประหารชีวิตและหาก A เป็นดังนี้:

var A = function() { this.hey = function() { alert('from A') } };

สิ่งที่อยู่ข้างในfunction() { }นั้นกำลังจะดำเนินการ เมื่อคุณไปถึงthis.hey..เส้นนั้นthisจะเปลี่ยนเป็นa1และคุณจะได้รับสิ่งนี้:

a1.hey = function() { alert('from A') }

ฉันจะไม่ครอบคลุมว่าทำไมthisการเปลี่ยนแปลงa1แต่นี่เป็นคำตอบที่ดีในการเรียนรู้เพิ่มเติม

ดังนั้นเพื่อสรุปเมื่อคุณvar a1 = new A()มี 3 สิ่งที่เกิดขึ้นในพื้นหลัง:

  1. a1วัตถุที่ว่างเปล่าใหม่ทั้งหมดถูกสร้างขึ้นและได้รับมอบหมายให้a1 = {}
  2. a1.__proto__property ถูกกำหนดให้ชี้ไปที่สิ่งเดียวกับที่A.prototypeชี้ไปที่ (object ว่างอีก {})

  3. A()กำลังดำเนินการฟังก์ชั่นโดยthisตั้งค่าเป็นวัตถุใหม่ที่ว่างเปล่าที่สร้างขึ้นในขั้นตอนที่ 1 (อ่านคำตอบที่ฉันอ้างถึงข้างต้นว่าทำไมthisการเปลี่ยนแปลงถึงa1)

ตอนนี้ลองสร้างวัตถุอื่น:

var a2 = new A();

ขั้นตอนที่ 1,2,3 จะทำซ้ำ คุณสังเกตเห็นบางสิ่ง? คำสำคัญคือการทำซ้ำ ขั้นตอนที่ 1: a2จะเป็นวัตถุที่ว่างเปล่าใหม่ขั้นตอนที่ 2: __proto__คุณสมบัติของมันจะชี้ไปที่สิ่งเดียวกันA.prototypeและที่สำคัญที่สุดขั้นตอนที่ 3: ฟังก์ชั่นA()จะถูกดำเนินการอีกครั้งซึ่งหมายความว่าa2จะได้รับheyคุณสมบัติที่มีฟังก์ชั่น a1และa2มีสองคุณสมบัติ SEPARATE ตั้งชื่อheyซึ่งชี้ไปที่ 2 ฟังก์ชัน SEPARATE! ตอนนี้เรามีฟังก์ชั่นที่ซ้ำกันในสองวัตถุที่แตกต่างกันทำสิ่งเดียวกันอุ๊ปส์ ... คุณสามารถจินตนาการถึงความหมายของหน่วยความจำของสิ่งนี้ถ้าเรามีวัตถุ 1,000 ชิ้นที่สร้างขึ้นด้วยnew Aหลังจากการประกาศฟังก์ชั่นทั้งหมด เราจะป้องกันสิ่งนี้ได้อย่างไร

จำได้ไหมว่าทำไม__proto__คุณสมบัติจึงมีอยู่ในทุกวัตถุ ดังนั้นถ้าคุณดึงyoManคุณสมบัติบนa1(ซึ่งไม่มีอยู่) __proto__คุณสมบัติของมันจะได้รับการพิจารณาซึ่งถ้ามันเป็นวัตถุ (และเป็นกรณีส่วนใหญ่) มันจะตรวจสอบว่ามีyoManหรือไม่ มันจะปรึกษาวัตถุนั้น__proto__เป็นต้นถ้าเป็นเช่นนั้นมันจะเอาค่าคุณสมบัตินั้นและแสดงให้คุณเห็น

ดังนั้นบางคนตัดสินใจที่จะใช้ความจริงนี้ + ความจริงที่ว่าเมื่อคุณสร้างa1ขึ้น__proto__คุณสมบัติของมันจะชี้ไปที่ออบเจ็กต์ (ว่าง) เดียวกันA.prototypeและทำสิ่งนี้:

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

เย็น! ตอนนี้เมื่อคุณสร้างa1มันจะผ่านขั้นตอนทั้ง 3 ขั้นตอนข้างต้นอีกครั้งและในขั้นตอนที่ 3 ก็ไม่ได้ทำอะไรเลยเนื่องจากfunction A()ไม่มีสิ่งใดที่จะต้องดำเนินการ และถ้าเราทำ:

a1.hey

จะเห็นว่าa1ไม่มีheyและจะตรวจสอบ__proto__วัตถุคุณสมบัติเพื่อดูว่ามีหรือไม่ซึ่งเป็นกรณี

ด้วยวิธีการนี้เราจะกำจัดส่วนหนึ่งออกจากขั้นตอนที่ 3 ซึ่งฟังก์ชั่นจะทำซ้ำในการสร้างวัตถุใหม่แต่ละครั้ง แทนการa1และa2มีการแยกheyทรัพย์สินตอนนี้ไม่มีของพวกเขามีมัน ซึ่งตอนนี้ฉันคิดว่าคุณคงเข้าใจแล้ว นั่นเป็นสิ่งที่ดี ... ถ้าคุณเข้าใจ__proto__และFunction.prototypeคำถามเช่นนี้จะค่อนข้างชัดเจน

หมายเหตุ: บางคนมักจะไม่เรียกคุณสมบัติต้นแบบภายในเนื่องจาก__proto__ฉันใช้ชื่อนี้ผ่านการโพสต์เพื่อแยกความแตกต่างให้ชัดเจนกับFunctional.prototypeทรัพย์สินว่าเป็นสองสิ่งที่แตกต่างกัน


1
คำตอบที่ละเอียดและให้ข้อมูลจริงๆ ฉันทำการทดสอบหน่วยความจำบางอย่างโดยใช้โครงสร้างวัตถุด้านบน (A.prototype.hey vs object this.hey) และสร้างแต่ละอินสแตนซ์ 1,000 รายการ รอยเท้าหน่วยความจำสำหรับวิธีการคุณสมบัติวัตถุมีขนาดใหญ่ขึ้นประมาณ 100kb เมื่อเปรียบเทียบกับต้นแบบ ฉันเพิ่มฟังก์ชั่นอื่นโดยมีจุดประสงค์เดียวกันกับที่เรียกว่า "silly" และมันเพิ่มขึ้นเป็นเส้นตรงเป็น 200kb ไม่สำคัญ แต่ไม่ใช่ถั่วลิสงเช่นกัน
jookyone

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

ประเด็นคือ__proto__และ.prototypeต่าง ๆ โดยสิ้นเชิง
Wayou

1
ผมไม่รู้สึกว่ามีความพึงพอใจที่จะเพียงแค่ให้คุณ upvote ... ทำดี!
Kristianmitk

58

ในกรณีส่วนใหญ่จะเหมือนกัน แต่รุ่นที่สองจะบันทึกหน่วยความจำเนื่องจากมีเพียงอินสแตนซ์เดียวของฟังก์ชันแทนที่จะเป็นฟังก์ชันแยกต่างหากสำหรับแต่ละวัตถุ

เหตุผลที่ใช้แบบฟอร์มแรกคือเข้าถึง "สมาชิกส่วนตัว" ตัวอย่างเช่น:

var A = function () {
    var private_var = ...;

    this.x = function () {
        return private_var;
    };

    this.setX = function (new_x) {
        private_var = new_x;
    };
};

เนื่องจากกฎการกำหนดขอบเขตของ javascript ทำให้ private_var มีฟังก์ชันที่กำหนดให้กับ this.x แต่ไม่ใช่นอกวัตถุ


1
ดูโพสต์นี้: stackoverflow.com/a/1441692/654708สำหรับตัวอย่างในการเข้าถึงสมาชิกส่วนตัวผ่านทางต้นแบบ
GFoley83

@ GFoley83 คำตอบนั้นไม่แสดงว่า - วิธีต้นแบบสามารถเข้าถึงคุณสมบัติ "สาธารณะ" ของวัตถุที่กำหนดได้เท่านั้น เฉพาะเมธอดพิเศษ (ไม่ใช่บนต้นแบบ) เท่านั้นที่สามารถเข้าถึงสมาชิกส่วนตัว
Alnitak

27

ตัวอย่างแรกเปลี่ยนอินเทอร์เฟซสำหรับวัตถุนั้นเท่านั้น ตัวอย่างที่สองเปลี่ยนอินเทอร์เฟซสำหรับวัตถุทั้งหมดของคลาสนั้น


ทั้งสองจะทำให้ฟังก์ชันxพร้อมใช้งานสำหรับวัตถุทั้งหมดที่มีการกำหนดต้นแบบเป็นอินสแตนซ์ใหม่ของ:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
Spencer Williams

21

ปัญหาขั้นสุดท้ายด้วยการใช้thisแทนprototypeคือเมื่อแทนที่เมธอด constructor ของคลาสพื้นฐานจะยังคงอ้างถึงเมธอด overridden พิจารณาสิ่งนี้:

BaseClass = function() {
    var text = null;

    this.setText = function(value) {
        text = value + " BaseClass!";
    };

    this.getText = function() {
        return text;
    };

    this.setText("Hello"); // This always calls BaseClass.setText()
};

SubClass = function() {
    // setText is not overridden yet,
    // so the constructor calls the superclass' method
    BaseClass.call(this);

    // Keeping a reference to the superclass' method
    var super_setText = this.setText;
    // Overriding
    this.setText = function(value) {
        super_setText.call(this, "SubClass says: " + value);
    };
};
SubClass.prototype = new BaseClass();

var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!

subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

เมื่อเทียบกับ:

BaseClass = function() {
    this.setText("Hello"); // This calls the overridden method
};

BaseClass.prototype.setText = function(value) {
    this.text = value + " BaseClass!";
};

BaseClass.prototype.getText = function() {
    return this.text;
};

SubClass = function() {
    // setText is already overridden, so this works as expected
    BaseClass.call(this);
};
SubClass.prototype = new BaseClass();

SubClass.prototype.setText = function(value) {
    BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};

var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

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

var A = function (param1) {
    var privateVar = null; // Private variable

    // Calling this.setPrivateVar(param1) here would be an error

    this.setPrivateVar = function (value) {
        privateVar = value;
        console.log("setPrivateVar value set to: " + value);

        // param1 is still here, possible memory leak
        console.log("setPrivateVar has param1: " + param1);
    };

    // The constructor logic starts here possibly after
    // many lines of code that define methods

    this.setPrivateVar(param1); // This is valid
};

var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0

a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0

เมื่อเทียบกับ:

var A = function (param1) {
    this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
    this.publicVar = value; // No private variable
};

var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1

20

ทุกวัตถุเชื่อมโยงกับวัตถุต้นแบบ เมื่อพยายามเข้าถึงคุณสมบัติที่ไม่มีอยู่ JavaScript จะค้นหาวัตถุต้นแบบของวัตถุสำหรับคุณสมบัตินั้นและส่งคืนถ้ามีอยู่

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


ในตัวอย่างแรกของคุณคุณกำลังเพิ่มคุณสมบัติxให้กับแต่ละอินสแตนซ์ที่สร้างด้วยAฟังก์ชัน

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

ในตัวอย่างที่สองคุณกำลังเพิ่มคุณสมบัติให้กับวัตถุต้นแบบที่อินสแตนซ์ทั้งหมดที่สร้างโดยAชี้ไปที่

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

โดยสรุปในตัวอย่างแรกสำเนาของการทำงานที่ได้รับมอบหมายให้แต่ละอินสแตนซ์ ในตัวอย่างที่สองสำเนาเดียวของการทำงานร่วมกันโดยทุกกรณี


1
โหวตสิ่งนี้เพื่อเป็นคำตอบที่ตรงประเด็นที่สุด
Nick Pineda

1
ฉันชอบวิธีการตรงไปข้างหน้าของคุณ !! ยกนิ้วให้!
Prince Vijay Pratap

16

ความแตกต่างคืออะไร? => มาก

ฉันคิดว่าthisเวอร์ชันนี้ใช้เพื่อเปิดใช้งานการห่อหุ้มข้อมูลเช่นการซ่อนข้อมูล ช่วยจัดการกับตัวแปรส่วนตัว

ให้เราดูตัวอย่างต่อไปนี้:

var AdultPerson = function() {

  var age;

  this.setAge = function(val) {
    // some housekeeping
    age = val >= 18 && val;
  };

  this.getAge = function() {
    return age;
  };

  this.isValid = function() {
    return !!age;
  };
};

ตอนนี้prototypeโครงสร้างสามารถใช้ได้ดังนี้:

ผู้ใหญ่ที่แตกต่างกันมีอายุที่ต่างกัน แต่ผู้ใหญ่ทุกคนจะได้รับสิทธิเหมือนกัน
ดังนั้นเราเพิ่มมันโดยใช้ต้นแบบมากกว่านี้

AdultPerson.prototype.getRights = function() {
  // Should be valid
  return this.isValid() && ['Booze', 'Drive'];
};

ให้ดูที่การใช้งานตอนนี้

var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )

var p2 = new AdultPerson;
p2.setAge(45);    
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***

หวังว่านี่จะช่วยได้


3
+1 คำตอบที่ซับซ้อนและมีกราฟน้อยกว่าคำตอบอื่น แต่คุณควรทำอย่างละเอียดอีกเล็กน้อยก่อนแสดงตัวอย่าง (ดี) เหล่านี้
yerforkferchips

1
ฉันไม่แน่ใจเกี่ยวกับ "เวอร์ชันนี้ใช้เพื่อเปิดใช้งานการห่อหุ้มข้อมูลเช่นการซ่อนข้อมูล" หากมีการกำหนดคุณสมบัติภายในฟังก์ชันโดยใช้ "this" ดังใน "this.myProperty = ... " คุณสมบัติดังกล่าวจะไม่ "เป็นส่วนตัว" และสามารถเข้าถึงได้จากวัตถุนอกคลาสโดยใช้ "new"
NoChance

14

Prototype เป็นเทมเพลตของคลาส ซึ่งใช้กับอินสแตนซ์ในอนาคตทั้งหมดของมัน ในขณะที่นี่เป็นตัวอย่างเฉพาะของวัตถุ


14

ฉันรู้ว่าสิ่งนี้ได้รับคำตอบถึงความตาย แต่ฉันต้องการแสดงตัวอย่างจริงของความแตกต่างความเร็ว

ฟังก์ชั่นโดยตรงบนวัตถุ

ฟังก์ชั่นต้นแบบ

ที่นี่เรากำลังสร้างวัตถุใหม่ 2,000,000 ชิ้นด้วยprintวิธีการใน Chrome เรากำลังจัดเก็บทุกวัตถุในอาเรย์ การวางprintเครื่องต้นแบบจะใช้เวลาประมาณ 1/2 นาน


13

ให้ฉันให้คำตอบที่ครอบคลุมมากขึ้นที่ฉันได้เรียนรู้ในระหว่างการฝึกอบรม JavaScript

คำตอบส่วนใหญ่พูดถึงความแตกต่างอยู่แล้วเช่นเมื่อการสร้างต้นแบบฟังก์ชั่นที่ใช้ร่วมกันกับทุกกรณี (ในอนาคต) ในขณะที่การประกาศฟังก์ชั่นในชั้นเรียนจะสร้างสำเนาสำหรับแต่ละอินสแตนซ์

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

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

รูปแบบ Object Decorator

ไม่แน่ใจว่ารูปแบบนี้ยังคงมีความเกี่ยวข้องทุกวันนี้ แต่มีอยู่จริง และมันเป็นเรื่องดีที่จะรู้เกี่ยวกับมัน คุณเพียงผ่านวัตถุและคุณสมบัติไปยังฟังก์ชันมัณฑนากร มัณฑนากรส่งคืนวัตถุที่มีคุณสมบัติและวิธีการ

var carlike = function(obj, loc) {
    obj.loc = loc;
    obj.move = function() {
        obj.loc++;
    };
    return obj;
};

var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();

ชั้นเรียนการทำงาน

ฟังก์ชั่นใน JavaScript เป็นวัตถุพิเศษ นอกเหนือจากการเรียกใช้ฟังก์ชั่นสามารถจัดเก็บคุณสมบัติเช่นวัตถุอื่น ๆ

ในกรณีCarนี้เป็นฟังก์ชั่น ( ยังคิดว่าวัตถุ ) ที่สามารถเรียกใช้ตามที่คุณคุ้นเคย มันมีคุณสมบัติmethods(ซึ่งเป็นวัตถุที่มีmoveฟังก์ชั่น) เมื่อCarมีการรื้อฟื้นextendการเรียกฟังก์ชันที่ไม่มายากลบางส่วนและขยายCarฟังก์ชั่น (คิดว่าวัตถุ) methodsด้วยวิธีการที่กำหนดไว้ภายใน

ตัวอย่างนี้แม้ว่าจะแตกต่างกันมาใกล้เคียงกับตัวอย่างแรกในคำถาม

var Car = function(loc) {
    var obj = {loc: loc};
    extend(obj, Car.methods);
    return obj;
};

Car.methods = {
    move : function() {
        this.loc++;
    }
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

คลาส Prototypal

สองรูปแบบแรกให้การอภิปรายของการใช้เทคนิคในการกำหนดวิธีการที่ใช้ร่วมกันหรือใช้วิธีการที่กำหนดไว้แบบอินไลน์ในร่างกายของตัวสร้าง ในทั้งสองกรณีทุกอินสแตนซ์มีmoveฟังก์ชั่นของตัวเอง

รูปแบบต้นแบบไม่ได้ให้ผลดีกับการตรวจสอบเดียวกันเนื่องจากการแบ่งปันฟังก์ชั่นผ่านการมอบหมายต้นแบบเป็นเป้าหมายที่สำคัญสำหรับรูปแบบต้นแบบ ตามที่คนอื่น ๆ ชี้ให้เห็นก็คาดว่าจะมีรอยความทรงจำที่ดีขึ้น

อย่างไรก็ตามมีจุดหนึ่งที่น่าสนใจที่จะทราบ: prototypeวัตถุทุกชิ้นมีคุณสมบัติความสะดวกสบายconstructorซึ่งชี้กลับไปที่ฟังก์ชั่น (คิดว่าวัตถุ) มันมาพร้อมกับ

เกี่ยวกับสามบรรทัดสุดท้าย:

ในตัวอย่างนี้Carเชื่อมโยงไปยังprototypeวัตถุซึ่งเชื่อมโยงconstructorไปยังCarตัวเองCar.prototype.constructorคือCarตัวมันเอง สิ่งนี้ช่วยให้คุณทราบว่าฟังก์ชันตัวสร้างใดสร้างวัตถุบางอย่าง

amy.constructorการค้นหาล้มเหลวจึงได้รับการแต่งตั้งให้Car.prototypeซึ่งมีคุณสมบัติคอนสตรัคเตอร์ และamy.constructorเป็นCarเช่นนั้น

นอกจากนี้เป็นamy ประกอบการทำงานโดยเห็นว่าวัตถุต้นแบบตัวถูกดำเนินการทางด้านขวาของ ( ) สามารถพบได้ทุกที่ในต้นแบบถูกดำเนินการทางด้านซ้ายของ ( ) ห่วงโซ่instanceof CarinstanceofCaramy

var Car = function(loc) {
    var obj = Object.create(Car.prototype);
    obj.loc = loc;
    return obj;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);

นักพัฒนาบางคนอาจสับสนในการเริ่มต้น ดูตัวอย่างด้านล่าง:

var Dog = function() {
  return {legs: 4, bark: alert};
};

var fido = Dog();
console.log(fido instanceof Dog);

ตัวinstanceofดำเนินการส่งคืนfalseเนื่องจากDogต้นแบบไม่พบในfidoห่วงโซ่ต้นแบบ เป็นวัตถุที่เรียบง่ายที่จะถูกสร้างขึ้นพร้อมกับตัวอักษรวัตถุคือมันเป็นเพียงแค่ได้รับมอบหมายให้fidoObject.prototype

รูปแบบ Pseudoclassical

นี่เป็นเพียงรูปแบบต้นแบบอีกรูปแบบหนึ่งในรูปแบบที่ง่ายกว่าและคุ้นเคยมากกว่าที่จะทำผู้ที่เขียนโปรแกรมใน Java เช่นเนื่องจากมันใช้ตัวnewสร้าง

มันเหมือนกับในรูปแบบต้นแบบจริงๆมันเป็นเพียงน้ำตาลแบบซินแทคติกของรูปแบบต้นแบบ

อย่างไรก็ตามความแตกต่างหลักคือมีการปรับให้เหมาะสมในเอ็นจิน JavaScript ที่ใช้เฉพาะเมื่อใช้รูปแบบ pseudoclassical เท่านั้น คิดว่ารูปแบบ pseudoclassical อาจเป็นรูปแบบต้นแบบเร็วขึ้น ความสัมพันธ์เชิงวัตถุในตัวอย่างทั้งสองนั้นเหมือนกัน

var Car = function(loc) {
    this.loc = loc;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();

ท้ายที่สุดไม่ควรยากเกินไปที่จะรู้ว่าการเขียนโปรแกรมเชิงวัตถุสามารถทำได้อย่างไร มีสองส่วน

ส่วนหนึ่งที่กำหนดคุณสมบัติ / วิธีการทั่วไปในต้นแบบ (เชน)

และอีกส่วนหนึ่งที่คุณใส่คำจำกัดความที่ทำให้วัตถุแตกต่างจากกัน ( locตัวแปรในตัวอย่าง)

นี่คือสิ่งที่ช่วยให้เราสามารถใช้แนวคิดเช่นซูเปอร์คลาสหรือคลาสย่อยใน JavaScript

รู้สึกอิสระที่จะเพิ่มหรือแก้ไข เสร็จสมบูรณ์อีกครั้งฉันสามารถทำให้ชุมชนนี้เป็น Wiki ได้


เพื่อไม่ให้โพสต์อย่างละเอียดมาก แต่ฉันคิดว่าการสืบทอด OO และ Prototypical นั้นเป็นโรงเรียนแห่งความคิดที่แตกต่างกัน
Nick Pineda

พวกเขาเป็น แต่ใครจะ "ทำ OO" ด้วยเทคนิค / ความคิดที่แตกต่างกันใช่มั้ย
Ely

ไม่แน่ใจจริงๆ หลายคนบอกว่าปรัชญาการทำต้นแบบแตกต่างกันและหลายคนพยายามเปรียบเทียบกับ OO เพราะโรงเรียนแห่งความคิดที่หลายคนคุ้นเคย
Nick Pineda

ฉันหมายถึงถ้าคุณต้องการฝึกฝนสไตล์ OO และภาษามีชุดของเทคนิคที่ช่วยในการทำเช่นนั้นมันไม่จำเป็นต้องผิด
Ely

11

ฉันเชื่อว่า @ Matthewth Crumley นั้นถูกต้อง พวกมันใช้งานได้หากไม่ได้มีโครงสร้างเทียบเท่า หากคุณใช้ Firebug เพื่อดูวัตถุที่สร้างขึ้นโดยใช้newคุณจะเห็นว่าพวกเขาเหมือนกัน อย่างไรก็ตามการตั้งค่าของฉันจะเป็นดังต่อไปนี้ ฉันเดาว่ามันดูเหมือนกับสิ่งที่ฉันคุ้นเคยใน C # / Java นั่นคือกำหนดคลาสกำหนดเขตข้อมูลตัวสร้างและวิธีการ

var A = function() {};
A.prototype = {
    _instance_var: 0,

    initialize: function(v) { this._instance_var = v; },

    x: function() {  alert(this._instance_var); }
};

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


2
_instance_var ในคุณสมบัติinitializeและx methods do not refer to the _instance_var` บนAอินสแตนซ์ แต่เป็นแบบโกลบอล ใช้this._instance_varหากคุณต้องการใช้_instance_varคุณสมบัติของAอินสแตนซ์
Lekensteyn

2
สิ่งที่ตลกคือเบ็นรี่ก็ทำผิดเช่นกันซึ่งถูกเปิดเผยหลังจากสองปีด้วยเช่นกัน: p
Lekensteyn

10

ดังที่ได้กล่าวไว้ในคำตอบอื่น ๆ มันเป็นการพิจารณาประสิทธิภาพเนื่องจากฟังก์ชั่นในต้นแบบถูกแชร์กับอินสแตนซ์ทั้งหมด - แทนที่จะเป็นฟังก์ชั่นที่สร้างขึ้นสำหรับแต่ละอินสแตนซ์

ฉันรวบรวม jsperf เพื่อแสดงสิ่งนี้ มีความแตกต่างอย่างมากในเวลาที่ใช้ในการยกตัวอย่างชั้นเรียนถึงแม้ว่ามันจะมีความเกี่ยวข้องเฉพาะในกรณีที่คุณทำหลายกรณี

http://jsperf.com/functions-in-constructor-vs-prototype


8

นึกถึงภาษาที่พิมพ์แบบคงที่สิ่งต่าง ๆprototypeเป็นแบบคงที่และเป็นสิ่งที่thisเกี่ยวข้องกับอินสแตนซ์

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