ES6...扩展运算符的实现原理

2021-08-29  本文已影响0人  AoeKeller

ES6...扩展运算符的实现原理-记录TypeError("Invalid attempt to spread non-iterable instance")的问题分析

最近重构的新项目上线,观察前端监控日志有类型错误

TypeError("Invalid attempt to spread non-iterable instance")

提示的报错机型是,Android5.1.1的vivoXplay5,vivo 6sPlus等vivo系列。找不到对应机型但是有Android5.1.1的OPPO,结果OPPO是正常的。只好自己爬代码分析。
该类型错误是因为使用了ES6的扩展运算符展开MapIterator对象报错。但查阅了canisue网站,Map.values等是支持5.1.1系统的。怀疑代码报错的地方是

[...MapObje.values()]

转义后的代码如下

k = Object(o["a"])(u["a"].values())

Object(o["a"])的最终调用如下的d(t)函数

"75fc": function(t, e, n) {
  "use strict";
  var r = n("a745")
    , i = n.n(r);
  function o(t) {
    if (i()(t)) {
      for (var e = 0, n = new Array(t.length); e < t.length; e++)
        n[e] = t[e];
      return n
    }
  }
  ......
  function l(t) {
    if (u()(Object(t)) || "[object Arguments]" === Object.prototype.toString.call(t))
      return s()(t)
  }
  function f() {
    throw new TypeError("Invalid attempt to spread non-iterable instance")
  }
  function d(t) {
    return o(t) || l(t) || f()
  }
  n.d(e, "a", (function () {
    return d
  }
  ))
},

进入d(t)的o(t)中,o(t)的实现就是判断入参是否是数组,也就是Array.isArray(),判断t如果是数组的话直接生成一个新数组,拷贝t中的属性。

function o(t) {
    if (i()(t)) {
      for (var e = 0, n = new Array(t.length); e < t.length; e++)
        n[e] = t[e];
      return n
    }
  }

如果o(t)不满足的话,进入l(t)中,l(t)的u()(Object(t)主要是判断是否实现了Symbol.iterator迭代器接口

t.exports = n("584a").isIterable = function(t) {
            var e = Object(t);
            return void 0 !== e[i] || "@@iterator"in e || o.hasOwnProperty(r(e))
        }

其中 e[i]是指的对象是否有实现Symbol.iterator,否则的话判断是否有@@iterator,或者o.hasOwnProperty(r(e)),

截屏2021-08-29 上午9.34.16.png

其中r函数也很简单,是一个类型检测功能

void 0 === t ? "Undefined" : null === t ? "Null" : "string" == typeof (n = a(e = Object(t), i)) ? n : o ? r(e) : "Object" == (s = r(e)) && "function" == typeof e.callee ? "Arguments" : s

基于以上,猜测目前是因为Android5.1.1的vivo系统可能对Map的Iterator接口实现有问题,但是目前找不到该手机,只能是猜测,后面找到真机后在调试定位。
总结扩展运算符的实现原理:

  1. 是否是数组,数组直接浅拷贝属性
  2. 是否实现Iterator接口,检测方式包括是否有实现Symbol.iterator、@@Iterator、是否是其他可迭代对象等(叫可迭代也不合适好像)、或者对象本身是否是Arguments
  3. 都不满足的话抛出类型错误。
上一篇下一篇

猜你喜欢

热点阅读