2014-12-20 31 views
14

Próbuję rozszerzyć JavaScript Math. Ale jedno mnie zaskoczyło.Rozszerzanie obiektu Math przez prototyp nie działa

Kiedy próbowałem przedłużyć go przez prototype

Math.prototype.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

W konsoli mam błąd „nie można ustawić właściwość«randomBetween»undefined” ...

Ale gdybym asigne tę funkcję do Math.__proto__

Math.__proto__.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

Wtedy wszystko działa poprawnie.

Czy ktoś może mi wyjaśnić, dlaczego działa w ten sposób? Doceniam każdą pomoc.

Odpowiedz

24

Math nie jest konstruktorem, więc nie ma prototype właściwość:

new Math(); // TypeError: Math is not a constructor 

Zamiast tego, po prostu dodaj swój sposób do samego Math jako own property:

Math.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

swoje podejście z __proto__ działa, ponieważ od Math jest instancją Object, Math.__proto__ jest Object.prototype.

Ale pamiętaj, że dodajesz metodę randomBetween do wszystkich obiektów, nie tylko do Math. Może to być problematyczne, na przykład podczas iterowania obiektów za pomocą pętli for...in.

+0

@GeorgeJempty Dlaczego nie lubisz "własnej własności"? – Oriol

+0

@GeorgeJempty "własność własna" w JavaScript jest właściwością, która istnieje bezpośrednio na konkretnym obiekcie (w przeciwieństwie do tego, który jest dziedziczony przez łańcuch prototypów). Może łatwiej byłoby spojrzeć na to, czy zawierało cytaty, czy też były kursywą? – JLRishe

+0

Dzięki za wyjaśnienia, cytaty pomogłyby, gdyby było inaczej, wygląda na to, że angielski jest zniekształcony. –

3

Cytując this answer:

Niektóre implementacje JavaScript umożliwiają bezpośredni dostęp do [[Prototype]] własności, np poprzez niestandardowym właściwość o nazwie __proto__. Ogólnie rzecz biorąc, możliwe jest tylko ustawienie prototypu obiektu podczas tworzenia obiektu: Jeśli utworzysz nowy obiekt za pomocą nowego Func(), właściwość [[Prototype]] obiektu zostanie ustawiona na obiekt, do którego odwołuje się Func.prototype.

Powodem nie można przypisać do swojego prototypu z zastosowaniem .prototype dlatego, że obiekt Math został już utworzony.

Na szczęście dla nas, możemy przypisać nowe właściwości do obiektu Math używając zwyczajnie:

Math.myFunc = function() { return true }; 

w Twoim przypadku będzie to:

Math.randomBetween = function(...) { ... }; 
+0

Aby być sprawiedliwym tak samo jak nienawidzę '__proto__', od tego czasu został on ustandaryzowany i działa we wszystkich nowoczesnych przeglądarkach. –

1

To dlatego, że nie ma Math jest obiektem , nie a function.

W javascript, function jest przybliżonym odpowiednikiem klasy w językach obiektowych. prototype to specjalna właściwość, która umożliwia dodawanie metod instancji do tej klasy .Jeśli chcesz rozszerzyć tę klasę, użyjesz prototype i "po prostu działa".

Teraz zastanówmy się, co to jest Math. Nigdy nie tworzysz obiektu matematycznego, po prostu używasz jego metod. W rzeczywistości nie ma sensu tworzyć dwóch różnych obiektów Math, ponieważ Math zawsze działa tak samo! Innymi słowy, obiekt Math w javascriptu jest po prostu wygodnym sposobem grupowania grup wstępnie napisanych funkcji związanych z matematyką. To jak słownik zwykłej matematyki.

Chcesz dodać coś do tej grupy? Po prostu dodaj właściwość do kolekcji! Oto dwa proste sposoby na zrobienie tego.

Math.randomBetween = function() { ... } 
Math["randomBetween"] = function() {... } 

Korzystanie drugi sposób sprawia, że ​​nieco bardziej oczywiste, że jest to rodzaj słownika kolekcji, ale oba robią to samo.

0
var MyMath = Object.create(Math); // empty object with prototype Math 

MyMath.randomBetween = function (a, b) { 
    return this.floor(this.random() * (b - a + 1) + a); 
}; 

typeof(MyMath);     // object 
Object.getPrototypeOf(MyMath); // Math 
MyMath.PI;      // 3.14... 
MyMath.randomBetween(0, 10); // exactly that 
  • przedmiotem Math jest prototypem nowej MyMath obiektu
  • MyMath ma dostęp do wszystkich funkcjonalności Math
  • można dodać niestandardowe funkcje do MyMath bez manipulowania Math
  • w swoim niestandardowe metody, użyj słowa kluczowego this, aby zapoznać się z funkcją Math

W tym podejściu nie ma kodu Monkey Patching. To jest najlepszy sposób na rozszerzenie JavScript Math. Nie ma potrzeby powtarzania wyjaśnień z innych odpowiedzi.