JavaScript: для чего используются .extend и .prototype?


122

Я относительно новичок в JavaScript и продолжаю видеть .extend и .prototype в сторонних библиотеках, которые я использую. Я думал, что это связано с javascript-библиотекой Prototype, но я начинаю думать, что это не так. Для чего они используются?

Ответы:


136

Наследование в Javascript основано на прототипах, поэтому вы расширяете прототипы таких объектов, как Date, Math, и даже свои собственные.

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

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

В приведенном выше фрагменте я определяю метод для всех объектов Date (уже существующих и всех новых).

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

Итак, вы можете сделать что-то вроде:

extend( Fighter, Human )

И Fighterконструктор / объект унаследует прототип Human, поэтому, если вы определите такие методы, как liveи dieon, Humanтогда Fighterони также унаследуют их.

Обновленное разъяснение:

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


75
«функция высокого уровня» означает, что .extendона не встроена, но часто предоставляется библиотекой, такой как jQuery или Prototype.
visum

13
Я бы добавил, что расширять прототипы нативных объектов в JS не предлагается
framp

1
@meder - вы должны добавить визуальный комментарий в свой ответ. :)
Маниш Гупта

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оператор with для объекта функции, будет создан новый объект, который будет унаследован от своего конструктора.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__ является геттером / сеттером для Prototype.

Разве это не должно быть .extend (), а не .extends ()?
SJHowe,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.