JavaScript: do czego służą pliki .extend i .prototype?

122

Jestem stosunkowo nowy w JavaScript i ciągle widzę .extend i .prototype w bibliotekach innych firm, których używam. Myślałem, że ma to coś wspólnego z biblioteką Prototype javascript, ale zaczynam myśleć, że tak nie jest. Do czego służą?

Andrzej
źródło

Odpowiedzi:

136

Dziedziczenie JavaScript jest oparte na prototypach, więc możesz rozszerzyć prototypy obiektów, takich jak Date, Math, a nawet własne.

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

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

W powyższym fragmencie definiuję metodę dla wszystkich obiektów Date (już istniejących i wszystkich nowych).

extend jest zwykle funkcją wysokiego poziomu, która kopiuje prototyp nowej podklasy, którą chcesz rozszerzyć z klasy bazowej.

Możesz więc zrobić coś takiego:

extend( Fighter, Human )

A Fighterkonstruktor / przedmiot posiądą prototyp Human, więc jeśli zdefiniowanie metod, takich jak livei diena Humanczym Fighterbędzie również dziedziczyć tych.

Zaktualizowane wyjaśnienie:

„funkcja wysokiego poziomu”, co oznacza .extend nie jest wbudowana, ale często dostarczana przez bibliotekę, taką jak jQuery lub Prototype.

meder omuraliev
źródło
75
Znaczenie „funkcji wysokiego poziomu” .extendnie jest wbudowane, ale często dostarczane przez bibliotekę, taką jak jQuery lub Prototype.
visum
13
Dodam, że nie sugeruje się rozszerzania prototypów obiektów natywnych w JS
framp
1
@meder - w odpowiedzi należy dodać komentarz visum. :)
Manish Gupta
9
We współczesnym programowaniu w Javascript zwyczajowo traktuje się obiekty globalne i natywne jak elementy publicznej łazienki; nie możesz uniknąć wchodzenia tam, ale powinieneś starać się zminimalizować kontakt z powierzchniami. Dzieje się tak, ponieważ changing the native objects can break other developer's assumptions of these objects,prowadzi to do błędów javascript, których wytropienie może często kosztować wiele godzin. Wiodące zdanie w tej odpowiedzi wydaje się błędnie interpretować tę cenną praktykę javascript.
Ninjaxor
24

.extend()jest dodawany przez wiele bibliotek innych firm, aby ułatwić tworzenie obiektów z innych obiektów. Przykłady można znaleźć pod adresem http://api.jquery.com/jQuery.extend/ lub http://www.prototypejs.org/api/object/extend .

.prototype odwołuje się do „szablonu” (jeśli chcesz to tak nazwać) obiektu, więc dodając metody do prototypu obiektu (widzisz to często w bibliotekach, aby dodać do String, Date, Math lub nawet Function) te metody są dodawane do każdego nowego wystąpienia tego obiektu.

pnomolos
źródło
19

extendSposób na przykład w jQuery lub PrototypeJS , kopiuje wszystkie właściwości ze źródła do obiektu docelowego.

Jeśli chodzi o prototypewłaściwość, jest to element składowy obiektów funkcji, jest częścią rdzenia języka.

Każda funkcja może służyć jako konstruktor do tworzenia nowych instancji obiektów. Wszystkie funkcje mają tę prototypewłaściwość.

Gdy użyjesz newoperatora with na obiekcie funkcji, zostanie utworzony nowy obiekt, który odziedziczy po swoim konstruktorze prototype.

Na przykład:

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

var foo = new Foo();

foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
CMS
źródło
18

Dziedziczenie w Javascript wydaje się być wszędzie otwartą debatą. Można go nazwać „Ciekawym przypadkiem języka Javascript”.

Chodzi o to, że istnieje klasa bazowa, a następnie rozszerzasz klasę bazową, aby uzyskać funkcję podobną do dziedziczenia (nie do końca, ale nadal).

Chodzi o to, aby zrozumieć, co naprawdę oznacza prototyp. Nie dostałem tego, dopóki nie zobaczyłem kodu Johna Resiga (blisko tego, co jQuery.extendrobi), który napisał fragment kodu, który to robi i twierdzi, że źródłem inspiracji były biblioteki base2 i prototyp.

Oto kod.

    /* 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;
  };
})();

Są trzy części, które wykonują tę pracę. Najpierw przejrzyj właściwości i dodaj je do instancji. Następnie tworzymy konstruktor, który później będzie można dodać do obiektu, a kluczowe linie to:

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

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

Najpierw wskaż Class.prototypeżądany prototyp. Teraz cały obiekt się zmienił, co oznacza, że ​​musisz wymusić powrót układu do jego własnego.

I przykład użycia:

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

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

Przeczytaj więcej na ten temat tutaj w poście Javascript Inheritance autorstwa Johna Resiga .

ambodi
źródło
2

Niektóre extendfunkcje w bibliotekach innych firm są bardziej złożone niż inne. Na przykład Knockout.js zawiera minimalnie prosty plik, który nie ma niektórych sprawdzeń, które wykonuje jQuery:

function extend(target, source) {
    if (source) {
        for(var prop in source) {
            if(source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}
Simon_Weaver
źródło
2
  • .extends() stworzyć klasę, która jest dzieckiem innej klasy.
    za kulisami Child.prototype.__proto__ustawia swoją wartość Parent.prototype
    tak, aby metody były dziedziczone.
  • .prototype dziedziczyć funkcje z jednego do drugiego.
  • .__proto__ jest narzędziem pobierającym / ustawiającym dla Prototype.
humaid
źródło
Czy nie powinno to być .extend (), a nie .extends ()?
SJHowe