聊聊 Array 中的坑

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

内容简介:原文:翻译:疯狂的技术宅本文首发微信公众号: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 中的坑》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

宇宙涟漪中的孩子

宇宙涟漪中的孩子

谢云宁 / 四川科学技术出版社 / 2017-11 / 28.00元

近未来。日冕科技公司通过建造围绕太阳的光幕搜集了近乎无穷的能源,这些能源主要用于地球上的网络空间建设。随着全球网络时间频率的不断提升,越来越多的人选择接驳进虚拟空间,体验现实中难以经历的丰富人生。 网络互动小说作者宁天穹一直自认为是这些人中普通的一员,有一天却被一名读者带进反抗组织,了解到日冕公司的各种秘密,并被告知自己的小说将在抵抗运动中起到重要作用。 起初他拒绝参与,但看到地球被笼......一起来看看 《宇宙涟漪中的孩子》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具