使用 Function 构造函数覆盖 Object.prototype 方法时出现范围错误
Range error when overriding Object.prototype method with Function constructor
我正在尝试覆盖 Object.prototype.toString
以添加额外 class 描述的功能。
这是初始代码:
(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);
当我在控制台中 运行 时,我得到以下输出:
[object TestClass]
好处是它不会彻底改变 Object.prototype.toString
的工作方式,所以使用另一种类型 [即不是 TestClass],一切都按预期工作,例如Object.prototype.toString.call(12)
将输出 [object Number]
.
到目前为止,此实施没有任何问题。但是,我有另一个使用以下代码的实现:
(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);
有了这个,我得到了 TestClass 的正确输出,但是当我使用其他东西时,比如 12
,我得到了 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)
这似乎是 toString.apply
的递归问题。但是,我不明白为什么第二个实现是递归的,如果第一个不是?
注意:第二个实现的原因是添加类型检查代码[即if(this instanceof MyClassType){return '[object MyClassType]'}
] 用于从数组中的 class 名称列表中动态地获取不同的 classes。换句话说,我不是为每个新的 Class 修改代码,而是将 class 名称附加到数组,然后自动生成条件语句。
问题是您的 IIFE 的 toString
参数不在您的 new Function
代码的范围内。相反,它使用全局 toString
= window.toString
= Object.prototype.toString
.
要解决此问题,您需要在 new Function
的代码中声明 toString
变量以使返回的闭包起作用。作为一个简单的常量:
(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();
})();
或作为参数:
(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);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
})();
我正在尝试覆盖 Object.prototype.toString
以添加额外 class 描述的功能。
这是初始代码:
(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);
当我在控制台中 运行 时,我得到以下输出:
[object TestClass]
好处是它不会彻底改变 Object.prototype.toString
的工作方式,所以使用另一种类型 [即不是 TestClass],一切都按预期工作,例如Object.prototype.toString.call(12)
将输出 [object Number]
.
到目前为止,此实施没有任何问题。但是,我有另一个使用以下代码的实现:
(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);
有了这个,我得到了 TestClass 的正确输出,但是当我使用其他东西时,比如 12
,我得到了 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)
这似乎是 toString.apply
的递归问题。但是,我不明白为什么第二个实现是递归的,如果第一个不是?
注意:第二个实现的原因是添加类型检查代码[即if(this instanceof MyClassType){return '[object MyClassType]'}
] 用于从数组中的 class 名称列表中动态地获取不同的 classes。换句话说,我不是为每个新的 Class 修改代码,而是将 class 名称附加到数组,然后自动生成条件语句。
问题是您的 IIFE 的 toString
参数不在您的 new Function
代码的范围内。相反,它使用全局 toString
= window.toString
= Object.prototype.toString
.
要解决此问题,您需要在 new Function
的代码中声明 toString
变量以使返回的闭包起作用。作为一个简单的常量:
(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();
})();
或作为参数:
(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);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
})();