JavaScript: .extend และ .prototype ใช้สำหรับอะไร?


122

ฉันค่อนข้างใหม่กับ JavaScript และยังคงเห็น .extend และ .prototype ในไลบรารีของบุคคลที่สามที่ฉันใช้อยู่ ฉันคิดว่ามันเกี่ยวข้องกับไลบรารี Prototype javascript แต่ฉันเริ่มคิดว่ามันไม่ใช่อย่างนั้น สิ่งเหล่านี้ใช้ทำอะไร?

คำตอบ:


136

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

Date.prototype.lol = function() {
 alert('hi');
};

( new Date ).lol() // alert message

ในตัวอย่างด้านบนฉันกำหนดวิธีการสำหรับอ็อบเจ็กต์ Date ทั้งหมด (อ็อบเจ็กต์ที่มีอยู่แล้วและอ็อบเจ็กต์ใหม่ทั้งหมด)

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

ดังนั้นคุณสามารถทำสิ่งต่างๆเช่น:

extend( Fighter, Human )

และคอนFighterสตรัคเตอร์ / อ็อบเจกต์จะสืบทอดต้นแบบของHumanดังนั้นหากคุณกำหนดวิธีการเช่นliveและdieต่อไปHumanก็Fighterจะสืบทอดสิ่งเหล่านั้นด้วย

อัปเดตคำชี้แจง:

"ฟังก์ชันระดับสูง" ความหมาย .extend ไม่ได้อยู่ในตัว แต่มักจัดเตรียมโดยไลบรารีเช่น jQuery หรือ Prototype


75
"ฟังก์ชันระดับสูง" ความหมาย.extendไม่ได้อยู่ในตัว แต่มักจัดเตรียมโดยไลบรารีเช่น jQuery หรือ Prototype
visum

13
ฉันจะเพิ่มไม่แนะนำให้ขยายต้นแบบของวัตถุดั้งเดิมใน JS
framp

1
@meder - คุณควรเพิ่มความคิดเห็น visum ในคำตอบของคุณ :)
Manish Gupta

9
ในการเขียนโปรแกรม Javascript สมัยใหม่เป็นเรื่องปกติที่จะต้องปฏิบัติต่อลูกโลกและวัตถุพื้นเมืองเช่นองค์ประกอบของห้องน้ำสาธารณะ คุณไม่สามารถหลีกเลี่ยงการเข้าไปที่นั่นได้ แต่คุณควรพยายามลดการสัมผัสกับพื้นผิวให้น้อยที่สุด เนื่องจากchanging the native objects can break other developer's assumptions of these objects,นำไปสู่จุดบกพร่องของจาวาสคริปต์ซึ่งมักใช้เวลาหลายชั่วโมงในการติดตาม ดูเหมือนว่าประโยคนำหน้าคำตอบนี้จะบิดเบือนความจริงในการฝึกจาวาสคริปต์ที่มีคุณค่านี้
Ninjaxor

24

.extend()ถูกเพิ่มโดยไลบรารีของบุคคลที่สามจำนวนมากเพื่อให้ง่ายต่อการสร้างวัตถุจากวัตถุอื่น ๆ ดูhttp://api.jquery.com/jQuery.extend/หรือhttp://www.prototypejs.org/api/object/extendสำหรับตัวอย่างบางส่วน

.prototype หมายถึง "แม่แบบ" (ถ้าคุณต้องการเรียกมันว่า) ของวัตถุดังนั้นโดยการเพิ่มวิธีการลงในต้นแบบของวัตถุ (คุณเห็นสิ่งนี้มากในไลบรารีเพื่อเพิ่มใน String, Date, Math หรือแม้แต่ Function) วิธีการเหล่านั้น จะถูกเพิ่มลงในอินสแตนซ์ใหม่ทุกชิ้นของออบเจ็กต์นั้น


19

extendวิธีการเช่นในjQueryหรือPrototypeJSสำเนาคุณสมบัติทั้งหมดจากแหล่งไปยังวัตถุที่ปลายทาง

ตอนนี้เกี่ยวกับprototypeคุณสมบัติเป็นสมาชิกของวัตถุฟังก์ชันซึ่งเป็นส่วนหนึ่งของแกนภาษา

สามารถใช้ฟังก์ชันใด ๆ เป็นตัวสร้างเพื่อสร้างอินสแตนซ์ออบเจ็กต์ใหม่ได้ ฟังก์ชันทั้งหมดมีprototypeคุณสมบัตินี้

เมื่อคุณใช้newโอเปอเรเตอร์กับอ็อบเจ็กต์ฟังก์ชันอ็อบเจ็กต์ใหม่จะถูกสร้างขึ้นและจะสืบทอดจากคอนสตรัคprototypeเตอร์

ตัวอย่างเช่น:

function Foo () {
}
Foo.prototype.bar = true;

var foo = new Foo();

foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true

18

การสืบทอด Javascript ดูเหมือนจะเป็นการอภิปรายที่เปิดกว้างในทุกๆที่ เรียกได้ว่าเป็น "กรณีที่น่าสงสัยของภาษา Javascript"

แนวคิดคือมีคลาสพื้นฐานแล้วคุณขยายคลาสฐานเพื่อให้ได้คุณสมบัติที่เหมือนการสืบทอด (ไม่สมบูรณ์ แต่ยังคงอยู่)

แนวคิดทั้งหมดคือการได้รับสิ่งที่ต้นแบบมีความหมายจริงๆ ฉันไม่ได้รับมันจนกว่าฉันจะเห็นรหัสของ John Resig (ใกล้เคียงกับสิ่งที่jQuery.extendทำ) เขียนโค้ดที่ทำและเขาอ้างว่า base2 และไลบรารีต้นแบบเป็นแหล่งที่มาของแรงบันดาลใจ

นี่คือรหัส

    /* Simple JavaScript Inheritance
     * By John Resig http://ejohn.org/
     * MIT Licensed.
     */  
     // Inspired by base2 and Prototype
    (function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};

  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;

    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;

            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }

    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = prototype;

    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;

    return Class;
  };
})();

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

// Populate our constructed prototype object
Class.prototype = prototype;

// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;

ก่อนอื่นให้ชี้Class.prototypeไปที่ต้นแบบที่ต้องการ ตอนนี้วัตถุทั้งหมดเปลี่ยนไปหมายความว่าคุณต้องบังคับให้เค้าโครงกลับไปเป็นของตัวเอง

และตัวอย่างการใช้งาน:

var Car = Class.Extend({
  setColor: function(clr){
    color = clr;
  }
});

var volvo = Car.Extend({
   getColor: function () {
      return color;
   }
});

อ่านเพิ่มเติมได้ที่นี่ที่Javascript Inheritance by John Resig 's post


2

extendฟังก์ชันบางอย่างในไลบรารีของบุคคลที่สามซับซ้อนกว่าฟังก์ชันอื่น ๆ ตัวอย่างเช่นKnockout.jsมีสิ่งที่เรียบง่ายน้อยที่สุดที่ไม่มีการตรวจสอบบางอย่างที่ jQuery ทำ:

function extend(target, source) {
    if (source) {
        for(var prop in source) {
            if(source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}

2
  • .extends() สร้างคลาสซึ่งเป็นลูกของคลาสอื่น
    เบื้องหลัง Child.prototype.__proto__กำหนดคุณค่าของมันเพื่อParent.prototype
    ให้มีการสืบทอดวิธีการ
  • .prototype สืบทอดคุณสมบัติจากคนหนึ่งไปยังอีกคนหนึ่ง
  • .__proto__ เป็น getter / setter สำหรับ Prototype

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