使用函数构造函数覆盖 Object.prototype 方法时出现范围错误 [英] Range error when overriding Object.prototype method with Function constructor

查看:49
本文介绍了使用函数构造函数覆盖 Object.prototype 方法时出现范围错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图覆盖 Object.prototype.toString 以添加额外类描述的功能.

I'm trying to override Object.prototype.toString in a bid to add functionality for additional class descriptions.

这是初始代码:

(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:

[object TestClass]

好消息是它不会彻底改变 Object.prototype.toString 的工作方式,所以使用另一种类型 [即不是 TestClass],事情按预期工作,例如Object.prototype.toString.call(12) 会输出[object Number].

The good thing is that it doesn't drastically modify the way Object.prototype.toString works, so with another type [i.e. not TestClass], things work just as expected e.g. 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);

有了这个,我得到了 TestClass 的正确输出,但是当我使用其他东西时,比如 12,我得到一个 RangeError:

With this, I get the proper output for TestClass, but when I use something else, like 12, I get a 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 的递归问题.但是,我不明白为什么第二个实现是递归的,如果第一个没有?

This appears to be an issue with recursion of toString.apply. However, I can't figure out why this second implementation is recursing, if the first one does not?

注意:第二个实现的原因是添加类型检查代码[即if(this instanceof MyClassType){return '[object MyClassType]'}] 从数组中的类名列表中动态返回不同的类.换句话说,不是为我想出的每个新类修改代码,而是将类名附加到数组中,然后自动生成条件语句.

Note: The reason for this second implementation is to add the type-checking code [i.e. if(this instanceof MyClassType){return '[object MyClassType]'}] for different classes dynamically from a list of class names in an array. 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.

推荐答案

问题是您的 IIFE 的 toString 参数不在您的 new Function 代码范围内.相反,它使用全局 toString = window.toString = Object.prototype.toString.

The problem is that the toString parameter of your IIFE is not in scope in your new Function code. Instead, it uses the global toString = window.toString = Object.prototype.toString.

要解决这个问题,您需要在 new Function 的代码中声明 toString 变量,以使返回的闭包起作用.或者作为一个简单的常量:

To fix this, you need to declare the toString variable inside the new Function's code to make the returned closure work. 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();
})();

或作为参数:

(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 方法时出现范围错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆