简体   繁体   English

使用 Function 构造函数覆盖 Object.prototype 方法时出现范围错误

[英]Range error when overriding Object.prototype method with Function constructor

I'm trying to override Object.prototype.toString in a bid to add functionality for additional class descriptions.我正在尝试覆盖Object.prototype.toString以添加其他 class 描述的功能。

Here's the initial code:这是初始代码:

(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);

When I run this in the console, I get the following output:当我在控制台中运行它时,我得到以下 output:

[object TestClass]

The good thing is that it doesn't drastically modify the way Object.prototype.toString works, so with another type [ie not TestClass], things work just as expected eg Object.prototype.toString.call(12) will output [object Number] . The good thing is that it doesn't drastically modify the way Object.prototype.toString works, so with another type [ie not TestClass], things work just as expected eg Object.prototype.toString.call(12) will output [object Number]

This implementation works with no issues so far.到目前为止,此实现没有问题。 However, I have another implementation with the following 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);

With this, I get the proper output for TestClass, but when I use something else, like 12 , I get a RangeError:有了这个,我得到了 TestClass 的正确 output ,但是当我使用其他东西时,比如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)

This appears to be an issue with recursion of toString.apply .这似乎是toString.apply递归的问题。 However, I can't figure out why this second implementation is recursing, if the first one does not?但是,我不知道为什么第二个实现是递归的,如果第一个没有?

Note : The reason for this second implementation is to add the type-checking code [ie if(this instanceof MyClassType){return '[object MyClassType]'} ] for different classes dynamically from a list of class names in an array.注意:第二个实现的原因是从数组中的 class 名称列表中为不同的类动态添加类型检查代码 [即if(this instanceof MyClassType){return '[object MyClassType]'} ]。 In other words, rather than modifying code for each new Class I come up with, I append the class name to the array instead, and the conditional statement is generated automatically.换句话说,我没有为我想出的每个新的 Class 修改代码,而是将 append 的 class 名称改为数组,并自动生成条件语句。

The problem is that the toString parameter of your IIFE is not in scope in your new Function code.问题是您的 IIFE 的toString参数不在您的new Function代码中的 scope 中。 Instead, it uses the global toString = window.toString = Object.prototype.toString .相反,它使用全局toString = window.toString = Object.prototype.toString

To fix this, you need to declare the toString variable inside the new Function 's code to make the returned closure work.要解决此问题,您需要在new Function的代码中声明toString变量,以使返回的闭包起作用。 Either as a simple constant:要么作为一个简单的常数:

(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();
})();

or as a 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);
//                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM