2011-01-14 8 views
46

Tworzę klasę Vector, która może zasadniczo zawierać trzy wartości liczbowe. Jednak na takich wektorach można wykonać wiele operacji - np. uzyskiwanie wielkości, dodawanie lub odejmowanie innego wektora itd.Czy powinienem użyć prototypu, czy nie?

Zastanawiałem się, czy te funkcje powinny być kodowane jako prototypowe funkcje klasy Vector, czy też powinienem je zdefiniować w konstruktorze.

Która z tych dwóch metod jest lepsza?

function Vector3D(x, y, z) { 
    this.x = x; 
    this.y = y 
    this.z = z; 
} 

Vector3D.prototype.magnitude = function() { 
    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 
}; 

lub

function Vector3D(x, y, z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 

    this.magnitude = function() { 
     return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 
    }; 
} 

Odpowiedz

49

Taka jest właśnie sytuacja korzystania z prototypu. Widzę dwa główne korzyści takiego postępowania:

  1. funkcje nie są tworzone wielokrotnie. Jeśli zdefiniujesz funkcje wewnątrz konstruktora, dla każdej zdefiniowanej funkcji zostanie utworzona nowa anonimowa funkcja, za każdym razem, gdy konstruktor będzie nazywać się. Prototypy są statycznymi obiektami, a każde wystąpienie Vector3D będzie po prostu odniesienia funkcji prototypu.
  2. Prototyp to pojedynczy obiekt, który można łatwo zmanipulować. Zapewnia to dużą elastyczność; niestety mogę tylko podać kilka przykładów tego, co to może zaoferować:
    1. Jeśli chcesz stworzyć klasę dla dzieci, na przykład Vector3DSpecial, możesz po prostu sklonować Vector3D.prototype i przypisać to do Vector3DSpecial.prototype. Chociaż można to również zrobić przy użyciu konstruktorów przez Vector3DSpecial.prototype = new Vector3D();, konstruktorzy mogą zawierać efekty uboczne, które zostaną wykonane w tym prostym przypisaniu prototypu, a zatem należy ich unikać. Dzięki prototypom możesz nawet wybrać tylko określone funkcje w prototypie, które zostaną skopiowane do nowej klasy.
    2. Dodawanie metod do Vector3D jest po prostu kwestią dodawania właściwości do prototypu i pozwala na łatwiejsze dzielenie/organizowanie kodu na wiele plików lub na dynamiczne dodawanie metod w innych częściach kodu. Oczywiście, możesz zrobić kombinację dodawania metod w konstruktorze i poprzez prototyp, ale jest to niespójne i prawdopodobnie doprowadzi do większej złożoności w dalszej części ścieżki.

kiedy ja nie używanie prototyp? W przypadku obiektów singleton, na przykład kontrolera, który współdziała ze stroną i może delegować pracę na inne obiekty. Globalny obiekt "powiadomienie" jest jednym z takich przykładów. W tym przypadku rozszerzenie jest mało prawdopodobne, a obiekt jest tworzony tylko raz, co sprawia, że ​​prototyp ma dodatkową (koncepcyjną) złożoność.

8

prototyp metody będzie działać tylko do własności publicznej, jeśli chcesz śledzić x, y, z, jak „prywatnych” zmiennych prototyp nie będzie działać.

Używałbym tego ostatniego, ponieważ możesz chcieć metod, które działają tylko ze zmiennymi prywatnymi/wewnętrznymi, ale wszystko zależy od kontekstu.

function Vector3D(x, y, z) { 
    // x, y, z is automatically in this scope now, but as private members. 
    this.magnitude = function() { 
     return Math.sqrt(x * x + y * y + z *z); 
    } 
} 
+1

Dzięki za reakcję. x, y i z powinny być również możliwe do wyodrębnienia z instancji Vector3D, więc powinny być publiczne. W takim przypadku prototyp mógłby być najlepszym wyborem? – pimvdb

+3

+1 dla poprawnej odpowiedzi, ale ja wolę prototypy, ponieważ wszystko, co prywatne w js jest potokiem, i zwykle tylko utrudni ci jednostkowe przetestowanie twojego kodu - kogo ukrywasz z wyjątkiem siebie :) –

+0

Zgadzam się z tobą, dlatego mam tylko publiczne zmienne. W Narzędziach dla programistów Google Chrome funkcje są również wyświetlane jako członkowie, jeśli zostaną przekazane przez konstruktora, podczas gdy byłoby bardziej praktyczne, gdyby były "ukryte" w prototypie i że pojawiłyby się tylko x, yiz. – pimvdb

0

ECMA 6 http://es6-features.org/#BaseClassAccess

class Shape { 
    … 
    toString() { 
     return `Shape(${this.id})` 
    } 
} 
class Rectangle extends Shape { 
    constructor (id, x, y, width, height) { 
     super(id, x, y) 
     … 
    } 
    toString() { 
     return "Rectangle > " + super.toString() 
    } 
} 
class Circle extends Shape { 
    constructor (id, x, y, radius) { 
     super(id, x, y) 
     … 
    } 
    toString() { 
     return "Circle > " + super.toString() 
    } 
} 

ECMA 5

var Shape = function (id, x, y) { 
    … 
}; 
Shape.prototype.toString = function (x, y) { 
    return "Shape(" + this.id + ")" 
}; 
var Rectangle = function (id, x, y, width, height) { 
    Shape.call(this, id, x, y); 
    … 
}; 
Rectangle.prototype.toString = function() { 
    return "Rectangle > " + Shape.prototype.toString.call(this); 
}; 
var Circle = function (id, x, y, radius) { 
    Shape.call(this, id, x, y); 
    … 
}; 
Circle.prototype.toString = function() { 
    return "Circle > " + Shape.prototype.toString.call(this); 
}; 
Powiązane problemy