我在MDN上执行Array.isArray方法的polyfill时,我发现了以下内容:
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}虽然这是可行的,但我想知道为什么MDN没有列出以下内容作为isArray的polyfill
if (!Array.isArray) {
Array.isArray = function(arg) {
return arg.constructor === Array;
};
}上面的代码有点简短和简单。我想知道与上面的实现相比,使用MDN的实现有什么优势吗?
发布于 2020-05-29 06:18:44
使MDN polyfill成为可安全使用的polyfill的最重要原因是,数组是一个外来对象。区分外来物体的最好方法是通过使用与该物体相关的外来特征-也就是说,外来物体的外来属性。
如果查看Object.prototype.toString方法的规范,就会发现它使用了抽象操作isArray,该操作检查奇异的数组对象。
另一方面,看看constructor property的规范。它不是数组的奇特属性,所以javascript代码可以很容易地更改它。
const x = [];
x.constructor = Object事实上,构造函数属性更多地用于元编程。您可以-在es5中-创建子类,而不需要接触构造函数属性。
现在,以下是您的实现中可能出现问题的地方:
const customIsArray = function(arg) {
return arg.constructor === Array;
};
// 1) won't work with subclasses of Array
class CustomArray extends Array {
// ...
}
const customArray = new CustomArray()
customIsArray(customArray) // false
Array.isArray(customArray) // true
// 2) won't work across different realms (iframes, web workers, service workers ... if we are speaking about the browser environment)
const iframe = document.createElement('iframe')
document.body.appendChild(iframe)
const IframeArray = iframe.contentWindow.Array;
const iframeArray = new IframeArray();
customIsArray(iframeArray) // false
Array.isArray(iframeArray) // true
// 3) won't work with few edge cases like (customIsArray will return true, while Array.isArray will return false)
const fakeArray1 = { __proto__: Array.prototype }
const fakeArray2 = { constructor: Array }
customIsArray(fakeArray1) // true
Array.isArray(fakeArray1) // false
customIsArray(fakeArray2) // true
Array.isArray(fakeArray2) // false 发布于 2020-05-29 04:45:05
一个问题是,一个constructor属性为Array的非数组对象会在不应该传递的时候传递:
// Bad polyfill, do not use
Array.isArray = function(arg) {
return arg.constructor === Array;
};
const badObj = {};
badObj.constructor = Array;
console.log(Array.isArray(badObj));
上面的情况非常奇怪,但polyfill必须尽可能符合规范,即使它需要更复杂的代码。
https://stackoverflow.com/questions/62074163
复制相似问题