# 2019年05月刊

# 2019/05/27 - 2019/06/02 ⌚️


  • 几种进制的相互转换计算方法,在 JavaScript 中如何表示和转换

    点击

    parseInt(str, radix) 将一个 radix 进制的 str 转化为十进制,parseInt('23',8) // 19,将八进制的‘23’转化为10进制的‘19’

    number.toString(radix) 将一个数字转化为 radix 进制的数字字符串

    (0x11).toString(8); // 21
    (0x11).toString(10); // 17
    (0x11).toString(2); // 10001
    
    1
    2
    3
  • 使用 CSS 绘制几何图形(圆形、三角形、扇形、菱形等) (opens new window)

  • BFC 实现原理,可以解决的问题,如何创建 BFC

    点击

    BFC(Block formatting context) 直译为"块级格式化上下文"。它是一个独立的渲染区域,只有块级元素参与, 它规定了内部的块级元素如何布局,并且与这个区域外部毫不相干。

    BCF 可以解决的问题:浮动定位,消除外边距折叠,清除浮动,自适应多栏布局

    BFC 的创建:根元素或包含根元素的元素,浮动元素(float 不为 none),绝对定位元素( positionabsolute 或者 fixed),displayinline-block,table-cell,table-caption,overflow 值不为 visible,弹性元素( flex 布局),网格元素( grid 布局)

  • 理解 JavaScript 的执行上下文栈,可以应用堆栈信息快速定位问题

    点击

    执行上下文 就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。

    执行上下文总共有三种类型:全局执行上下文, 函数执行上下文, Eval 函数执行上下文

    执行栈,在其他编程语言中也被叫做调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。

  • null 和 undefined 的区别

    点击
    1. Number 转换的值不同,Number(null) 输出为 0, Number(undefined) 输出为 NaN

    2. null 表示一个值被定义了,但是这个值是空值

    3. undefined 表示缺少值,即此处应该有值,但是还没有定义

  • 理解值类型和引用类型

    点击

    JavaScript 中的变量分为基本类型和引用类型:

    基本类型: 保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问

    引用类型: 保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript 不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用

  • 基本类型对应的内置对象,以及他们之间的装箱拆箱操作

    点击

    String(), Number(), Boolean()

    装箱:就是把基本类型转变为对应的对象。装箱分为隐式和显示

    // 隐式装箱: 每当读取一个基本类型的值时,后台会创建一个该基本类型所对应的对象。
    // 在这个基本类型上调用方法,其实是在这个基本类型对象上调用方法。
    // 这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立刻被销毁。
    let num = 123;
    num.toFixed(2); // '123.00'//上方代码在后台的真正步骤为
    var c = new Number(123);
    c.toFixed(2);
    c = null;
    // 显式装箱: 通过内置对象 Boolean、Object、String 等可以对基本类型进行显示装箱。
    var obj = new String('123');
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    拆箱: 拆箱与装箱相反,把对象转变为基本类型的值。

    Number([1]); //1
    // 转换演变:
    [1].valueOf(); // [1];
    [1].toString(); // '1';Number('1'); //1
    
    1
    2
    3
    4

# 2019/05/20 - 2019/05/26 ⌚️


  • null 是一种数据类型,可为什么 typeof null === 'object' ?

    点击

    虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object

  • 介绍下 Set、Map、WeakSet 和 WeakMap 的区别?

    点击
    • Set
      • 成员唯一、无序且不重复[value, value],键值与键名是一致的(或者说只有键值,没有键名)
      • 可以遍历,方法有:add、delete、has
    • WeakSet
      • 成员都是对象
      • 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏
      • 不能遍历,方法有 add、delete、has
    • Map
      • 本质上是键值对的集合,类似集合
      • 可以遍历,方法很多可以跟各种数据格式转换
    • WeakMap
      • 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
      • 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
      • 不能遍历,方法有 get、set、has、delete
  • 实现一个方法取多个数组的并集

    点击
    function merge(...args) {
      let arr = [];
      for (let i = 0; i < args.length; i++) {
        arr = arr.concat(args[i]);
        console.log(args[i]);
      }
      return [...new Set(arr)];
    }
    
    console.log(merge([0, 1, 2, 3], [1, 2, 3, 8], [1, 10])); // [ 0, 1, 2, 3, 8, 10 ]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 实现一个方法取多个数组的交集

    点击
    function intersect(...args) {
      if (args.length === 0) {
        return [];
      }
    
      if (args.length === 1) {
        return args[0];
      }
    
      return args.reduce((result, arg) => {
        return result.filter(item => arg.includes(item));
      });
    }
    
    console.log(intersect([0, 1, 2, 3], [1, 2, 3], [1])); // [1]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  • 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    let arr = [2, 2, 1, 4, 4, 5, 5, 1, 8];
    // 实现一个singleNumber找出不重复的8
    
    1
    2
    点击

    这道题第一眼看过去,思路挺简单的,我们只需要维护一个对象来记录每一个元素出现的次数,使用元素的值作为 key,元素出现的次数作为 value。之后再遍历这个对象,找到 value 为 1 的 key。对应的 key 就是那个元素。

    function singleNumber(nums) {
      const obj = {};
      for (let i = 0; i < nums.length; i++) {
        obj[nums[i]] = obj[nums[i]] ? obj[nums[i]] + 1 : 1;
      }
      for (let key in obj) {
        if (obj[key] === 1) {
          return Number(key); // 由于 key 是 string ,因此我们这里需要转化下
        }
      }
    }
    
    console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8])); // 8
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    当然,更好的解法是用异或解决,两个相同数异或得 0,因此不断异或,最后剩下得就是不重复的数字,当然这只是在这种特殊情况下才使用,应用场景不大

    function singleNumber(nums) {
      for (let i = 1; i < nums.length; i++) {
        nums[0] ^= nums[i];
      }
      return nums[0];
    }
    
    console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8]));
    
    1
    2
    3
    4
    5
    6
    7
    8
  • hash 路由和 history 路由的区别?

    点击

    路由的哈希模式其实是利用了 window 可以监听 onhashchange 事件,也就是说你的 url 中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(搞点事情),这么一来,即使前端并没有发起 http 请求他也能够找到对应页面的代码块进行按需加载。

    路由的 history 模式其实是利用了 pushStatereplaceState 这两个神器,其作用就是可以将 url替换并且不刷新页面,好比挂羊头卖狗肉,http 并没有去请求服务器该路径下的资源,一旦刷新就会暴露这个实际不存在的“羊头”,显示404

  • HTMLXHTML 有什么区别?

    点击

    XHTML 语法严格,主要不同包括:

    • XHTML 元素必须被正确地嵌套。
    • XHTML 元素必须被关闭。
    • 标签名必须用小写字母。
    • XHTML 文档必须拥有根元素。

# 2019/05/13 - 2019/05/19 ⌚️


  • 请解释 <script><script async><script defer> 的区别

    点击
    1. <script src="script.js"></script>

    没有 deferasync,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

    1. <script async src="script.js"></script>

    async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。

    1. <script defer src="myscript.js"></script>

    defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

  • html5 新标签有哪些?

    点击
    <article>
      标签定义外部的内容。比如来自一个外部的新闻提供者的一篇新的文章,或者来自
      blog 的文本,或者是来自论坛的文本。亦或是来自其他外部源内容。
    
      <aside>
        标签定义 article 以外的内容。aside 的内容应该与 article 的内容相关。
    
        <audio>
          标签定义声音,比如音乐或其他音频流。
    
          <canvas>
            标签定义图形,比如图表和其他图像。这个 HTML
            元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API
            展现给客户端 JavaScript 以使脚本能够把想绘制的东西都绘制到一块画布上。
    
            <command>
              标签定义命令按钮,比如单选按钮、复选框或按钮。
    
              <datalist>
                标签定义可选数据的列表。与 input
                元素配合使用,就可以制作出输入值的下拉列表。
    
                <details>
                  标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。与
                  <legend>
                    一起使用,来制作 detail
                    的标题。该标题对用户是可见的,当在其上点击时可打开或关闭
                    detail。
    
                    <figcaption>
                      标签定义 figure 元素的标题。”figcaption” 元素应该被置于
                      “figure” 元素的第一个或最后一个子元素的位置。 HTML5:
                      <figure><figcaption>PRC</figcaption></figure>
    
                      <figure>
                        标签用于对元素进行组合。使用
                        <figcaption>
                          元素为元素组添加标题。 HTML5:
                          <figure>
                            <figcaption>PRC</figcaption>
                            <p>
                              The People's Republic of China was born in 1949...
                            </p>
                          </figure>
    
                          <footer>
                            标签定义 section 或 document
                            的页脚。典型地,它会包含创作者的姓名、文档的创作日期以及/或者联系信息。
    
                            <header>
                              标签定义 section 或 document 的页眉。
    
                              <hgroup>
                                标签用于对网页或区段(section)的标题进行组合。
    
                                <nav>
                                  标签定义导航链接的部分。
    
                                  <section>
                                    标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
    
                                    <source />
                                    标签为媒介元素(比如
                                    <video><audio>
                                        )定义媒介资源。
    
                                        <video>
                                          标签定义视频,比如电影片段或其他视频流。
                                          HTML5:
                                          <video
                                            src="movie.ogg"
                                            controls="controls"
                                          >
                                            您的浏览器不支持 video 标签。
                                          </video>
                                        </video>
                                      </audio>
                                    </video>
                                  </section>
                                </nav>
                              </hgroup>
                            </header>
                          </footer>
                        </figcaption>
                      </figure>
                    </figcaption>
                  </legend></details
                >
              </datalist></command
            ></canvas
          >
        </audio>
      </aside>
    </article>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
  • <a> 标签中 href="javascript:;" 表示什么意思??

    点击

    这里的 href="javascript:;" ,其中 javascript: 是伪协议,它可以让我们通过一个链接来调用 javascript 函数.而采用这个方式 javascript:; 可以实现 A 标签的点击事件运行时,如果页面内容很多,有滚动条时,页面不会乱跳,用户体验更好。

  • 实现数组扁平化的方法?

    参考文章: 《数组的去重与扁平化》 (opens new window)

  • GitSVN 的区别?

    点击

    Git 和 SVN 孰优孰好,每个人有不同的体验。

    Git 是分布式的,SVN 是集中式的

    这是 Git 和 SVN 最大的区别。若能掌握这个概念,两者区别基本搞懂大半。因为 Git 是分布式的,所以 Git 支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而 SVN 必须联网才能正常工作。

    Git 复杂概念多,SVN 简单易上手

    所有同时掌握 Git 和 SVN 的开发者都必须承认,Git 的命令实在太多了,日常工作需要掌握 add,commit,status,fetch,push,rebase 等,若要熟练掌握,还必须掌握 rebase 和 merge 的区别,fetch 和 pull 的区别等,除此之外,还有 cherry-pick,submodule,stash 等功能,仅是这些名词听着都很绕。

    在易用性这方面,SVN 会好得多,简单易上手,对新手很友好。但是从另外一方面看,Git 命令多意味着功能多,若我们能掌握大部分 Git 的功能,体会到其中的奥妙,会发现再也回不去 SVN 的时代了。

    Git 分支廉价,SVN 分支昂贵

    在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要 feature 分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。

    Git 分支是指针指向某次提交,而 SVN 分支是拷贝的目录。这个特性使 Git 的分支切换非常迅速,且创建成本非常低。

    而且 Git 有本地分支,SVN 无本地分支。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用 Git,便可以创建本地分支存储没写完的代码,待问题处理完后,再回到本地分支继续完成代码。

  • 前端日志埋点方案?

    《小蝌蚪传记:200 行代码实现前端无痕埋点》 (opens new window)仅供参考,并不实用

  • npm、yarn 依赖包管理的原理,两者的区别 ?

    点击 首先,这两个都属于 js 包管理工具,都可以安装包或者模块, 两者命令有所不同

    yarn 是由 facebook、google 等联合开发推出的,具有速度快离线工作从多个源安装安装版本统一更简洁的输出多注册来源处理更好的语义化的优点

# 2019/05/06 - 2019/05/12 ⌚️


  • 如何有效避免回流与重绘 ?

    点击
    1. Display 的值会影响布局,从而影响页面元素位置变化,所以会更改渲染树的结构,慎用

    2. 使用 DocumentFragment 进行缓存操作,引发一次回流和重绘

    3. 使用 cloneNode (true or false) 和 replaceChild 技术,引发一次回流和重绘。

    4. 不要对元素进行 JS 动画流操作,尽量使用 CSS 动画属性,以减少回流的 Render Tree 的规模

  • 从输入 URL 到页面展现的详细过程 ?

    参考文章: 《输入 URL 至页面渲染》 (opens new window)

  • 浏览器跨标签通信 ?

    localstorage 或者 cookie 或者 url 传递参数

  • 浏览器海量数据存储 ?

    点击

    cookie 用于短期存储用户身份,登录状态等较小的信息;localStorage/sessionStorage 用于长期存储数据,浏览器关闭不影响它们的内存,相比于 cookie,storage 能存储较多;IndexedDB 是浏览器提供的接近于 NoSQL 的数据库,允许存储大量数据。

  • 域名解析的过程?

    点击

    1、在浏览器中输入 www.qq.com 域名,操作系统会先检查自己本地的 hosts 文件是否有这个网址映射关系,如果有,就先调用这个 IP 地址映射,完成域名解析。

    2、如果 hosts 里没有这个域名的映射,则查找本地 DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。

    3、如果 hosts本地DNS解析器缓存 都没有相应的网址映射关系,首先会找 TCP/ip 参数中设置的 首选DNS服务器,在此我们叫它 本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。

    4、如果要查询的域名,不由 本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个 IP 地址映射,完成域名解析,此解析不具有权威性。

    5、如果 本地DNS服务器 本地区域文件与缓存解析都失效,则根据 本地DNS服务器 的设置(是否设置转发器)进行查询,如果未用转发模式,本地 DNS 就把请求发至 13 台根 DNS,根 DNS 服务器收到请求后会判断这个域名 (.com) 是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP本地DNS服务器 收到 IP 信息后,将会联系负责 .com 域的这台服务器。这台负责 .com 域的服务器收到请求后,如果自己无法解析,它就会找一个管理 .com 域的下一级 DNS 服务器地址(http://qq.com)本地DNS服务器。当 本地DNS服务器 收到这个地址后,就会找 http://qq.com 域服务器,重复上面的动作,进行查询,直至找到 www.qq .com 主机。

    6、如果用的是转发模式,此 DNS 服务器就会把请求转发至上一级 DNS 服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根 DNS 或把转请求转至上上级,以此循环。不管是 本地DNS服务器 用是是转发,还是根提示,最后都是把结果返回给 本地DNS服务器,由此 DNS 服务器再返回给客户机。

  • JavaScript 异常处理的方式,统一的异常处理方案

    参考文章:《JavaScript 的异常处理》 (opens new window)

  • 如何解决页面加载海量数据而不冻结前端 UI ?

    点击
    题目:10w 条记录的数组,一次性渲染到页面上,如何处理可以不冻结UI?
    
    1

    分治思想,在一定的时间内多次加载数据,直至渲染完成,使用 window.requestAnimationFramedocument.createDocumentFragment() 实现

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>页面加载海量数据</title>
      </head>
    
      <body>
        <ul id="list-with-big-data">
          100000 数据
        </ul>
        <script>
          // 此处添加你的代码逻辑
          (function() {
            const ulContainer = document.getElementById('list-with-big-data');
    
            // 防御性编程
            if (!ulContainer) {
              return;
            }
    
            const total = 100000; // 插入数据的总数
            const batchSize = 4; // 每次批量插入的节点个数,个数越多,界面越卡顿
            const batchCount = total / batchSize; // 批处理的次数
            let batchDone = 0; // 已完成的批处理个数
    
            function appendItems() {
              // 使用 DocumentFragment 减少 DOM 操作次数,对已有元素不进行回流
              const fragment = document.createDocumentFragment();
    
              for (let i = 0; i < batchSize; i++) {
                const liItem = document.createElement('li');
                liItem.innerText = batchDone * batchSize + i + 1;
                fragment.appendChild(liItem);
              }
    
              // 每次批处理只修改 1 次 DOM
              ulContainer.appendChild(fragment);
              batchDone++;
              doAppendBatch();
            }
    
            function doAppendBatch() {
              if (batchDone < batchCount) {
                // 在重绘之前,分批插入新节点
                window.requestAnimationFrame(appendItems);
              }
            }
    
            // kickoff
            doAppendBatch();
    
            // 使用 事件委托 ,利用 JavaScript 的事件机制,实现对海量元素的监听,有效减少事件注册的数量
            ulContainer.addEventListener('click', function(e) {
              const target = e.target;
    
              if (target.tagName === 'LI') {
                alert(target.innerText);
              }
            });
          })();
        </script>
      </body>
    </html>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

# 2019/04/29 - 2019/05/05 ⌚️


  • ES6 class 构造以及继承的底层实现原理

    《ES6 类以及继承的实现原理》 (opens new window)

  • 手动实现一个 new ?

    点击
    function myNew(Obj, ...args) {
      var obj = Object.create(Obj.prototype); //使用指定的原型对象及其属性去创建一个新的对象
      Obj.apply(obj, args); // 绑定 this 到obj, 设置 obj 的属性
      return obj; // 返回实例
    }
    
    1
    2
    3
    4
    5
  • 手动实现一个 instanceof?

    点击

    instanceof 其原理就是判断实例对象的 __proto__ 是不是强等于对象的prototype 属性,如果不是继续往原型链上找,直到 __proto__null 为止。

    function instanceOf(obj, object) {
      //obj 表示实例对象,object 表示对象
      var O = object.prototype;
      obj = obj.__proto__;
      while (true) {
        if (obj === null) return false;
        if (O === obj)
          // 这里重点:当 O 严格等于 obj 时,返回 true
          return true;
        obj = obj.__proto__;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  • == 的类型转化规则

    点击
    [] == false // true
    
    {} == false  // false
    
    1
    2
    3

    1,null 和 undefined,相等。

    2,数字和字符串,转化为数字再比较。

    3,如果有 true 或 false,转换为 1 或 0,再比较。

    4,如果有引用类型,优先调用 valueOf。

    5,其余都不相等。

  • DOMBOM 有什么区别 ?

    点击
    • DOM Document Object Model,文档对象模型

    DOM 是为了操作文档出现的 API,document 是其的一个对象

    DOM 和文档有关,这里的文档指的是网页,也就是 html 文档。DOM 和浏览器无关,他关注的是网页本身的内容。

    • BOM Browser Object Model,浏览器对象模型

    BOM 是为了操作浏览器出现的 API,window 是其的一个对象

    window 对象既为 javascript 访问浏览器提供 API,同时在 ECMAScript 中充当 Global 对象

  • doctype有什么用?

    点击

    doctype 是一种标准通用标记语言的文档类型声明,目的是告诉标准通用标记语言解析器要使用什么样的文档类型定义(DTD)来解析文档。

    声明是用来指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。 声明必须是 HTML 文档的第一行,位于 html 标签之前。

    浏览器本身分为两种模式,一种是标准模式,一种是怪异模式,浏览器通过 doctype 来区分这两种模式,doctype 在 html 中的作用就是触发浏览器的标准模式,如果 html 中省略了 doctype,浏览器就会进入到 Quirks 模式的怪异状态,在这种模式下,有些样式会和标准模式存在差异,而 html 标准和 dom 标准值规定了标准模式下的行为,没有对怪异模式做出规定,因此不同浏览器在怪异模式下的处理也是不同的,所以一定要在 html 开头使用 doctype。

  • 箭头函数和普通函数有什么区别?

    点击
    • 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象,用 call apply bind 也不能改变 this 指向
    • 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
    • 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
    • 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
    • 箭头函数没有原型对象 prototype