Bereichsfehler beim Überschreiben der Object.prototype-Methode mit dem Funktionskonstruktor
Ich versuche, Object.prototype.toString
ein Gebot zu überschreiben , um Funktionen für zusätzliche Klassenbeschreibungen hinzuzufügen.
Hier ist der Anfangscode:
(function(toString){
Object.prototype.toString = function(){
if(this instanceof TestClass)
{
return '[object TestClass]';
}
return toString.apply(this, arguments);
}
})(Object.prototype.toString);
function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);
Wenn ich dies in der Konsole ausführe, erhalte ich die folgende Ausgabe:
[object TestClass]
Das Gute ist, dass es die Funktionsweise nicht drastisch verändert. Object.prototype.toString
Bei einem anderen Typ [dh nicht TestClass] funktionieren die Dinge also wie erwartet, z . B. Object.prototype.toString.call(12)
werden ausgegeben [object Number]
.
Diese Implementierung funktioniert bisher ohne Probleme. Ich habe jedoch eine andere Implementierung mit dem folgenden Code:
(function(toString){
var fn_code_str = `return function(){
if(this instanceof TestClass)
{
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`;
var pre_fn = new Function(fn_code_str);
Object.prototype.toString = pre_fn();
})(Object.prototype.toString);
function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);
Damit erhalte ich die richtige Ausgabe für TestClass, aber wenn ich etwas anderes verwende, wie z. B. 12
einen RangeError:
VM527:5 Uncaught RangeError: Maximum call stack size exceeded
at Function.[Symbol.hasInstance] (<anonymous>)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:5:21)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
Dies scheint ein Problem mit der Rekursion von zu sein toString.apply
. Ich kann jedoch nicht herausfinden, warum diese zweite Implementierung rekursiv ist, wenn die erste dies nicht tut.
Hinweis : Der Grund für diese zweite Implementierung besteht darin, den Typprüfungscode [dh if(this instanceof MyClassType){return '[object MyClassType]'}
] für verschiedene Klassen dynamisch aus einer Liste von Klassennamen in einem Array hinzuzufügen . Mit anderen Worten, anstatt den Code für jede neue Klasse zu ändern, füge ich stattdessen den Klassennamen an das Array an, und die bedingte Anweisung wird automatisch generiert.
Antworten
Das Problem ist, dass der toString
Parameter Ihres IIFE in Ihrem new Function
Code nicht im Gültigkeitsbereich liegt . Stattdessen wird das globale toString
= window.toString
= verwendet Object.prototype.toString
.
Um dies zu beheben, müssen Sie die toString
Variable im new Function
Code des Codes deklarieren , damit der zurückgegebene Abschluss funktioniert. Entweder als einfache Konstante:
(function() {
var pre_fn = new Function(`
const toString = Object.prototype.toString;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return function(){
if(this instanceof TestClass) {
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`);
Object.prototype.toString = pre_fn();
})();
oder als Parameter:
(function() {
var pre_fn = new Function('toString', `
// ^^^^^^^^^^^
return function(){
if(this instanceof TestClass) {
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`);
Object.prototype.toString = pre_fn(Object.prototype.toString);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
})();