JavaScript: Для чого використовуються .extend та .prototype?


122

Я відносно новий у JavaScript і продовжую бачити .extend та .prototype у бібліотеках сторонніх організацій, які я використовую. Я думав, що це стосується бібліотеки JavaScript прототипу, але я починаю вважати, що це не так. Для чого вони використовуються?

Відповіді:


136

Спадщина Javascript заснована на прототипі, тому ви розширюєте прототипи таких об'єктів, як Date, Math і навіть власні користувацькі.

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

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

У фрагменті вище я визначаю метод для всіх об'єктів Date (вже існуючих та всіх нових).

extend зазвичай функція високого рівня, яка копіює прототип нового підкласу, який потрібно поширити з базового класу.

Тож ви можете зробити щось на кшталт:

extend( Fighter, Human )

А Fighterконструктор / об'єкт успадковує прототип Human, так що якщо ви визначити методи , такі , як liveа dieна Humanте Fighterбуде також успадкує ті.

Оновлено роз'яснення:

"функція високого рівня", що означає .extend не вбудований, але часто надається бібліотекою, такою як jQuery або прототип.


75
Значення "функції високого рівня" .extendне є вбудованим, але часто надається бібліотекою, такою як jQuery або Prototype.
visum

13
Я додам, що не пропонується розширювати прототипи нативних об'єктів у JS
framp

1
@meder - у своїй відповіді слід додати коментар visum. :)
Маніш Гупта

9
У сучасному програмуванні Javascript прийнято трактувати глобальні та рідні об’єкти як елементи громадської ванної кімнати; ви не можете уникнути заходу туди, але слід намагатися мінімізувати контакт з поверхнями. Це тому, що changing the native objects can break other developer's assumptions of these objects,призводять до помилок javascript, які часто можуть витратити багато годин на відстеження. Провідне речення щодо цієї відповіді, схоже, хибно представляє цю ціннісну практику JavaScript.
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».

Ідея полягає в тому, що є базовий клас, а потім ви розширюєте базовий клас, щоб отримати схожу на спадщину функцію (не повністю, але все-таки).

Вся ідея полягає у тому, щоб отримати те, що насправді означає прототип. Я не отримав його, поки не побачив код Джона Ресіга (близький до того, що 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 від поста Джона Ресіга .


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__ - це геттер / сетер для прототипу.

Якщо це не має бути .extend (), а не .extends ()?
SJHowe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.