แนะนำ
โหมดการใช้รหัสซ้ำสี่โหมดที่แนะนำในบทความนี้เป็นแนวปฏิบัติที่ดีที่สุดและแนะนำให้ทุกคนในระหว่างกระบวนการเขียนโปรแกรม
รูปแบบที่ 1: การสืบทอดต้นแบบ
การสืบทอดต้นแบบคือการให้วัตถุหลักเป็นต้นแบบของวัตถุเด็กเพื่อให้บรรลุวัตถุประสงค์ของการสืบทอด:
การคัดลอกรหัสมีดังนี้:
วัตถุฟังก์ชัน (o) {
ฟังก์ชั่น f () {
-
f.prototype = o;
คืน F () ใหม่;
-
// วัตถุหลักที่จะสืบทอด
var parent = {
ชื่อ: "Papa"
-
// วัตถุใหม่
var child = object (parent);
// ทดสอบ
console.log (child.name); // "พ่อ"
// ตัวสร้างหลัก
ฟังก์ชั่นบุคคล () {
// ทรัพย์สิน "ของตัวเอง"
this.name = "Adam";
-
// เพิ่มแอตทริบิวต์ใหม่ลงในต้นแบบ
person.prototype.getName = function () {
ส่งคืนสิ่งนี้ชื่อ;
-
// สร้างบุคคลใหม่
var papa = คนใหม่ ();
// มรดก
var kid = object (papa);
console.log (kid.getName ()); // "อดัม"
// ตัวสร้างหลัก
ฟังก์ชั่นบุคคล () {
// ทรัพย์สิน "ของตัวเอง"
this.name = "Adam";
-
// เพิ่มแอตทริบิวต์ใหม่ลงในต้นแบบ
person.prototype.getName = function () {
ส่งคืนสิ่งนี้ชื่อ;
-
// มรดก
var kid = object (person.prototype);
console.log (typeof kid.getName); // "ฟังก์ชั่น" เพราะมันถูกกำหนดไว้ในต้นแบบ
console.log (typeof kid.name); // "ไม่ได้กำหนด" เพราะมีเพียงต้นแบบที่สืบทอดมา
ในเวลาเดียวกัน ECMASCript5 ยังมีวิธีการที่คล้ายกันที่เรียกว่า Object.create สำหรับการสืบทอดวัตถุและการใช้งานมีดังนี้:
การคัดลอกรหัสมีดังนี้:
/* ใช้ Ecmascript 5 เวอร์ชันใหม่เพื่อให้คุณสมบัติ*/
var child = object.create (ผู้ปกครอง);
var child = object.create (parent, {
อายุ: {value: 2} // descriptor ECMA5
-
console.log (child.hasownproperty ("อายุ")); // จริง
นอกจากนี้ยังสามารถกำหนดคุณสมบัติในพารามิเตอร์ที่สองในลักษณะที่ละเอียดยิ่งขึ้น:
การคัดลอกรหัสมีดังนี้:
// ก่อนอื่นกำหนดวัตถุวัตถุใหม่
var man = object.create (null);
// ถัดไปสร้างการตั้งค่าการกำหนดค่าที่มีคุณสมบัติ
// คุณสมบัติถูกตั้งค่าเป็นเขียนได้พิสูจน์ได้และกำหนดค่าได้
var config = {
เขียนได้: จริง
enumerable: จริง
สามารถกำหนดค่าได้: จริง
-
// มักจะใช้ Object.defineProperty () เพื่อเพิ่มคุณสมบัติใหม่ (ECMASCript5 รองรับ)
// ตอนนี้เพื่อความสะดวกเราปรับแต่งฟังก์ชั่นการห่อหุ้ม
var defelEprop = function (obj, key, value) {
config.value = ค่า;
Object.defineProperty (obj, key, config);
-
defeleprop (man, 'car', 'delorean');
defineprop (man, 'dob', '1981');
defeleprop (มนุษย์, 'เครา', เท็จ);
ดังนั้นมรดกสามารถทำได้:
การคัดลอกรหัสมีดังนี้:
var driver = object.create (man);
defeleprop (ไดรเวอร์, 'topspeed', '100mph');
driver.topspeed // 100mph
แต่มีสิ่งหนึ่งที่ควรทราบนั่นคือต้นแบบของวัตถุที่สร้างโดย Object.create (null) ไม่ได้กำหนดนั่นคือไม่มีวิธีการ toString และค่าของวิธีการดังนั้นข้อผิดพลาดจะเกิดขึ้นเมื่อการแจ้งเตือน (มนุษย์); แต่แจ้งเตือน (man.car); ไม่เป็นไร
โหมด 2: คัดลอกแอตทริบิวต์ทั้งหมดสำหรับการสืบทอด
การสืบทอดด้วยวิธีนี้คือการคัดลอกคุณสมบัติทั้งหมดในวัตถุหลักไปยังวัตถุลูก โดยทั่วไปวัตถุลูกสามารถใช้ข้อมูลของวัตถุหลักได้
ก่อนอื่นให้ดูตัวอย่างสำเนาตื้น:
การคัดลอกรหัสมีดังนี้:
/* สำเนาตื้น*/
ฟังก์ชั่นขยาย (พาเรนต์เด็ก) {
var i;
เด็ก = เด็ก || -
สำหรับ (ฉันอยู่ในพาเรนต์) {
if (parent.hasownproperty (i)) {
เด็ก [i] = ผู้ปกครอง [i];
-
-
เด็กกลับ;
-
var dad = {ชื่อ: "อดัม"};
var kid = ขยาย (พ่อ);
console.log (kid.name); // "อดัม"
var dad = {
นับ: [1, 2, 3],
อ่าน: {paper: true}
-
var kid = ขยาย (พ่อ);
kid.counts.push (4);
console.log (dad.counts.toString ()); // "1,2,3,4"
console.log (dad.reads === kid.reads); // จริง
ในบรรทัดสุดท้ายของรหัสคุณสามารถพบว่าการอ่านของพ่อและเด็กนั้นเหมือนกันนั่นคือพวกเขาใช้การอ้างอิงเดียวกันซึ่งเป็นปัญหาที่เกิดจากสำเนาตื้น
มาดูสำเนาลึก:
การคัดลอกรหัสมีดังนี้:
/* สำเนาลึก*/
ฟังก์ชั่น Extenddeep (Parent, Child) {
var i,
toStr = object.prototype.toString
Astr = "[อาร์เรย์วัตถุ]";
เด็ก = เด็ก || -
สำหรับ (ฉันอยู่ในพาเรนต์) {
if (parent.hasownproperty (i)) {
if (typeof parent [i] === 'Object') {
เด็ก [i] = (toStr.Call (ผู้ปกครอง [i]) === Astr)? -
Extenddeep (ผู้ปกครอง [i], เด็ก [i]);
} อื่น {
เด็ก [i] = ผู้ปกครอง [i];
-
-
-
เด็กกลับ;
-
var dad = {
นับ: [1, 2, 3],
อ่าน: {paper: true}
-
var kid = exteddeep (พ่อ);
kid.counts.push (4);
console.log (kid.counts.toString ()); // "1,2,3,4"
console.log (dad.counts.toString ()); // "1,2,3"
console.log (dad.reads === kid.reads); // เท็จ
kid.reads.paper = false;
หลังจากการคัดลอกลึกค่าทั้งสองจะไม่เท่ากันบิงโก!
โหมด 3: มิกซ์อิน
ผสมในคือการคัดลอกคุณสมบัติหนึ่ง (หรือทั้งหมด) (หรือวิธีการ) ของวัตถุไปยังวัตถุอื่น ยกตัวอย่างกันเถอะ:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นผสม () {
var arg, prop, child = {};
สำหรับ (arg = 0; arg <arguments.length; arg += 1) {
สำหรับ (prop ในอาร์กิวเมนต์ [arg]) {
if (อาร์กิวเมนต์ [arg] .hasownproperty (prop)) {
เด็ก [prop] = อาร์กิวเมนต์ [arg] [prop];
-
-
-
เด็กกลับ;
-
var cake = mix (
{ไข่: 2, ใหญ่: จริง},
{Butter: 1, Salted: True},
{แป้ง: '3 ถ้วย'}
{น้ำตาล: 'แน่นอน!' -
-
console.dir (เค้ก);
ฟังก์ชั่นผสมจะคัดลอกแอตทริบิวต์เด็กของพารามิเตอร์ทั้งหมดที่ส่งผ่านเข้าไปในวัตถุลูกเพื่อสร้างวัตถุใหม่
แล้วเราแค่ต้องการผสมในบางคุณลักษณะบางอย่าง? ทำอย่างไร? ในความเป็นจริงเราสามารถใช้พารามิเตอร์พิเศษเพื่อกำหนดคุณสมบัติที่จำเป็นต้องผสมเช่น Mix (Child, Parent, Method1, Method2) เพื่อให้เราสามารถผสม Method1 และ Method2 ใน Parent เป็นลูกได้เท่านั้น บนรหัส:
การคัดลอกรหัสมีดังนี้:
// รถ
var car = function (การตั้งค่า) {
this.model = settings.model || 'ไม่มีแบบจำลอง';
this.colour = settings.colour || 'ไม่มีสีให้';
-
// mixin
var mixin = function () {};
mixin.prototype = {
DriveForward: function () {
console.log ('ขับไปข้างหน้า');
-
drivebackward: function () {
console.log ('ไดรฟ์ย้อนกลับ');
-
-
// พารามิเตอร์ทั้งสองที่กำหนดไว้คือวัตถุที่ผสมลงใน (reciving) และวัตถุที่ถูกผสมลงใน (ให้)
ฟังก์ชั่น Augment (Teedobj, GivingObj) {
// หากมีชื่อวิธีการที่ระบุจะมีพารามิเตอร์พิเศษ 3 ตัว
ถ้า (อาร์กิวเมนต์ [2]) {
สำหรับ (var i = 2, len = arguments.length; i <len; i ++) {
DEECINIVENTOBJ.PROTOTYPE [อาร์กิวเมนต์ [i]] = การให้ prototype [อาร์กิวเมนต์ [i]];
-
-
// หากคุณไม่ได้ระบุพารามิเตอร์ที่สามหรือพารามิเตอร์มากกว่านั้นวิธีทั้งหมดจะถูกผสม
อื่น {
สำหรับ (var methodname ในการให้ prototype) {
// ตรวจสอบว่าวัตถุที่ได้รับไม่มีชื่อที่จะผสมดังนั้นหากรวมอยู่
if (! DetivingObj.prototype [MethodName]) {
DEECIVINGOBJ.PROTOTYPE [MEWMENTNAME] = GIVERSOBJ.PROTOTYPE [MethodName];
-
-
-
-
// ผสมแอตทริบิวต์สำหรับรถยนต์ แต่ค่าผสมกับ 'driveforward' และ 'drivebackward'*/
Augment (Car, Mixin, 'Driveforward', 'Drivebackward');
// สร้างรถวัตถุใหม่
Var Vehicle = New Car ({รุ่น: 'Ford Escort', Color: 'Blue'});
// วิธีการทดสอบว่าได้รับการผสมสำเร็จหรือไม่
ยานพาหนะ Driveforward ();
ยานพาหนะ drivebackward ();
วิธีนี้มีความยืดหยุ่นในการใช้งานมากขึ้น
รูปแบบที่ 4: วิธีการยืม
วัตถุหนึ่งตัวยืมวิธีหนึ่งหรือสองวิธีของวัตถุอื่นและไม่มีการเชื่อมต่อโดยตรงระหว่างวัตถุทั้งสองนี้ ไม่จำเป็นต้องอธิบายเพิ่มเติมเพียงใช้รหัสเพื่ออธิบาย:
การคัดลอกรหัสมีดังนี้:
var one = {
ชื่อ: 'Object',
พูดว่า: ฟังก์ชั่น (ทักทาย) {
กลับมาทักทาย + ',' + this.name;
-
-
// ทดสอบ
console.log (one.say ('hi')); // "สวัสดีวัตถุ"
var two = {
ชื่อ: 'วัตถุอื่น'
-
console.log (one.say.apply (สอง, ['hello'])); // "สวัสดีวัตถุอื่น"
// กำหนดพูดกับตัวแปรสิ่งนี้จะชี้ไปที่ตัวแปรส่วนกลาง
var บอกว่า = one.say;
console.log (พูด ('hoho')); // "hoho, undefined"
// ผ่านฟังก์ชั่นการโทรกลับ
var etanother = {
ชื่อ: 'ยังมีวัตถุอื่น'
วิธีการ: ฟังก์ชั่น (การโทรกลับ) {
ส่งคืนการโทรกลับ ('hola');
-
-
console.log (yetanother.method (one.say)); // "Holla, undefined"
ฟังก์ชั่นผูก (o, m) {
return function () {
return m.apply (o, [] .slice.call (อาร์กิวเมนต์));
-
-
var twosay = bind (สอง, one.say);
console.log (twosay ('yo')); // "yo, วัตถุอื่น"
// ecmascript 5 เพิ่มเมธอด () ลงในฟังก์ชัน prototype เพื่อให้ใช้งานง่ายใช้ () และการโทร ()
if (typeof function.prototype.bind === 'undefined') {
function.prototype.bind = function (thisarg) {
var fn = สิ่งนี้
slice = array.prototype.slice
args = slice.call (อาร์กิวเมนต์, 1);
return function () {
return fn.apply (thisarg, args.concat (slice.call (อาร์กิวเมนต์)));
-
-
-
var twosay2 = one.say.bind (สอง);
console.log (twosay2 ('bonjour')); // "bonjour, วัตถุอื่น"
var twosay3 = one.say.bind (สอง, 'Enchanté');
console.log (twosay3 ()); // "Enchantéวัตถุอื่น"
สรุป
ไม่จำเป็นต้องสรุป