0

我正在尝试覆盖Object.prototype.toString以添加其他类描述的功能。

这是初始代码:

(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]'}从数组中的类名列表中为不同的类动态添加类型检查代码[即]。换句话说,我没有为我提出的每个新类修改代码,而是将类名附加到数组中,并且自动生成条件语句。

4

1 回答 1

3

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

要解决此问题,您需要toString在 's 代码中声明变量new Function以使返回的闭包工作。要么作为一个简单的常数:

(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);
//                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
})();
于 2020-11-30T15:42:38.900 回答