资讯专栏INFORMATION COLUMN

聊聊 Array 中的坑

songze / 2048人阅读

摘要:原文翻译疯狂的技术宅本文首发微信公众号欢迎关注,每天都给你推送新鲜的前端技术文章类型检测假设是一个数组,我们想要实现一些功能。将为数组返回,即使它们是在另一个中创建的。本文首发微信公众号欢迎关注,每天都给你推送新鲜的前端技术文章

原文: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

接着看代码:


这两个都是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

再看看这个:


上面的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
欢迎关注,每天都给你推送新鲜的前端技术文章

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101233.html

相关文章

  • 【Copy攻城狮日志】聊聊JavaScript heap out of memory

    摘要:当时,如果老生区大小超过设定的值时,就会报错。一般是无限制增长的数组无限制设置属性和值大循环等出处林小新。这部分由于攻城狮并为深入,可以参考如何定位的内存泄漏内存泄漏以及定位 showImg(https://segmentfault.com/img/bVbnysD?w=649&h=658);↑开局一张图,故事全靠编↑ 从一次宕机说起 这是一个很狗血的故事,故事的开头是一个项目,这个项...

    paulquei 评论0 收藏0
  • 聊聊javascript中的数组

    摘要:数组定义数组数组名称元素元素定义空数组前端定义数组同时添加不同类型的元素构造函数方式数组名称元素,元素数组名称类型,表示数组的长度存在元素的个数用创造出一个空数组的构造函数前端用创造一个空数组的构造函数并添加元素函数方式定义数组名称元素,元 数组 定义数组 1.var 数组名称 = [元素1,元素2,...]; var arr=[];//定义空数组 var arr1=[100,前端,t...

    Towers 评论0 收藏0
  • 基于Vue2实现的仿手机QQapp(支持对话功能,滑动删除....)—— 聊聊开发过程中踩到的一些坑

    摘要:使用进行的仿手机的的制作,在上,参考了设计师的作品,作品由个人独立开发,源码中进行了详细的注释。关于接入聊天机器人遇到的跨域问题起初,天真的以为官方应该提供了用的接口,然而没有找到。 使用Vue2进行的仿手机QQ的webapp的制作,在ui上,参考了设计师kaokao的作品,作品由个人独立开发,源码中进行了详细的注释。 由于自己也是初学Vue2,所以注释写的不够精简,请见谅。 目前已实...

    williamwen1986 评论0 收藏0
  • ES6时代,你真的会克隆对象吗(二)

    摘要:多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。比如,表达式会返回,因为属性得到的仅仅是构造函数,而且是可以被手动更改的,只是返回的构造函数的名字,它并不返回类名。 原文:ES6时代,你真的会克隆对象吗(二) 上一篇,我们从Symbol和是否可枚举以及属性描述符的角度分析了ES6下怎么浅拷贝一个对象,发表在掘金和segmentfault上(...

    BoYang 评论0 收藏0
  • 聊聊在javascript中数组的使用

    摘要:在中,数组里可以容纳容纳中任何类型的值。方法大全在中数组是可修改的对象,每个数组都有着很多好用的方法,大多数我们日常都会常用。把元素添加到数组的头部。利用使用下标进行操作。对当前数组中的每一项运行给定的函数返回函数结果为的项组成的数组。 杂谈     数组是最简单的内存数据结构,也是js中最常用的类型之一,整理了下我觉得应该了解数组的相关知识。 在js中,数组里可以容纳容纳js中任何...

    zone 评论0 收藏0

发表评论

0条评论

songze

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<