美文网首页
ES6...扩展运算符的实现原理

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

作者: AoeKeller | 来源:发表于2021-08-29 14:36 被阅读0次

    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. 都不满足的话抛出类型错误。

    相关文章

      网友评论

          本文标题:ES6...扩展运算符的实现原理

          本文链接:https://www.haomeiwen.com/subject/wvnwiltx.html