Zalety używania prototypu, a definiowanie metod prosto w konstruktorze? [duplikat]

To pytanie ma już odpowiedź tutaj:

Zastanawiam się, czy są jakieś zalety korzystania z jednego z nich nad drugim, i w którą stronę powinienem iść?

Podejście konstruktora:

var Class = function () {

    this.calc = function (a, b) {
        return a + b;
    };

};

Podejście prototypowe:

var Class = function () {};

Class.prototype.calc = function (a, b) {
    return a + b;
};

Nie podoba mi się to, używając prototypu, definicje metod są oddzielone od klasy i nie jestem świadomy, czy jest jakiś konkretny powód, dla którego powinienem użyć tego tylko w pierwszym podejściu.

Również, czy istnieje jakaś korzyść z używania funkcji dosłownej do zdefiniowania "klasy", zamiast tylko definicji funkcji:

var Class = function () {};

Vs

function Class () {};
Dzięki!
Author: Leo, 2010-12-22

4 answers

Metody dziedziczone przez łańcuch prototypów mogą być zmieniane uniwersalnie dla wszystkich instancji, na przykład:

function Class () {}
Class.prototype.calc = function (a, b) {
    return a + b;
}

// Create 2 instances:
var ins1 = new Class(),
    ins2 = new Class();

// Test the calc method:
console.log(ins1.calc(1,1), ins2.calc(1,1));
// -> 2, 2

// Change the prototype method
Class.prototype.calc = function () {
    var args = Array.prototype.slice.apply(arguments),
        res = 0, c;

    while (c = args.shift())
        res += c;

    return res; 
}

// Test the calc method:
console.log(ins1.calc(1,1,1), ins2.calc(1,1,1));
// -> 3, 3

Zauważ jak zmienia się metoda zastosowana do obu instancji? Dzieje się tak dlatego, że ins1 i ins2 mają tę samą funkcję calc(). Aby to zrobić z publicznymi metodami utworzonymi podczas budowy, musisz przypisać nową metodę do każdej instancji, która została utworzona, co jest niezręcznym zadaniem. To dlatego, że ins1 i ins2 mieliby swoje własne, indywidualnie utworzone funkcje calc().

Kolejnym efektem ubocznym tworzenia metod wewnątrz konstruktora jest gorsza wydajność. Każda metoda musi być wytworzona przy każdym uruchomieniu funkcji konstruktora. Metody w łańcuchu prototypów są tworzone raz, a następnie" dziedziczone " przez każdą instancję. Z drugiej strony monety, metody publiczne mają dostęp do zmiennych "prywatnych", co nie jest możliwe przy metodach dziedziczonych.

Jeśli chodzi o Twoje function Class() {} vs var Class = function () {} pytanie, to pierwsze jest "wciągnięte" na górę bieżącego zakresu przed wykonaniem. Dla tego ostatniego, deklaracja zmiennej jest podnoszona, ale nie przypisanie. Na przykład:

// Error, fn is called before the function is assigned!
fn();
var fn = function () { alert("test!"); } 

// Works as expected: the fn2 declaration is hoisted above the call
fn2();
function fn2() { alert("test!"); }
 406
Author: Andy E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-22 11:23:19

Zaletą podejścia prototypowego jest efektywność. Istnieje jeden obiekt funkcji calc() współdzielony pomiędzy wszystkimi obiektami Class (przez co mam na myśli obiekty utworzone przez wywołanie konstruktora Class). Drugi sposób (przypisanie metod wewnątrz konstruktora) tworzy nowy obiekt funkcji dla każdego obiektu Class, zużywając więcej pamięci i zajmując więcej czasu przetwarzania podczas wywoływania konstruktora Class. Jednak to podejście ma pewną zaletę: metoda calc() ma dostęp do zmiennych lokalnych wewnątrz konstruktor, którego możesz użyć na swoją korzyść:

function Class() {
    var calcCallCount = 0;

    this.calc = function (a, b) {
        ++calcCallCount;
        alert("Calc called " + calcCallCount + " times");
        return a + b;
    };
};

Odnośnie var Class = function() {...} versus function Class() {...}, generalnie wolę to drugie, ponieważ oznacza to, że funkcja ma nazwę, która może być przydatna podczas debugowania. Inną różnicą jest to, że ta ostatnia wersja (deklaracja funkcji ) jest podnoszona, co oznacza, że jest dostępna wszędzie w zakresie, w jakim jest zdefiniowana, a nie tylko po definicji. Jednak niektórzy ludzie wolą używać poprzedniej (a funkcji wyrażenie) wszędzie.

 59
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-10 11:37:28
var YourClass = function(){
  var privateField = "somevalue";
  this.publicField = "somevalue";
  this.instanceMethod1 = function(){
     //you may access both private and public field from here:
     //in order to access public field, you must use "this":
     alert(privateField + "; " + this.publicField);
  };
}

YourClass.prototype.instanceMethod2 = function(){
  //you may access only public field 2 from this method, but not private fields:
  alert(this.publicField);
  //error: drawaback of prototype methods:
  alert(privateField);  
};

Zalety metod prototypowych:

  1. Kiedy definiujesz metody za pomocą prototypu, są one współdzielone między wszystkimi instancjami YourClass. W rezultacie całkowity Rozmiar takich instancji wynosi

  2. Kolejną zaletą metod, zdefiniowanych za pomocą prototypu - jest użycie klas odziedziczonych, możesz nadpisać takie metody i w nadpisanej metodzie klasy pochodnej możesz wywołać metodę klasy bazowej o tej samej nazwie, ale z metodami zdefiniowanymi w konstruktorze nie możesz tego zrobić.

 39
Author: Alexandr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-28 21:03:28

Przede wszystkim należy użyć dosłownego obiektu w następujący sposób:

var Class = {
  calc: function (a, b) {
    return a + b;
  }
};

Ta notacja jest czystsza i sprawia, że oczywiste jest, że w Javascript obiekty są po prostu hashami, a nie czymś wspieranym z przepisu, jak predefiniowana Klasa.

Różnica między definicjami polega na tym, że jeśli dodasz metodę do prototypu, będzie tylko jedna metoda utworzona w pamięci dla wszystkich instancji. Jeśli więc masz metodę generyczną i obiekt, który jest tworzony/używany w wielu instancjach, powinieneś dodać metoda prototypu.

 -4
Author: azAttis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-22 10:55:13