聊聊 Array 中的坑

栏目: JavaScript · 发布时间: 7年前

内容简介:原文:翻译:疯狂的技术宅本文首发微信公众号:jingchengyideng

原文: https://jakearchibald.com/201...

翻译:疯狂的技术宅

本文首发微信公众号:jingchengyideng

欢迎关注,每天都给你推送新鲜的前端技术文章

Array 类型检测

function foo(obj) {
  // …
}

假设 obj 是一个数组,我们想要实现一些功能。比如 JSON.stringify 就是一个例子,它以不同的方式把数组输出到其他对象。

我们可以这样做:

if (obj.constructor == Array) // …

但是对于数组的子类来说这是错误的:

class SpecialArray extends Array {}
const specialArray = new SpecialArray();
console.log(specialArray.constructor === Array); // false
console.log(specialArray.constructor === SpecialArray); // true

所以如果你想检查子类的类型,那么应该用 instanceof

console.log(specialArray instanceof Array); // true
console.log(specialArray instanceof SpecialArray); // true

但是当引入多个realm时,事情将会变得更加复杂:

Multiple realms

realm包含 self 引用的JavaScript全局对象。 因此,可以说在worker中运行的代码与在页面中运行的代码处于不同的realm。 在iframe之间也是如此,但同源iframe也共享一个ECMAScript'代理',这意味着对象可以 穿越 realm

接着看代码:

<iframe srcdoc="<script>var arr = [];</script>"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  const arr = iframe.contentWindow.arr;
  console.log(arr.constructor === Array); // false
  console.log(arr.constructor instanceof Array); // false
</script>

这两个都是false,因为:

console.log(Array === iframe.contentWindow.Array); // false

iframe有自己的数组构造函数,它与父页面中的构造函数不同。

Array.isArray

console.log(Array.isArray(arr)); // true

Array.isArray 将为数组返回true,即使它们是在另一个realm中创建的。 对于任何realm的 Array 的子类,它也会返回true。 这就是 JSON.stringify 内部的处理方法。

但是,这并不意味着 arr 有 array 方法。 有些甚至所有方法都已设置为undefined,或者数组可能已将其整个原型删除:

const noProtoArray = [];
Object.setPrototypeOf(noProtoArray, null);
console.log(noProtoArray.map); // undefined
console.log(noProtoArray instanceof Array); // false
console.log(Array.isArray(noProtoArray)); // true

不管怎样,如果要杜绝上述问题,可以通过Array原型调用Array的方法:

if (Array.isArray(noProtoArray)) {
  const mappedArray = Array.prototype.map.call(noProtoArray, callback);
  // …
}

Symbols 与 realms

再看看这个:

<iframe srcdoc="<script>var arr = [1, 2, 3];</script>"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  const arr = iframe.contentWindow.arr;

  for (const item of arr) {
    console.log(item);
  }
</script>

上面的logs 1, 2, 3 很不引人注目,但 for-of 循环通过调用 arr[Symbol.iterator] 来工作,这在某种程度上可以跨越realm。 这是如何做:

const iframe = document.querySelector('iframe');
const iframeWindow = iframe.contentWindow;
console.log(Symbol === iframeWindow.Symbol); // false
console.log(Symbol.iterator === iframeWindow.Symbol.iterator); // true

虽然每个realm都有自己的Symbol实例,但Symbol.iterator在各个realm都是相同的。

Symbols同时也是JavaScript中最独特和最独特的东西。

The most unique 多唯一性

const symbolOne = Symbol('foo');
const symbolTwo = Symbol('foo');
console.log(symbolOne === symbolTwo); // false
const obj = {};
obj[symbolOne] = 'hello';
console.log(obj[symbolTwo]); // undefined
console.log(obj[symbolOne]); // 'hello'

传递给 Symbol 函数的字符串只是一个描述。 即使在同一realm内,这些Symbol也是独一无二的。

The least unique 最小唯一性

const symbolOne = Symbol.for('foo');
const symbolTwo = Symbol.for('foo');
console.log(symbolOne === symbolTwo); // true
const obj = {};
obj[symbolOne] = 'hello';
console.log(obj[symbolTwo]); // 'hello'

Symbol.for(str) 创建一个与传递它的字符串唯一的symbol。 有趣的是它在各个realms都是一样的:

const iframe = document.querySelector('iframe');
const iframeWindow = iframe.contentWindow;
console.log(Symbol.for('foo') === iframeWindow.Symbol.for('foo')); // true

这就是 Symbol.iterator 大致的工作原理。

创建自己的 'is' 函数

如果我们想要创建我们自己的“is”函数并跨越realm会怎么样? 好吧,Symbol允许我们这样做:

const typeSymbol = Symbol.for('whatever-type-symbol');

class Whatever {
  static isWhatever(obj) {
    return obj && Boolean(obj[typeSymbol]);
  }
  constructor() {
    this[typeSymbol] = true;
  }
}

const whatever = new Whatever();
Whatever.isWhatever(whatever); // true

即使实例来自另一个realm,即使它是一个子类,即使它的原型已被删除,也是可以的。

唯一的问题是,你需要确认自己的symbol名称在所有代码中都是唯一的。 如果其他人创建了他们自己的 Symbol.for('whatever-type-symbol') 并使用它来表示别的东西,那么 isWhatever 肯定返回false。

本文首发微信公众号:jingchengyideng

欢迎关注,每天都给你推送新鲜的前端技术文章


以上所述就是小编给大家介绍的《聊聊 Array 中的坑》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Operating Systems

Operating Systems

Remzi Arpaci-Dusseau、Andrea Arpaci-Dusseau / Arpaci-Dusseau Books / 2012-8-19 / USD 21.00

A book about modern operating systems. Topics are broken down into three major conceptual pieces: Virtualization, Concurrency, and Persistence. Includes all major components of modern systems includin......一起来看看 《Operating Systems》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换