Hallo,
Ihr schreibt im JavaScript-Bereich "Daher ist es unmöglich, Math als
Prototyp zu erweitern" und begründet dies, weil das Math Objekt keinen
Konstruktor besitzt mit dem sich Instanzen erzeugen lassen.Wer aber sagt, dass ich für einen prototypischen Verweis eine neue Instanz erzeugen muss?
Du hast Recht, prototypische Erweiterung hat auch dann einen Sinn, wenn von einem Objekt direkt keine Instanzen möglich sind.
Aber alleine ABC.prototype = Math; ist noch keine *prototypische Erweiterung* des Math-Objekts, und darum ging es ja. Prototypische Erweiterung wäre, wenn man z.B. mehrere von Math abgeleitete Konstruktoren schreiben würde, und man dann Math.prototype.member definieren würde, um allen Objekten, die mit diesen Konstruktoren erzeugt wurden und werden, neue Member zu verpassen.
function ABC = function () {}; ABC.prototype = Math;
function ABC = function () {}; DEF.prototype = Math;
var x = new ABC();
var y = new ABC();
Math.prototype.neueFunktion = function () { alert("neue Funktion"); };
x.neueFunktion();
y.neueFunktion();
Math.prototype
~~~ existiert aber nicht - und das war der Knackpunkt, auf den den Frage hinauswollte.
> `Math.round = function () { return "Hallo Welt"; }`{:.language-javascript}
Anscheinend alle vordefinierten Methoden lassen sich überschreiben. Ich weiß nicht, ob das ein Erfordernis von ECMAScript ist oder einfach nur gängig bei den Browsern (nach erfolgloser Recherche glaube ich letzteres). Zumindest kann ich es nicht als Notwendigkeit erklären.
Zwar wirkt sich diese Änderung auch auf abgeleitete Objekte aus, die Math als Prototyp haben. Prototypische Erweiterung im Sinne der Frage ist dieses Überschreiben aber nicht - auch wenn ich zugestehen muss, dass es zumindest faktisch prototypischer Erweiterung gleichkommt. Aber wie gesagt kenne ich keine Regeln, die dieses Verhalten vorschreiben.
> Beim Regular Expression Objekt hingegen ist meiner Meinung nach eine
> "sinnvolle" Erweiterung nicht möglich oder kann hier mal jemand ein
> Beispiel bringen, wo dann auch noch das Regular Expression Objekt als
> solches funktioniert.
Es gibt zum Beispiel die proprietären Eigenschaften leftContext, lastMatch und rightContext, die am RegExp-Objekt selbst, nicht an den Instanzen hängen. Die kann man nachbauen (z.B. für Browser, die sie nicht kennen) und sie an die jeweilige Instanz hängen. Wir definieren also die exec-Funktion neu:
~~~javascript
RegExp.prototype._exec = RegExp.prototype.exec;
RegExp.prototype.exec = function (str) {
var res = this._exec(str);
this.res = res;
this.leftContext = this.res.input.substring(0, this.res.index);
this.lastMatch = this.res[0];
this.rightContext = this.res.input.substr(this.res.index + this.res[0].length);
return res;
};
var str = "foobarquuxbarmuh";
var exp = new RegExp("b.r", "g");
var res;
while (res = exp.exec(str)) {
alert(exp.leftContext + "[" + exp.lastMatch + "]" + exp.rightContext + "\n" +
RegExp.leftContext + '[' + RegExp.lastMatch + ']' + RegExp.rightContext);
}
Getestet mit Gecko.
(Jetzt nur als schnelles Beispiel, der Code funktioniert wahrscheinlich nicht mit allen anderen denkbaren regulären Ausdrücken und die erzeugten Eigenschaften sind somit wahrscheinlich nicht immer äquivalent zu den gleichnamigen am RegExp-Objekt.)
Mathias