除了在Firefox中,为什么.call on String.methods无处可用

时间:2014-09-18 21:46:37

标签: javascript string node.js google-chrome firefox

我想知道尝试将数组中的所有小写项目转换为大写。 我正在评估一些变体并检查.call()变体最快的变体(http://jsperf.com/uppercaseperformance

使用以下代码在Firefox(32.0.1)中运行良好:

console.log(String.toUpperCase.call(null,['a', 'lower', 'case', 'string', 'array']))

仅限Firefox中的输出:

A,LOWER,CASE,STRING,ARRAY <- Thats nice ;)

相同的代码不适用于Chrome,Safari,node.js等。 Chrome / Safari输出:

TypeError: Cannot read property 'call' of undefined

node.js输出:

TypeError: Cannot call method 'call' of undefined

这可能是在错误的上下文中使用.call吗? <{3}}网站上的浏览器兼容性显示应支持.call()

3 个答案:

答案 0 :(得分:4)

String generic methods不是ECMAScript标准的一部分,它们仅在Firefox中提供。

您可以为所有其他浏览器(直接从MDN复制):

/*globals define*/
// Assumes all supplied String instance methods already present
// (one may use shims for these if not available)
(function () {
    'use strict';

    var i,
        // We could also build the array of methods with the following, but the
        //   getOwnPropertyNames() method is non-shimable:
        // Object.getOwnPropertyNames(String).filter(function (methodName)
        //  {return typeof String[methodName] === 'function'});
        methods = [
            'quote', 'substring', 'toLowerCase', 'toUpperCase', 'charAt',
            'charCodeAt', 'indexOf', 'lastIndexOf', 'startsWith', 'endsWith',
            'trim', 'trimLeft', 'trimRight', 'toLocaleLowerCase',
            'toLocaleUpperCase', 'localeCompare', 'match', 'search',
            'replace', 'split', 'substr', 'concat', 'slice'
        ],
        methodCount = methods.length,
        assignStringGeneric = function (methodName) {
            var method = String.prototype[methodName];
            String[methodName] = function (arg1) {
                return method.apply(arg1, Array.prototype.slice.call(arguments, 1));
            };
        };

    for (i = 0; i < methodCount; i++) {
        assignStringGeneric(methods[i]);
    }
}());

请注意,使用上面的垫片只会在此基础上添加一些抽象:

String.prototype.toUpperCase.apply(['a', 'lower', 'case', 'string', 'array']);
// "A,LOWER,CASE,STRING,ARRAY"

这里有趣的部分是一个数组被用作String方法的this值。

根据规范(§ 15.5.4.18 - &gt; § 15.5.4.16步骤2),this绑定通过内部ToString算法强制转换为字符串,对于对象(注意数组是对象)调用内部ToPrimitive算法,该算法又调用数组的toString方法,该方法又使用空参数列表调用数组的join方法。

也就是说,调用.toUpperCase()将数组作为this绑定传递将首先隐式地将this强制转换为字符串:

['a', 'b'].toString() === ['a', 'b'].join();
['a', 'b'].join() === 'a,b';

然后toUpperCase会将此字符串的字符映射到等效的大写字符。因此:

String.prototype.toUpperCase.apply(['a', 'b']) === ['a', 'b'].join().toUpperCase();

答案 1 :(得分:3)

这似乎是Firefox的一个特点,更多的是一个隐藏的功能,而不是一个bug。

实际上,按照标准,{p> toUpperCase仅作为prototype method of String提供,因此应在有效实例上调用。你当然可以尝试:

String.prototype.toUpperCase.call(null,['a', 'lower', 'case', 'string', 'array'])

在Chrome中,显然会返回:

TypeError: String.prototype.toUpperCase called on null or undefined

在其上调用call(null, ...)时,将使用空this引用调用实例方法。您尝试is only implemented in Firefox的静态调用样式,而不是任何当前ECMAScript标准的一部分。

答案 2 :(得分:1)

试试这个String.prototype.toUpperCase.call(['a', 'lower', 'case', 'string', 'array'])