使用原型 apply vs this 来调用函数

Using prototype apply vs this to call function

MDN String 页面上,他们有一个 polyfill 示例 String.includes。

String.prototype.includes = function() {'use strict';
    return String.prototype.indexOf.apply(this, arguments) !== -1;
};

他们使用 String.prototype.indexOf.apply 与直接在 this 上调用 indexOf 有什么原因吗?

String.prototype.includes = function(searchString, position) {'use strict';
    return this.indexOf(searchString, position) !== -1;
};

是的,这样做是有原因的。它确保即使字符串的 indexOf 属性 被覆盖,仍然会使用原来的 indexOf 属性

如果我们使用 new String 构造函数,这样的事情是可能的。

var s = new String('test');
s.indexOf = function() {
    throw new Error('this is bad');
};
s.indexOf('test');//Throws error.

String.prototype.indexOf可以接受一个或两个参数,使用 apply 可以让你简单地传递进来的东西,因为它进来了,而不用担心类型或存在检查。

答案是使用 this.indexOf 的 polyfill 版本不符合 spec for String.prototype.includes,它允许 this 是任何可转换为字符串的东西:

If searchString appears as a substring of the result of converting this object to a String...

例如,thisincludes 可以是一个数字:

<< String.prototype.includes.call(1, '1')
>> true

这类似于 String.prototype.indexOf,根据 spec 也不需要它的 this 是一个字符串。

<< String.prototype.indexOf.call(1, '1')
>> 0

如果 includes 按照 OP 建议的 this.indexOf:

实施
String.prototype.includes = function(searchString, position) {'use strict';
    return this.indexOf(searchString, position) !== -1;
};

然后使用非字符串 this 调用 includes,如规范所允许,会生成 运行 时错误:

<< String.prototype.includes.call(1, '1')
>> TypeError: undefined is not a function

而 MDN polyfill:

String.prototype.includes = function() {'use strict';
    return String.prototype.indexOf.apply(this, arguments) !== -1;
};

可以正常工作,利用 String.prototype.indexOfthis 也不必是字符串这一事实:

<< String.prototype.includes.call(1, '1')
>> true

所以我想 MDN polyfill 是这样写的,不是为了防止 indexOf 方法在某些特定字符串对象上被覆盖,或者作为 shorthand 以避免必须列出参数,或者由于某些克罗克福德人偏爱 prototype.apply 习语,而是为了正确实施规范。