一半设计一半前端http://www.mrszhao.com/鹤望岚一半设计一半前端http://www.mrszhao.com/post/344.html<p>在框架里面都讲模块化、组件化,其实发展到今天,模块化是走了很长的一条路的,现在ES6终于标准化了,不过也可以看看以前的历史。</p><h2>1、模块化发展历史</h2><h3>1.1 模块化的目的</h3><p cid="n36" mdtype="paragraph">2009年以前,前端还属于手动操作html/css/js之间的关系,js代码还不够庞大到需要工程化的处理。</p><p cid="n38" mdtype="paragraph">随着js的不断发展,在项目中越来越重要,承担的功能越来越多,js代码的体量和复杂度上升,就需要进行规范的管理。</p><p cid="n40" mdtype="paragraph">因为有了运行大量 Javascript 脚本的复杂程序 ,所以&nbsp;将 JavaScript 程序拆分为可按需导入的单独模块的机制就非常重要,一个js文件代码多了之后,就需要拆分成多个模块的文件,这样就形成了模块化的概念。</p><p><img src="http://www.mrszhao.com/zb_users/upload/2023/09/202309061693972612121776.jpg" alt="1.jpg"/></p><p cid="n44" mdtype="paragraph">在今天看来, 模块化应该具有以下价值:</p><ul class="ul-list list-paddingleft-2" cid="n46" mdtype="list" data-mark="-" style="list-style-type: square;"><li><p cid="n48" mdtype="paragraph">可维护性</p></li><li><p cid="n51" mdtype="paragraph">减少全局污染</p></li><li><p cid="n54" mdtype="paragraph">可复用性</p></li><li><p cid="n57" mdtype="paragraph">版本管理</p></li><li><p cid="n60" mdtype="paragraph">方便管理依赖关系</p></li><li><p cid="n63" mdtype="paragraph">分治思想的实践</p></li></ul><p cid="n65" mdtype="paragraph">但是,随着js的复杂攀升,ECMAScript却没有提出一套规范化的模块化语法,所以,js的模块化走了一条十来年不断演化的道路。</p><h2>1.2 前端模块化的雏形</h2><h3>1.2.1 第一阶段 文件划分</h3><p cid="n69" mdtype="paragraph">具体做法就是将每个功能及其相关状态数据各自单独放到不同的文件中, &nbsp;约定每个文件就是一个独立的模块, 使用某个模块就是将这个模块引入到页面中,然后直接调用模块中的成员(变量&nbsp;/&nbsp;函数)</p><pre class="prism-highlight prism-language-javascript">//module-1.js&nbsp;&nbsp; var&nbsp;module_name&nbsp;=&nbsp;&#39;module1&#39;; function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); } function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); } $(&#39;html&#39;).on(&#39;click&#39;,&nbsp;function()&nbsp;{ &nbsp;&nbsp;console.log(module_name+&#39;被执行了&#39;) })</pre><pre class="prism-highlight prism-language-javascript">//module-2.js&nbsp;&nbsp; var&nbsp;module_name&nbsp;=&nbsp;&#39;module2&#39;; function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); } function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); }</pre><pre class="prism-highlight prism-language-markup">&lt;!--index.html&nbsp;--&gt; &lt;script&nbsp;src=&quot;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-1.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-2.js&quot;&gt;&lt;/script&gt; &lt;script&gt; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;调用函数的时候,两个模块有相同的函数名,导致后面的模块覆盖了前面的 &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;命名冲突 &nbsp;&nbsp;&nbsp;&nbsp;fn1(); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;模块内部的成员可以在外面被修改 &nbsp;&nbsp;&nbsp;&nbsp;module_name&nbsp;=&nbsp;&#39;我的模块名&#39;; &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name) &lt;/script&gt;</pre><p cid="n74" mdtype="paragraph">这种缺点非常明显:</p><ul class="ul-list list-paddingleft-2" cid="n76" mdtype="list" data-mark="-" style="list-style-type: square;"><li><p cid="n78" mdtype="paragraph">模块变量相当于在全局声明,没有私有空间,所有成员都可以在模块外部被访问或者修改</p></li><li><p cid="n81" mdtype="paragraph">模块多了之后,会有命名冲突的问题。</p></li><li><p cid="n84" mdtype="paragraph">变量都在全局定义,导致难以调试,我们很难知道某个变量到底属于哪些模块。</p></li><li><p cid="n87" mdtype="paragraph">无法清晰地管理模块之间的依赖关系和加载顺序。假如 a.js 依赖 b.js,那么 HTML 中的 script 执行顺序需要手动调整,不然可能会产生运行时错误。</p></li></ul><h3>1.2.2 第二阶段 命名空间</h3><p cid="n90" mdtype="paragraph">在第一阶段的基础上,通过将每个模块「包裹」为一个全局对象的形式实现,有点类似于为模块内的成员添加了「命名空间」的感觉。</p><pre class="prism-highlight prism-language-javascript">//&nbsp;module-1.js var&nbsp;module1&nbsp;=&nbsp;{ &nbsp;&nbsp;module_name:&nbsp;&#39;module1&#39;, &nbsp;&nbsp;fn1:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;}, &nbsp;&nbsp;fn2:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} } $(&#39;html&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;console.log(module2.module_name&nbsp;+&nbsp;&#39;被执行了&#39;) })</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;module-2.js var&nbsp;module2&nbsp;=&nbsp;{ &nbsp;&nbsp;module_name:&nbsp;&#39;module2&#39;, &nbsp;&nbsp;fn1:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;}, &nbsp;&nbsp;fn2:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} } //&nbsp;无法管理模块之间的依赖关系。 module1.fn2();</pre><pre class="prism-highlight prism-language-markup">&lt;script&nbsp;src=&quot;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-1.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-2.js&quot;&gt;&lt;/script&gt; &lt;script&gt; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;通过「命名空间」减小了命名冲突的可能 &nbsp;&nbsp;&nbsp;&nbsp;module1.fn1(); &nbsp;&nbsp;&nbsp;&nbsp;module2.fn1(); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;但是同样没有私有空间,所有模块成员也可以在模块外部被访问或者修改, &nbsp;&nbsp;&nbsp;&nbsp;module1.module_name&nbsp;=&nbsp;&#39;改了之后的模块名&#39;; &nbsp;&nbsp;&nbsp;&nbsp;console.log(module1.module_name); &lt;/script&gt;</pre><p>虽然每个变量都有自己专属的命名空间,我们可以清楚地知道某个变量到底属于哪个<code>模块</code>,同时也避免全局变量命名的问题。 但是依然没有私有空间,外部可以修改模块内部变量,也无法管理模块之间的依赖关系。</p><h3>1.2.3 IIFE立即执行的函数表达式</h3><p cid="n98" mdtype="paragraph">使用立即执行函数表达式(IIFE:Immediately-Invoked&nbsp;Function&nbsp;Expression)为模块提供私有空间 。</p><p cid="n100" mdtype="paragraph">具体做法就是将每个模块成员都放在一个函数提供的私有作用域中,对于需要暴露给外部的成员,通过挂在到全局对象上的方式实现。</p><pre class="prism-highlight prism-language-javascript">//module-1.js ;&nbsp;(function&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;module_name&nbsp;=&nbsp;&#39;module1&#39;; &nbsp;&nbsp;function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;//&nbsp;不能直接访问模块内部的私有成员 &nbsp;&nbsp;$(&#39;html&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module1.module_name&nbsp;+&nbsp;&#39;被执行了&#39;) &nbsp;&nbsp;}) &nbsp;&nbsp;window.module1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;fn1:&nbsp;fn1, &nbsp;&nbsp;&nbsp;&nbsp;fn2:&nbsp;fn2 &nbsp;&nbsp;} })();</pre><pre class="prism-highlight prism-language-javascript">//module-2.js ;&nbsp;(function&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;module_name&nbsp;=&nbsp;&#39;module2&#39;; &nbsp;&nbsp;function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;&nbsp;&nbsp;module1.fn1(); &nbsp;&nbsp;} &nbsp;&nbsp;function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} &nbsp;&nbsp; &nbsp;&nbsp;window.module2&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;fn1:&nbsp;fn1, &nbsp;&nbsp;&nbsp;&nbsp;fn2:&nbsp;fn2 &nbsp;&nbsp;} })();</pre><pre class="prism-highlight prism-language-markup">&lt;script&nbsp;src=&quot;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-1.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-2.js&quot;&gt;&lt;/script&gt; &lt;script&gt; &nbsp;&nbsp;&nbsp;&nbsp;module1.fn1(); &nbsp;&nbsp;&nbsp;&nbsp;module2.fn1(); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;外部不能直接访问模块内部的私有成员 &nbsp;&nbsp;&nbsp;&nbsp;console.log(module1.module_name);&nbsp;//&nbsp;undefined &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;为模块添加了一个新的属性,虽然名字和模块内部的变量名同名,但是它们在不同的作用域,互相不受影响。 &nbsp;&nbsp;&nbsp;&nbsp;module1.module_name&nbsp;=&nbsp;&#39;改了模块名字&#39;; &nbsp;&nbsp;&nbsp;&nbsp;console.log(module1.module_name);&nbsp;//改了模块名字 &nbsp;&nbsp;&nbsp;&nbsp;module1.fn1();&nbsp;//&nbsp;module1fn1 &nbsp;&nbsp;&nbsp;&nbsp;console.log(module1);//{module_name:&nbsp;&#39;改了模块名字&#39;,&nbsp;fn1:&nbsp;ƒ,&nbsp;fn2:&nbsp;ƒ} &lt;/script&gt;</pre><p cid="n105" mdtype="paragraph">每个<code>IIFE</code>即<code>立即执行函数</code>都会创建一个私有的作用域,在私有作用域中的变量外界是无法访问的,只有模块内部的方法才能访问。相比于命名空间的模块化手段,<code>IIFE</code>实现的模块化安全性要更高,对于模块作用域的区分更加彻底。</p><p cid="n107" mdtype="paragraph">对于模块内部的module_name变量,我们只能在模块内部的fn函数中通过闭包访问,而在其它模块中无法直接访问。这就是模块私有化功能,避免模块私有成员被其他模块非法篡改,相比于命名空间的实现方式更加安全。</p><h3>1.2.4 利用传参解决依赖问题</h3><p cid="n110" mdtype="paragraph">只用IIFE虽然解决了私有化的问题,但是没有解决模块之间的依赖关系。</p><p cid="n112" mdtype="paragraph">后来通过利用立即执行函数的参数传递模块依赖项。 这使得每一个模块之间的关系变得更加明显。</p><pre class="prism-highlight prism-language-javascript">//module-1.js ;&nbsp;(function&nbsp;($)&nbsp;{ &nbsp;&nbsp;var&nbsp;module_name&nbsp;=&nbsp;&#39;module1&#39;; &nbsp;&nbsp;function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;&nbsp;&nbsp;$(&#39;body&#39;).css(&#39;backgroundColor&#39;,&nbsp;&#39;#ddd&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;window.module1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;fn1:&nbsp;fn1, &nbsp;&nbsp;&nbsp;&nbsp;fn2:&nbsp;fn2 &nbsp;&nbsp;} })(jQuery);</pre><pre class="prism-highlight prism-language-javascript">//module-2.js ;&nbsp;(function&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;module_name&nbsp;=&nbsp;&#39;module2&#39;; &nbsp;&nbsp;function&nbsp;fn1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn1&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;function&nbsp;fn2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(module_name&nbsp;+&nbsp;&#39;fn2&#39;); &nbsp;&nbsp;} &nbsp;&nbsp;module1.fn2(); &nbsp;&nbsp; &nbsp;&nbsp;window.module2&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;fn1:&nbsp;fn1, &nbsp;&nbsp;&nbsp;&nbsp;fn2:&nbsp;fn2 &nbsp;&nbsp;} })();</pre><pre class="prism-highlight prism-language-markup">&lt;script&nbsp;src=&quot;http://unpkg.com/jquery&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-1.js&quot;&gt;&lt;/script&gt; &lt;script&nbsp;src=&quot;js/module-2.js&quot;&gt;&lt;/script&gt; &lt;script&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;module1.fn1(); &nbsp;&nbsp;&nbsp;&nbsp;module2.fn1(); &lt;/script&gt;</pre><h2>2、模块化的规范</h2><p cid="n120" mdtype="paragraph">十年之前,模块化还主要使用闭包简单的实现一个命名空间。使用这种解决方式可以简单粗暴的处理全局变量和依赖关系等问题。</p><p cid="n122" mdtype="paragraph">转眼间模块化已经发展了有十余年了,不同的工具和轮子层出不穷,下面是最各大工具或框架的诞生时间:</p><table><tbody><tr class="firstRow"><td width="698" valign="top" style="word-break: break-all;">生态</td><td width="698" valign="top" style="word-break: break-all;">诞生时间</td></tr><tr><td width="698" valign="top" style="word-break: break-all;"><strong>CommonJS</strong></td><td width="698" valign="top" style="word-break: break-all;">2009年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;">Node.js</td><td width="698" valign="top" style="word-break: break-all;">2009年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;"><strong>NPM</strong></td><td width="698" valign="top" style="word-break: break-all;">2010年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;">requireJS(AMD)</td><td width="698" valign="top" style="word-break: break-all;">2010年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;">seaJS(CMD)</td><td width="698" valign="top" style="word-break: break-all;">2011年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;">broswerify</td><td width="698" valign="top" style="word-break: break-all;">2011年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;"><strong>webpack</strong></td><td width="698" valign="top" style="word-break: break-all;">2012年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;">grunt &nbsp;</td><td width="698" valign="top" style="word-break: break-all;">2012年</td></tr><tr><td width="698" valign="top" style="word-break: break-all;"><strong>gulp</strong></td><td width="698" valign="top" style="word-break: break-all;">2013年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">react</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2013年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;"><strong>vue</strong></td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2014年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;"><strong>ES6(Module)</strong></td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2015年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">angular</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2016年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">redux</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2015年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;"><strong>vite</strong></td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2020年</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">snowpack</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">2020年</td></tr></tbody></table><p cid="n142" mdtype="paragraph">随着前端工程的日益庞大,前端的模块化规范统一也经历了漫长的发展阶段,现在业界主流的三大模块规范是:<code>CommonJS</code>、<code>AMD</code>和<code>ES Modules</code>。对于模块规范而言,一般会包含两方面内容:</p><ul class="ul-list list-paddingleft-2" cid="n144" mdtype="list" data-mark="-" style="list-style-type: square;"><li><p cid="n146" mdtype="paragraph">统一的模块化代码规范</p></li><li><p cid="n149" mdtype="paragraph">实现自动加载模块的加载器(也称<code>loader</code>)</p></li></ul><h3>2.1 CommonJS规范</h3><p cid="n152" mdtype="paragraph">CommonJS 是业界最早正式提出的 JavaScript 模块规范,主要用于服务端 Node.js 。</p><pre class="prism-highlight prism-language-javascript">//module-a.js var&nbsp;data&nbsp;=&nbsp;&quot;hello&nbsp;world&quot;; function&nbsp;getData()&nbsp;{ &nbsp;&nbsp;return&nbsp;data; } module.exports&nbsp;=&nbsp;{ &nbsp;&nbsp;getData, };</pre><pre class="prism-highlight prism-language-javascript">//index.js const&nbsp;{&nbsp;getData&nbsp;}&nbsp;=&nbsp;require(&quot;./module-a.js&quot;); console.log(getData());</pre><p cid="n156" mdtype="paragraph">CommonJS 中使用<code>require</code>来导入一个模块,用<code>module.exports</code>来导出一个模块。CommonJS 定义了一套完整的模块化代码规范,不过仍然存在一些问题:</p><ul class="ul-list list-paddingleft-2" cid="n158" mdtype="list" data-mark="-" style="list-style-type: square;"><li><p cid="n160" mdtype="paragraph">它的模块加载器由 Node.js 提供,依赖了 Node.js 本身的功能实现。如果 CommonJS 模块直接放到浏览器中无法执行。</p></li><li><p cid="n163" mdtype="paragraph">CommonJS 约定以同步的方式进行模块加载,这种加载机制放到浏览器端,会带来明显的性能问题。它会产生大量同步的模块请求,浏览器要等待响应返回后才能继续解析模块。即,模块请求会造成浏览器 JS 解析过程的阻塞,导致页面加载速度缓慢。</p></li></ul><p cid="n165" mdtype="paragraph">CommonJS 的这种加载机制放在服务端是没问题的,一来模块都在本地,不需要进行网络 IO,二来只有服务启动时才会加载模块,而服务通常启动后会一直运行,所以对服务的性能并没有太大的影响。</p><p cid="n167" mdtype="paragraph">但是在浏览器端却会造成阻塞,白屏时间过长,用户体验不够友好。</p><p cid="n169" mdtype="paragraph">总之,CommonJS 是一个不太适合在浏览器中运行的模块规范。因此,业界也设计出了全新的规范来作为浏览器端的模块标准,最知名的要数<code>AMD</code>和<code>CMD</code>了。</p><h3>2.2 AMD规范和CMD规范</h3><h4>2.2.1 RequireJS和SeaJS</h4><p cid="n173" mdtype="paragraph"><code>AMD</code>全称为<code>Asynchronous Module Definition</code>,即异步模块定义规范。模块根据这个规范,在浏览器环境中会被异步加载,而不会像 CommonJS 规范进行同步加载,也就不会产生同步请求导致的浏览器解析过程阻塞的问题了。</p><p cid="n175" mdtype="paragraph">RequireJS 遵循的是 AMD(异步模块定义)规范。</p><p cid="n177" mdtype="paragraph">SeaJS 遵循的是 CMD (通用模块定义)规范(阿里的玉伯主导的)</p><p cid="n179" mdtype="paragraph">随着 2015 年 6 月,ECMAScript 对 ES6 Modules 的正式发布,浏览器厂商和 Node.js 随之纷纷跟进实现,市面上的模块化加载库随之暗淡失色,间接给 CommonJS 社区判了死刑。在浏览器端取而代之流行的做法的是大家都使用 ES6 Modules 写法,然后使用 Babel 等的 transpiler 来应对不同浏览器版本的支持程度和在浏览器端异步特性产生的一些待解决的问题。Node.js 的模块还是大量的采用 CommonJS 模式,随着对 ES6 Modules 的支持力度的提高和可以兼容之前 CommonJS 模块,CommonJS 写法过渡到 ES6 Modules 只是时间的问题。</p><h3>3、 ES6 Module</h3><p cid="n182" mdtype="paragraph"><code>ES Module</code>(或<code>ESM</code>), 是由 ECMAScript 官方提出的模块化规范,它已经得到了现代浏览器的内置支持。</p><p cid="n184" mdtype="paragraph">不仅在浏览器端,一直以 CommonJS 作为模块标准的 Node.js 也从<code>12.20</code>版本开始正式支持原生 ES Module。</p><h3>3.1 ESM特性</h3><h4>3.1.1 在HTML中声明脚本模块</h4><pre class="prism-highlight prism-language-markup">&lt;!--&nbsp;引入外部模块&nbsp;--&gt; &lt;script&nbsp;type=&quot;module&quot;&nbsp;src=&quot;main.js&quot;&gt;&lt;/script&gt; &lt;!--&nbsp;把模块导入内部脚本--&gt; &lt;script&nbsp;type=&quot;module&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;this&nbsp;is&nbsp;es&nbsp;module&#39;); &lt;/script&gt;</pre><h4>3.1.2 默认是严格模式</h4><pre class="prism-highlight prism-language-markup">&lt;!--&nbsp;ESM&nbsp;默认采用严格模式&nbsp;use&nbsp;strict&nbsp;--&gt; &lt;script&nbsp;type=&quot;module&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;console.log(this);&nbsp;//undefined &lt;/script&gt;</pre><h4>3.1.3 每个模块都是运行在单独的私有作用域中</h4><h4>3.1.4 通过CORS访问外部资源</h4><pre class="prism-highlight prism-language-markup">&lt;!--&nbsp;通过CORS&nbsp;跨域资源共享方式访问外部的模块,&nbsp;有的外部地址不支持CORS,会报错&nbsp;--&gt; &lt;script&nbsp;type=&quot;module&quot;&nbsp;src=&quot;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt; &lt;!--&nbsp;支持CORS跨域访问资源&nbsp;--&gt; &lt;script&nbsp;type=&quot;module&quot;&nbsp;src=&quot;unpkg.com/jquery&quot;&gt;&lt;/script&gt;</pre><blockquote><p>CORS 全称为 Cross-Origin Resource Sharing,被译为跨域资源共享,简称跨域访问,是 W3C 制定的标准协议。它由一系列传输的 HTTP 标头(首部字段)组成,浏览器会根据这些 HTTP 标头决定着是否阻止前端 JS 代码获取跨域请求的资源。CORS 主要作用是消除各种 API 的同源限制,以便在不同源(服务器)之间共享资源,且确保跨域数据传输的安全性。</p></blockquote><h4>3.1.5 模块会自动延迟加载</h4><pre class="prism-highlight prism-language-markup">&lt;!--&nbsp;ESM&nbsp;的script标签会延迟执行脚本,不影响页面的渲染&nbsp;--&gt; &lt;script&nbsp;type=&quot;module&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;alert(&#39;Hello&#39;); &lt;/script&gt; &lt;p&gt;页面内容&lt;/p&gt;</pre><h3>3.2 导入和导出</h3><p cid="n201" mdtype="paragraph">模块都在单独的私有作用域中,所以外部不能直接访问,必须通过导出到外部才能访问。</p><p cid="n203" mdtype="paragraph">为了获得模块的功能要做的第一件事是把它们导出来。使用&nbsp;<code>export</code>&nbsp;语句来完成。</p><p cid="n205" mdtype="paragraph">导出有三种方式。</p><h4>3.2.1 变量函数声明导出</h4><pre class="prism-highlight prism-language-javascript">//module.js //&nbsp;导出变量username export&nbsp;var&nbsp;username&nbsp;=&nbsp;&#39;诸葛&#39; //&nbsp;导出函数sayName export&nbsp;function&nbsp;sayName()&nbsp;{ &nbsp;&nbsp;console.log(username); } //&nbsp;导出类Person export&nbsp;class&nbsp;Person&nbsp;{ &nbsp;&nbsp;constructor(username)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;this.username&nbsp;=&nbsp;username; &nbsp;&nbsp;} }</pre><pre class="prism-highlight prism-language-javascript">//app.js //导入,这里的.js不能省略。import&nbsp;{}&nbsp;是一种语法,不是解构赋值 import&nbsp;{&nbsp;username,&nbsp;sayName,&nbsp;Person&nbsp;}&nbsp;from&nbsp;&quot;../modules/module.js&quot;; console.log(username); sayName() console.log(new&nbsp;Person(&#39;孔明&#39;))</pre><pre class="prism-highlight prism-language-markup">&lt;!--index.html--&gt; &lt;script&nbsp;type=&quot;module&quot;&nbsp;src=&quot;js/app.js&quot;&gt;&lt;/script&gt;</pre><h4>3.2.2 命名导出</h4><pre class="prism-highlight prism-language-javascript">//module.js //&nbsp;命名导出方式 var&nbsp;username&nbsp;=&nbsp;&#39;诸葛&#39;; function&nbsp;sayName()&nbsp;{ &nbsp;&nbsp;console.log(username); } class&nbsp;Person&nbsp;{ &nbsp;&nbsp;constructor(username)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;this.username&nbsp;=&nbsp;username; &nbsp;&nbsp;} } //&nbsp;集中命名导出 export&nbsp;{username,&nbsp;sayName,&nbsp;Person}; //&nbsp;通过as重命名,导入的时候,用重命名的名字导入 export&nbsp;{username,&nbsp;sayName&nbsp;as&nbsp;sayUserName,&nbsp;Person};</pre><h4>3.2.3 默认导出</h4><pre class="prism-highlight prism-language-javascript">//module.js //默认导出&nbsp;export&nbsp;default&nbsp;,后面没有{}大括号 export&nbsp;default&nbsp;sayName; //&nbsp;或者默认导出一个匿名函数 export&nbsp;default&nbsp;function(){ &nbsp;&nbsp;console.log(username); }</pre><pre class="prism-highlight prism-language-javascript">//app.js //导入默认的导出时,直接写上导出的名字,不需要大括号。因为每个模块只允许有一个默认导出 import&nbsp;sayName&nbsp;from&nbsp;&quot;../modules/module.js&quot;; //是这种的缩写形式 //import&nbsp;{default&nbsp;as&nbsp;sayName}&nbsp;from&nbsp;&#39;../modules/module.js&#39;</pre><p>导入有四种方式。</p><h4>3.2.4 按需导入</h4><p cid="n219" mdtype="paragraph">导入的变量名字必须和导出的变量名一致。后面的路径是相对根目录的相对路径,必须以 . 或者 / 或者http路径开头,不能直接用字母开头。</p><pre class="prism-highlight prism-language-javascript">import&nbsp;{&nbsp;sayName&nbsp;}&nbsp;from&nbsp;&quot;../modules/module.js&quot;;</pre><h4>3.2.5 命名空间导入</h4><p>如果需要导入的模块很多,有可能需要重命名导出的变量, 导致有点冗余。</p><pre class="prism-highlight prism-language-javascript">import&nbsp;{&nbsp;sayName&nbsp;as&nbsp;sayName1&nbsp;}&nbsp;from&nbsp;&quot;../modules/module.js&quot;; import&nbsp;{&nbsp;sayName&nbsp;as&nbsp;sayName2}&nbsp;from&nbsp;&quot;../modules/module1.js&quot;;</pre><p>一个更好的解决方是,导入每一个模块功能到一个模块功能对象上。可以使用以下语法形式:</p><pre class="prism-highlight prism-language-javascript">import&nbsp;*&nbsp;as&nbsp;Module&nbsp;from&nbsp;&#39;/modules/module.js&#39;;</pre><p>这将获取&nbsp;<code>module.js</code>&nbsp;中所有可用的导出,并使它们可以作为对象模块的成员使用,从而有效地为其提供自己的命名空间。</p><pre class="prism-highlight prism-language-javascript">import&nbsp;*&nbsp;as&nbsp;Module1&nbsp;from&nbsp;&#39;../modules/module.js&#39;; import&nbsp;*&nbsp;as&nbsp;Module2&nbsp;from&nbsp;&#39;../modules/module1.js&#39;; console.log(Module1.username); Module1.sayName(); console.log(new&nbsp;Module1.Person(&#39;孔明&#39;)) console.log(Module2.username) Module2.sayName();</pre><h4>3.2.6 默认导入</h4><pre class="prism-highlight prism-language-javascript">import&nbsp;_&nbsp;from&nbsp;&#39;module.js&#39;</pre><p>导入export default后面的值,可以取任意名字,因为一个模块只有一个export default,可以省略大括号。</p><h4>3.2.7 默认和按需同时导入</h4><pre class="prism-highlight prism-language-javascript">//module.js export&nbsp;{&nbsp;username,&nbsp;count&nbsp;} export&nbsp;default&nbsp;sayName</pre><pre class="prism-highlight prism-language-javascript">//app.js //两种方式导入 //&nbsp;import&nbsp;{username,&nbsp;count,&nbsp;default&nbsp;as&nbsp;sayName}&nbsp;from&nbsp;&#39;../module/module.js&#39; import&nbsp;sayName,&nbsp;{username,&nbsp;count}&nbsp;from&nbsp;&#39;../module/module.js&#39;</pre><h4>3.2.8 只运行不导入</h4><pre class="prism-highlight prism-language-javascript">import&nbsp;&#39;module.js&#39;</pre><p>只运行模块而不引入模块中的任何方法或变量。</p><h4>3.2.9 动态导入</h4><p cid="n244" mdtype="paragraph">import &nbsp;只能放在最外层作用域中,不能嵌套在if这种块作用域中。</p><p cid="n246" mdtype="paragraph">from 后面的路径也不能是变量。</p><p cid="n248" mdtype="paragraph">所以,当不知道模块加载的路径,或者在刚开始还不需要加载模块的时候,可以使用动态加载。</p><p cid="n250" mdtype="paragraph">这时用import()函数来实现动态加载。</p><pre class="prism-highlight prism-language-javascript">import(&#39;../module/module.js&#39;).then(function(module)&nbsp;{ &nbsp;&nbsp;console.log(module) })</pre><p>这是异步加载,当加载完模块后,才执行后面的回调函数,module形参获得模块返回的导出对象。</p><h4>3.2.10 注意事项</h4><p cid="n256" mdtype="paragraph">export {} 和 import {}都是一种语法,不是对象字面量,也不是解构赋值</p><p cid="n258" mdtype="paragraph">只有export default 后面可以跟一个值,可以是变量,函数,对象,字符串等值。export default {}这才是默认导出一个对象。</p><p cid="n260" mdtype="paragraph">导入和导出之间的成员的值是一种引用关系,不是赋值关系。导出的成员是只读的。</p><pre class="prism-highlight prism-language-javascript">//module.js var&nbsp;count&nbsp;=&nbsp;0; var&nbsp;username&nbsp;=&nbsp;&#39;Tom&#39;; setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;username&nbsp;=&nbsp;&#39;Jenn&#39;; },&nbsp;1000) setInterval(function&nbsp;()&nbsp;{ &nbsp;&nbsp;count++; },&nbsp;1000) export&nbsp;{&nbsp;username,&nbsp;count&nbsp;}</pre><pre class="prism-highlight prism-language-javascript">//app.js import&nbsp;{username,&nbsp;count}&nbsp;from&nbsp;&#39;../module/module.js&#39; console.log(count,&nbsp;username); setInterval(function()&nbsp;{ &nbsp;&nbsp;console.log(count,&nbsp;username); },&nbsp;1500)</pre><p>关于原生js的教案差不多就整理完了,算是一个总结吧,自动化构建和框架的教案就不放出来了。如果我以后转行不干了,再说!<br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/344.html" rel="nofollow" target="_blank">继续阅读《前端开发的模块化发展和ES6模块化标准》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-327.html">ES6 rel="nofollow" Module</a>,<a href="http://www.mrszhao.com/tags-328.html">模块化</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/344.html#comment" rel="nofollow" target="_blank">添加评论</a>(2)</p><hr /> <h3>最新评论:</h3><ul><li><a href="http://www.mrszhao.com/post/344.html#comment-235">2023-09-07 rel="nofollow" 21:44:52 PM</a>,赵老师 : 把以前的畅言留言系统关闭了,免得有广告,看看这个留言能用吗?</li><li><a href="http://www.mrszhao.com/post/344.html#comment-236">2023-09-07 rel="nofollow" 21:51:31 PM</a>,赵老师 : 可以留言了,罢工了很久的留言系统还是启动起来吧。</li></ul><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/231.html">JavaScript基础3:运算符和表达式</a> (2019-07-08) </li><li><a href="http://www.mrszhao.com/post/300.html">正则这个火星文!!!</a> rel="nofollow" rel="nofollow" (2021-11-05) </li><li><a href="http://www.mrszhao.com/post/250.html">JavaScript基础13:Object对象初了解</a> (2019-08-14) </li><li><a href="http://www.mrszhao.com/post/234.html">JavaScript基础4:Strings 及String Methods</a> (2019-07-11) </li><li><a href="http://www.mrszhao.com/post/228.html">JavaScript基础1:JavaScript的前世今生</a> (2019-03-27) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Sun, 30 Jul 2023 11:47:57 +0800一半设计一半前端http://www.mrszhao.com/post/345.html<p>前面用ES6写了一个 todos,这里放一个Vue版本写的,可以通过代码对比,看看Vue和原生js的区别。</p><p><a href="http://www.mrszhao.com/post/343.html" rel="nofollow" rel="nofollow" target="_blank" title="ES6版本的todos本地任务清单!">用ES6写了一个todos,本地任务清单!</a></p><p><a href="http://www.mrszhao.com/zb_users/upload/2023/07/todosVue/index.html" rel="nofollow" target="_blank" title="Vue版本的todos"><img src="http://www.mrszhao.com/zb_users/upload/2023/09/202309061693975768504890.jpg" title="5.jpg" alt="5.jpg"/></a></p><p>点击图片看效果。</p><p>核心代码:</p><pre class="prism-highlight prism-language-javascript">const&nbsp;filters&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;all(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;todos; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;active(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;todos.filter(item&nbsp;=&gt;&nbsp;!item.completed); &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;completed(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;todos.filter(item&nbsp;=&gt;&nbsp;item.completed); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;const&nbsp;TODO_KEY&nbsp;=&nbsp;&#39;todo-keys&#39; &nbsp;&nbsp;const&nbsp;storage&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;JSON.parse(localStorage.getItem(TODO_KEY))&nbsp;||&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localStorage.setItem(TODO_KEY,&nbsp;JSON.stringify(todos)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;const&nbsp;vm&nbsp;=&nbsp;new&nbsp;Vue({ &nbsp;&nbsp;&nbsp;&nbsp;el:&nbsp;&#39;#app&#39;, &nbsp;&nbsp;&nbsp;&nbsp;data:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;todos:[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;{id:1,&nbsp;title:&nbsp;&#39;上课&#39;,&nbsp;completed:&nbsp;true}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;{id:2,&nbsp;title:&nbsp;&#39;吃饭&#39;,&nbsp;completed:&nbsp;false}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;{id:3,&nbsp;title:&nbsp;&#39;睡觉&#39;,&nbsp;completed:&nbsp;false}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;{id:4,&nbsp;title:&nbsp;&#39;梦游&#39;,&nbsp;completed:&nbsp;false}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todos:&nbsp;storage.get(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newTodo:&nbsp;&#39;&#39;, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;editingTodo:&nbsp;null, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todoBeforeTitle:&nbsp;&#39;&#39;, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todoType:&nbsp;&#39;all&#39; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;methods:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pluralize(unit)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;unit&nbsp;+&nbsp;(this.remaining&nbsp;===&nbsp;1&nbsp;?&nbsp;&#39;&#39;&nbsp;:&nbsp;&#39;s&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addTodo(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;val&nbsp;=&nbsp;this.newTodo.trim(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!val)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;this.todos.push({id:this.todos.length&nbsp;&gt;&nbsp;0&nbsp;?&nbsp;this.todos[this.todos.length&nbsp;-1].id&nbsp;+&nbsp;1&nbsp;:&nbsp;0&nbsp;,&nbsp;title:&nbsp;val,&nbsp;completed:&nbsp;false}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todos.push({id:&nbsp;Date.now(),&nbsp;title:&nbsp;val,&nbsp;completed:&nbsp;false}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.newTodo&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removeTodo(todo)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;index&nbsp;=&nbsp;this.todos.indexOf(todo); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todos.splice(index,1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;editTodo(todo)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.editingTodo&nbsp;=&nbsp;todo; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todoBeforeTitle&nbsp;=&nbsp;todo.title; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;editDone(todo)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(todo&nbsp;!==&nbsp;this.editingTodo)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;val&nbsp;=&nbsp;todo.title.trim(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.removeTodo(todo); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.title&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.editingTodo&nbsp;=&nbsp;null; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todoBeforeTitle&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancelEdit(todo)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.title&nbsp;=&nbsp;this.todoBeforeTitle; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.editingTodo&nbsp;=&nbsp;null; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todoBeforeTitle&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removeAllCompleted()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;this.todos&nbsp;=&nbsp;this.todos.filter(item&nbsp;=&gt;&nbsp;!item.completed) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todos&nbsp;=&nbsp;filters.active(this.todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;computed:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remaining()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;return&nbsp;this.todos.filter(item&nbsp;=&gt;&nbsp;!item.completed).length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;filters.active(this.todos).length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allDone:{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.remaining&nbsp;===&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set(value)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.todos.forEach(item&nbsp;=&gt;&nbsp;item.completed&nbsp;=&nbsp;value); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filtersTodo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;filters[this.todoType](this.todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;directives:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;todo-focus&#39;(el)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;el.focus(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;watch:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todos:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deep:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handler:&nbsp;storage.set &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;})</pre><p>差不多了,原生js的万博manbext3.0首页登录也整理完了,框架的万博manbext3.0首页登录就不上了,如果有一天我转行了,可以把所有完整的项目都分享出来,再给自己三个月的时间吧。<br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/345.html" rel="nofollow" rel="nofollow" target="_blank">继续阅读《Vue版本的todos本地任务清单!》的全文内容...</a></p><p>分类: JavaScript万博manbext3.0首页登录集 | Tags: <a href="http://www.mrszhao.com/tags-329.html">Vue</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-325.html">todos</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-326.html">本地任务清单</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-256.html">js万博manbext3.0首页登录</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/345.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/345.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/201.html">JavaScript万博manbext3.0首页登录2:幻灯片切换效果(顺序切换和循环切换)</a> (2018-08-24) </li><li><a href="http://www.mrszhao.com/post/265.html">js小万博manbext3.0首页登录:商品分类筛选</a> rel="nofollow" (2019-08-30) </li><li><a href="http://www.mrszhao.com/post/246.html">js小万博manbext3.0首页登录:通过改变translateY的值实现点击按钮翻页效果</a> rel="nofollow" (2019-08-09) </li><li><a href="http://www.mrszhao.com/post/183.html">利用transform变形结合事件完成扇形导航</a> rel="nofollow" (2018-05-25) </li><li><a href="http://www.mrszhao.com/post/332.html">jQuery+Ajax实现表单的关联下拉菜单选择</a> rel="nofollow" (2021-12-18) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Fri, 28 Jul 2023 12:43:59 +0800一半设计一半前端http://www.mrszhao.com/post/343.html<p>学完了ES6,就可以拿一个小项目练练手,todoMVC是一个比较出名的用来练习各种编程语言的项目,可以直接去它官网看。</p><p>这里写一个ES6版本的。</p><p><a href="http://www.mrszhao.com/zb_users/upload/2023/07/todosES6/index.html" rel="nofollow" target="_blank" title="todosES6版本"><img src="http://www.mrszhao.com/zb_users/upload/2023/09/202309061693971516756203.jpg" title="4.jpg" alt="4.jpg"/></a></p><p>点击图片看效果,如果想看Vue2版本的,也可以<a href="http://www.mrszhao.com/post/345.html" rel="nofollow" rel="nofollow" target="_blank" title="Vue版本的todos本地任务清单">点这里</a>。</p><p>增删改查功能都有,自己看代码。</p><p>核心代码:</p><pre class="prism-highlight prism-language-javascript">//&nbsp;找对象 &nbsp;&nbsp;const&nbsp;newTodoInput&nbsp;=&nbsp;$(&#39;.new-todo&#39;); &nbsp;&nbsp;const&nbsp;oTodoList&nbsp;=&nbsp;$(&#39;.todo-list&#39;); &nbsp;&nbsp;const&nbsp;oMain&nbsp;=&nbsp;$(&#39;.main&#39;); &nbsp;&nbsp;const&nbsp;oFooter&nbsp;=&nbsp;$(&#39;.footer&#39;); &nbsp;&nbsp;const&nbsp;oTodoCount&nbsp;=&nbsp;$(&#39;.todo-count&#39;); &nbsp;&nbsp;const&nbsp;oClearCompleted&nbsp;=&nbsp;$(&#39;.clear-completed&#39;); &nbsp;&nbsp;const&nbsp;oToggleAll&nbsp;=&nbsp;$(&#39;.toggle-all&#39;); &nbsp;&nbsp;const&nbsp;oTodoType&nbsp;=&nbsp;$$(&#39;.filters&nbsp;a&#39;); &nbsp;&nbsp;//&nbsp;数据的本地存储 &nbsp;&nbsp;const&nbsp;TODOS_KEY&nbsp;=&nbsp;&#39;dotos_ES6&#39;; &nbsp;&nbsp;let&nbsp;todosStorage&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;JSON.parse(localStorage.getItem(TODOS_KEY))&nbsp;||&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localStorage.setItem(TODOS_KEY,JSON.stringify(todos)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;全局变量 &nbsp;&nbsp;//&nbsp;存储数据的todos &nbsp;&nbsp;//&nbsp;let&nbsp;todos&nbsp;=&nbsp;[ &nbsp;&nbsp;//&nbsp;&nbsp;{&nbsp;id:&nbsp;1,&nbsp;title:&nbsp;&#39;学习&#39;,&nbsp;completed:&nbsp;false&nbsp;}, &nbsp;&nbsp;//&nbsp;&nbsp;{&nbsp;id:&nbsp;2,&nbsp;title:&nbsp;&#39;做饭&#39;,&nbsp;completed:&nbsp;true&nbsp;}, &nbsp;&nbsp;//&nbsp;&nbsp;{&nbsp;id:&nbsp;3,&nbsp;title:&nbsp;&#39;接娃放学&#39;,&nbsp;completed:&nbsp;true&nbsp;}, &nbsp;&nbsp;//&nbsp;] &nbsp;&nbsp;let&nbsp;todos&nbsp;=&nbsp;todosStorage.get(); &nbsp;&nbsp;//&nbsp;用于区分单击和双击事件 &nbsp;&nbsp;let&nbsp;timer&nbsp;=&nbsp;null; &nbsp;&nbsp;//&nbsp;初始化渲染 &nbsp;&nbsp;render(todos); &nbsp;&nbsp;//&nbsp;当enter的时候添加事项 &nbsp;&nbsp;newTodoInput.addEventListener(&#39;keyup&#39;,&nbsp;(e)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(e.key&nbsp;===&nbsp;&#39;Enter&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;添加事项 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addTodo(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;重新渲染 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;}) &nbsp;&nbsp;//&nbsp;因为有很多事项,有很多删除按钮,所以用事件委托性能更高 &nbsp;&nbsp;//&nbsp;ul同时委托了单击事件和双击事件,通过300ms的延迟来判断是单击还是双击 &nbsp;&nbsp;//&nbsp;如果300ms以后没有单击,则是单击事件,执行对应的代码。 &nbsp;&nbsp;oTodoList.addEventListener(&#39;click&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;clearTimeout(timer); &nbsp;&nbsp;&nbsp;&nbsp;timer&nbsp;=&nbsp;setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;target&nbsp;=&nbsp;e.target; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(target); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;tempLi&nbsp;=&nbsp;target.closest(&#39;li&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;根据li的id属性找到todos里面该id的数据,数字和字符串的相等用== &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;todo&nbsp;=&nbsp;todos.find(item&nbsp;=&gt;&nbsp;item.id&nbsp;==&nbsp;tempLi.id); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果点击的是删除按钮,则删除该事项 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(target.className&nbsp;===&nbsp;&#39;destroy&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delTodo(todo); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果点击的是复选框按钮,则切换完成和未完成的状态 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(target.className&nbsp;===&nbsp;&#39;toggle&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.completed&nbsp;=&nbsp;target.checked; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;修复双击下出现输入框编辑的时候,单击输入框的文本,输入框又消失的问题 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(target.className&nbsp;===&nbsp;&#39;edit&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oEditing&nbsp;=&nbsp;tempLi.querySelector(&#39;.edit&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tempLi.classList.add(&#39;editing&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oEditing.focus(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;300); &nbsp;&nbsp;}) &nbsp;&nbsp;//&nbsp;编辑事项 &nbsp;&nbsp;oTodoList.addEventListener(&#39;dblclick&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果300ms以内又有点击事件,则是双击事件,清掉前面定时器要执行的代码,执行双击对应的代码。 &nbsp;&nbsp;&nbsp;&nbsp;clearTimeout(timer); &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;target&nbsp;=&nbsp;e.target; &nbsp;&nbsp;&nbsp;&nbsp;console.log(target); &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;tempLi&nbsp;=&nbsp;target.closest(&#39;li&#39;); &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;todo&nbsp;=&nbsp;todos.find(item&nbsp;=&gt;&nbsp;item.id&nbsp;==&nbsp;tempLi.id); &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(target.tagName&nbsp;===&nbsp;&#39;LABEL&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oEditing&nbsp;=&nbsp;tempLi.querySelector(&#39;.edit&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tempLi.classList.add(&#39;editing&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oEditing.focus(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;把输入框的光标放在最后面。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;element.setSelectionRange(selectionStart,&nbsp;selectionEnd&nbsp;[,&nbsp;selectionDirection]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果希望全选输入元素中的文本,你可以使用&nbsp;HTMLInputElement.select()&nbsp;方法。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oEditing.setSelectionRange(-1,&nbsp;-1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;存储输入框以前的数据 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;titleBeforeEdit&nbsp;=&nbsp;oEditing.value; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oEditing.addEventListener(&#39;keyup&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(e.key) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;val&nbsp;=&nbsp;this.value.trim(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;编辑完成 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(e.key&nbsp;===&nbsp;&#39;Enter&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(val&nbsp;===&nbsp;&#39;&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delTodo(todo); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.title&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;取消编辑 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(e.key&nbsp;===&nbsp;&#39;Escape&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.value&nbsp;=&nbsp;titleBeforeEdit; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;失去焦点的时候,编辑完成 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oEditing.addEventListener(&#39;blur&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;val&nbsp;=&nbsp;this.value.trim(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(val&nbsp;===&nbsp;&#39;&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delTodo(todo); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.title&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;}) &nbsp;&nbsp;//&nbsp;删除完成的事项 &nbsp;&nbsp;oClearCompleted.addEventListener(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;todos&nbsp;=&nbsp;todos.filter(todo&nbsp;=&gt;&nbsp;!todo.completed); &nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;}) &nbsp;&nbsp;//&nbsp;点击全选复选框,对所有事项的状态切换 &nbsp;&nbsp;oToggleAll.addEventListener(&#39;change&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;val&nbsp;=&nbsp;this.checked; &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(const&nbsp;todo&nbsp;of&nbsp;todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo.completed&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;todosStorage.set(todos); &nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;}) &nbsp;&nbsp;//&nbsp;根据hash切换a的状态 &nbsp;&nbsp;//&nbsp;不能点击a的时候获取hash,否则获取的是上一个hash值。 &nbsp;&nbsp;window.onhashchange&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(location.hash); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;a被选中的状态 &nbsp;&nbsp;&nbsp;&nbsp;selectedType(); &nbsp;&nbsp;&nbsp;&nbsp;render(todos); &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;找对象的函数 &nbsp;&nbsp;function&nbsp;$(selector)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;document.querySelector(selector); &nbsp;&nbsp;} &nbsp;&nbsp;function&nbsp;$$(selector)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;document.querySelectorAll(selector); &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;渲染事项 &nbsp;&nbsp;function&nbsp;render(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;对面板的切换 &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(todos.length)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oMain.style.display&nbsp;=&nbsp;&#39;block&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oFooter.style.display&nbsp;=&nbsp;&#39;block&#39;; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oMain.style.display&nbsp;=&nbsp;&#39;none&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oFooter.style.display&nbsp;=&nbsp;&#39;none&#39;; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!todos.length)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;renderTodos&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;筛选数据 &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(location.hash); &nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(location.hash)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;&#39;#/active&#39;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderTodos&nbsp;=&nbsp;todos.filter(todo&nbsp;=&gt;&nbsp;!todo.completed); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;&#39;#/completed&#39;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderTodos&nbsp;=&nbsp;todos.filter(todo&nbsp;=&gt;&nbsp;todo.completed); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderTodos&nbsp;=&nbsp;todos; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;a的被选中状态 &nbsp;&nbsp;&nbsp;&nbsp;selectedType(); &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;str&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(const&nbsp;obj&nbsp;of&nbsp;renderTodos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str&nbsp;+=&nbsp;`&lt;li&nbsp;id=&#39;${obj.id}&#39;&nbsp;class=${obj.completed&nbsp;?&nbsp;&#39;completed&#39;&nbsp;:&nbsp;&#39;&#39;}&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&nbsp;class=&quot;view&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class=&quot;toggle&quot;&nbsp;type=&quot;checkbox&quot;&nbsp;${obj.completed&nbsp;?&nbsp;&#39;checked&#39;&nbsp;:&nbsp;&#39;&#39;}&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;${obj.title}&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;button&nbsp;class=&quot;destroy&quot;&gt;&lt;/button&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class=&quot;edit&quot;&nbsp;value=&quot;${obj.title}&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/li&gt;` &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;oTodoList.innerHTML&nbsp;=&nbsp;str; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到未完成的事项的个数。 &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;remainingCount&nbsp;=&nbsp;getRemainingCount(todos); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;状态栏&nbsp;未完成数量的显示 &nbsp;&nbsp;&nbsp;&nbsp;oTodoCount.innerHTML&nbsp;=&nbsp;`&lt;strong&gt;${remainingCount}&lt;/strong&gt;&nbsp;${remainingCount&nbsp;===&nbsp;1&nbsp;?&nbsp;&#39;item&#39;&nbsp;:&nbsp;&#39;items&#39;}&nbsp;left` &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;删除完成事项的按钮 &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果事项的总个数大于未完成事项的个数,则按钮显示 &nbsp;&nbsp;&nbsp;&nbsp;oClearCompleted.style.display&nbsp;=&nbsp;todos.length&nbsp;&gt;&nbsp;remainingCount&nbsp;?&nbsp;&#39;block&#39;&nbsp;:&nbsp;&#39;none&#39;; &nbsp;&nbsp;&nbsp;&nbsp;//对全选复选框的状态设置 &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(remainingCount&nbsp;===&nbsp;0&nbsp;&amp;&amp;&nbsp;todos.length&nbsp;!==&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oToggleAll.checked&nbsp;=&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oToggleAll.checked&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;未完成的事项的个数 &nbsp;&nbsp;function&nbsp;getRemainingCount(todos)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;todos.filter(item&nbsp;=&gt;&nbsp;!item.completed).length; &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;添加事项 &nbsp;&nbsp;function&nbsp;addTodo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;value&nbsp;=&nbsp;newTodoInput.value.trim(); &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!value)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;todos.push({&nbsp;id:&nbsp;Date.now(),&nbsp;title:&nbsp;value,&nbsp;completed:&nbsp;false&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;newTodoInput.value&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;删除单个事项 &nbsp;&nbsp;function&nbsp;delTodo(todo)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;index&nbsp;=&nbsp;todos.indexOf(todo); &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(index&nbsp;!==&nbsp;-1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todos.splice(index,&nbsp;1); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;事项类别状态设置 &nbsp;&nbsp;function&nbsp;selectedType()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;oTodoType.forEach((item,&nbsp;index)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(item.hash&nbsp;===&nbsp;location.hash)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oTodoType.forEach(item&nbsp;=&gt;&nbsp;item.classList.remove(&#39;selected&#39;)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.classList.add(&#39;selected&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(item.hash); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;}</pre><p><br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/343.html" rel="nofollow" rel="nofollow" target="_blank">继续阅读《用ES6写了一个todos,本地任务清单!》的全文内容...</a></p><p>分类: JavaScript万博manbext3.0首页登录集 | Tags: <a href="http://www.mrszhao.com/tags-324.html">todoMVC</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-325.html">todos</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-326.html">本地任务清单</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-319.html">ES6</a>, rel="nofollow" rel="nofollow" | <a href="http://www.mrszhao.com/post/343.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/343.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/345.html" rel="nofollow" rel="nofollow">Vue版本的todos本地任务清单!</a> (2023-07-28) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Sat, 22 Jul 2023 11:29:48 +0800一半设计一半前端http://www.mrszhao.com/post/341.html<p>现在几乎都是使用ES6了,浏览器要兼容的时代随着移动端的统一归于平静,想起以前轰轰烈烈的浏览器大战,为了兼容性痛苦不堪的年代,这一切都过去了。况且随着脚手架等自动化构建工具的使用,直接写最新最酷的代码,再babel一下,放心大胆的用。<br/></p><p>所以,我也建议直接用最新版本的语法,不管是语法糖,还是效率,用起来都更舒心。</p><h2>1、Symbol</h2><p cid="n41" mdtype="paragraph">ES6为JavaScript引入了一个新的原生类型:Symbol,但是,和其他原生数据类型不一样,symbol没有字面量形式。作为构造函数来说它并不完整,因为它不支持语法:&quot;<code>new Symbol()</code>&quot;。</p><p cid="n43" mdtype="paragraph">下面是创建Symbol的过程:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;sym&nbsp;=&nbsp;Symbol(&#39;something&#39;); console.log(typeof&nbsp;sym);&nbsp;//symbol console.dir(Symbol)</pre><p cid="n46" mdtype="paragraph">注意事项:</p><ul class="ul-list list-paddingleft-2" cid="n48" mdtype="list" data-mark="-" style="list-style-type: square;"><li><p cid="n50" mdtype="paragraph">不能也不应该对Symbol()使用new。它不是一个构造器,也不会创建一个对象。</p></li><li><p cid="n53" mdtype="paragraph">传给Symbol(...)的参数是可选的,如果传入了的话,应该是一个为这个symbol的用途给出用户友好描述的字符串。</p></li><li><p cid="n56" mdtype="paragraph">typeof的输出是一个新的值&quot;symbol&quot;,这是识别symbol的首选方法。</p></li></ul><p cid="n58" mdtype="paragraph">两个Symbol永远不会相等</p><pre class="prism-highlight prism-language-javascript">console.log(Symbol(&#39;name&#39;)&nbsp;===&nbsp;Symbol(&#39;name&#39;));&nbsp;//&nbsp;false</pre><h3>1.1 为对象添加私有成员</h3><p cid="n62" mdtype="paragraph">利用Symbol不重复的特性,可以为对象添加不重复的键名。</p><p cid="n64" mdtype="paragraph">每个从&nbsp;<code>Symbol()</code>&nbsp;返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型的目的。</p><pre class="prism-highlight prism-language-javascript">//使用&nbsp;Symbol&nbsp;为对象添加不重复的键 const&nbsp;obj&nbsp;=&nbsp;{} obj[Symbol()]&nbsp;=&nbsp;&#39;123&#39; obj[Symbol()]&nbsp;=&nbsp;&#39;456&#39; console.log(obj) //也可以在计算属性名中使用 const&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;[Symbol()]:&nbsp;123 } console.log(obj)</pre><p>利用两个Symbol不相等的特性,可以为对象创建私有成员,外部不能访问。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;axisName&nbsp;=&nbsp;Symbol(&#39;obj的别名&#39;); const&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;利用这种方式可以创建私有成员,外部不能访问 &nbsp;&nbsp;&nbsp;&nbsp;[Symbol(&#39;obj的id&#39;)]:&nbsp;1, &nbsp;&nbsp;&nbsp;&nbsp;[Symbol(&#39;obj的name&#39;)]:&nbsp;&#39;obj&#39;, &nbsp;&nbsp;&nbsp;&nbsp;[axisName]:&nbsp;&#39;myObj&#39;, &nbsp;&nbsp;&nbsp;&nbsp;url:&nbsp;&#39;http://www.xxx.com&#39; } //&nbsp;外部不能访问,因为没有两个Symbol是一样的。 console.log(obj[Symbol(&#39;obj的id&#39;)]); console.log(obj[axisName]); console.log(obj.url);</pre><p>常规的方式不能获取Symbol属性名</p><pre class="prism-highlight prism-language-javascript">//&nbsp;for...in遍历不出Symbol,仅包含了以字符串为键的属性 for(const&nbsp;key&nbsp;in&nbsp;obj){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(key) } //&nbsp;也不能返回Symbol,仅包含了对象自身的、可枚举的、以字符串为键的属性 console.log(Object.keys(obj)) //&nbsp;当使用&nbsp;JSON.stringify()&nbsp;时,以&nbsp;symbol&nbsp;值作为键的属性会被完全忽略: console.log(JSON.stringify(obj))</pre><p>ES6的Object专门提供了一个方法用于获取对象的Symbol属性。</p><pre class="prism-highlight prism-language-javascript">//其包含的是以&nbsp;Symbol&nbsp;为键的属性 console.log(Object.getOwnPropertySymbols(obj));&nbsp;//[Symbol(obj的id),&nbsp;Symbol(obj的name),&nbsp;Symbol(obj的别名)]</pre><h3>1.2 内置的Symbol属性</h3><p cid="n77" mdtype="paragraph">除了自己创建的 symbol,JavaScript 还内建了一些在 ECMAScript 5 之前没有暴露给开发者的 symbol,它们代表了内部语言行为。它们可以使用以下属性访问:</p><p cid="n79" mdtype="paragraph">1、迭代 symbols&nbsp;<code>Symbol.iterator</code> </p><p cid="n81" mdtype="paragraph">一个返回一个对象默认迭代器的方法。被&nbsp;<code>for...of</code>&nbsp;使用。</p><p cid="n83" mdtype="paragraph">object默认没有这个迭代属性,所以不能使用for...of,但是可以自己定义</p><pre class="prism-highlight prism-language-javascript">//通过数组可以观察这个迭代器 const&nbsp;arr&nbsp;=&nbsp;[1,&nbsp;2,&nbsp;3]; console.log(arr[Symbol.iterator]);&nbsp;//&nbsp;f() const&nbsp;it&nbsp;=&nbsp;arr[Symbol.iterator]();&nbsp;//{next:&nbsp;f(){}} console.log(it.next());&nbsp;//{value:&nbsp;1,&nbsp;done:&nbsp;false} console.log(it.next()) console.log(it.next()) console.log(it.next());&nbsp;//{value:&nbsp;undefined,&nbsp;done:&nbsp;true}</pre><pre class="prism-highlight prism-language-javascript">const&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;&#39;诸葛&#39;, &nbsp;&nbsp;&nbsp;&nbsp;age:&nbsp;18, &nbsp;&nbsp;&nbsp;&nbsp;address:&nbsp;&#39;卧龙岗&#39;, &nbsp;&nbsp;&nbsp;&nbsp;[Symbol.iterator]:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;_this&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;num&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;keys&nbsp;=&nbsp;Object.keys(_this); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;_this[keys[num++]], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done:&nbsp;num&nbsp;&gt;&nbsp;keys.length &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} } //现在可以使用for...of迭代obj了 for(const&nbsp;value&nbsp;of&nbsp;myObj){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(value); }</pre><p cid="n87" mdtype="paragraph">2、<code>Symbol.replace</code> </p><p cid="n89" mdtype="paragraph">一个替换匹配字符串的子串的方法。被&nbsp;<code>String.prototype.replace()</code>&nbsp;使用。</p><p cid="n91" mdtype="paragraph">3、<code>Symbol.split</code> </p><p cid="n93" mdtype="paragraph">一个在匹配正则表达式的索引处拆分一个字符串的方法.。被&nbsp;<code>String.prototype.split()</code>&nbsp;使用。</p><p cid="n95" mdtype="paragraph">更多了解:</p><p cid="n97" mdtype="paragraph"><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol</a></p><h2>2、Set数据结构</h2><p cid="n100" mdtype="paragraph">Set&nbsp;对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。</p><p cid="n102" mdtype="paragraph"><code>Set</code>对象是值的集合,Set 中的元素只会出现一次,即 Set 中的元素是唯一的。</p><p cid="n104" mdtype="paragraph"><code>NaN</code>&nbsp;和&nbsp;<code>undefined</code>&nbsp;都可以被存储在 Set 中,<code>NaN</code>&nbsp;被视为相同的值(NaN 被认为是相同的,尽管 NaN !== NaN)。</p><h3>2.1 创建一个set数据结构的实例</h3><pre class="prism-highlight prism-language-javascript">//Set&nbsp;构造函数能创建&nbsp;Set&nbsp;对象实例 const&nbsp;mySet&nbsp;=&nbsp;new&nbsp;Set();&nbsp;//&nbsp;Set(0)&nbsp;{size:&nbsp;0}</pre><p>参数iterable 可选,如果传递一个可迭代对象,它的所有元素将不重复地被添加到新的&nbsp;<code>Set</code>&nbsp;中。如果不指定此参数或其值为&nbsp;<code>null</code>,则新的&nbsp;<code>Set</code>&nbsp;为空,返回一个新的&nbsp;<code>Set</code>&nbsp;对象。 &nbsp;</p><pre class="prism-highlight prism-language-javascript">const&nbsp;mySet1&nbsp;=&nbsp;new&nbsp;Set([1,2,2,3,3,4,5]); console.log(mySet1);//Set(5)&nbsp;{1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5}</pre><h3>2.2 实例的方法</h3><h4>2.2.1 添加add(value)</h4><p>如果&nbsp;<code>Set</code>&nbsp;对象中没有具有相同值的元素,则&nbsp;add()&nbsp;方法将插入一个具有指定值的新元素到&nbsp;<code>Set</code>&nbsp;对象中。 并返回<code>Set</code>&nbsp;对象本身,因此可以链式调用。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;mySet&nbsp;=&nbsp;new&nbsp;Set(); mySet.add(1).add(true).add(&#39;Tom&#39;).add(18) console.log(mySet);&nbsp;//Set(4)&nbsp;{1,&nbsp;true,&nbsp;&#39;Tom&#39;,&nbsp;18}</pre><h4>2.2.2 移除某个值delete(value)</h4><p cid="n117" mdtype="paragraph">delete()&nbsp;方法从&nbsp;<code>Set</code>&nbsp;对象中删除指定的值(如果该值在&nbsp;<code>Set</code>&nbsp;中)。</p><p cid="n119" mdtype="paragraph">成功删除返回&nbsp;<code>true</code>,否则返回&nbsp;<code>false</code>。</p><pre class="prism-highlight prism-language-javascript">console.log(mySet.delete(&#39;Tom&#39;));&nbsp;//&nbsp;true console.log(mySet.delete(&#39;daisy&#39;));//false</pre><p cid="n122" mdtype="paragraph">从Set中删除对象。</p><p cid="n124" mdtype="paragraph">因为对象是通过引用比较的,所以如果没有对原始对象的引用,就必须通过检查单个属性来删除它们。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;setObj&nbsp;=&nbsp;new&nbsp;Set(); setObj.add({&nbsp;x:&nbsp;5,&nbsp;y:&nbsp;20&nbsp;}).add({&nbsp;x:&nbsp;20,&nbsp;y:&nbsp;30&nbsp;}); //&nbsp;删除任何x&nbsp;&gt;&nbsp;10&nbsp;的对象&nbsp; setObj.forEach(point&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(point.x&nbsp;&gt;&nbsp;10)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setObj.delete(point); &nbsp;&nbsp;&nbsp;&nbsp;} }) console.log(setObj)</pre><h4>2.2.3 移除所有元素 clear()</h4><p cid="n128" mdtype="paragraph">clear()&nbsp;方法移除&nbsp;<code>Set</code>&nbsp;对象中所有元素。 返回值为undefined.</p><pre class="prism-highlight prism-language-javascript">mySet.clear()</pre><h4>2.2.4 has(value)</h4><p cid="n132" mdtype="paragraph">has()&nbsp;方法返回一个布尔值来指示对应的值是否存在于&nbsp;<code>Set</code>&nbsp;对象中。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;setObj&nbsp;=&nbsp;new&nbsp;Set(); setObj.add({&nbsp;x:&nbsp;5,&nbsp;y:&nbsp;20&nbsp;}).add({&nbsp;x:&nbsp;20,&nbsp;y:&nbsp;30&nbsp;}).add(&#39;circle&#39;); console.log(setObj.has({&nbsp;x:&nbsp;20,&nbsp;y:&nbsp;30}));&nbsp;//&nbsp;false,不是一个对象的引用 console.log(setObj.has(&#39;circle&#39;));&nbsp;//true</pre><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set</a></p><h3>2.3 实例的属性</h3><p cid="n138" mdtype="paragraph">size&nbsp;属性将会返回&nbsp;<code>Set</code>&nbsp;对象中(唯一的)元素的个数。</p><p cid="n140" mdtype="paragraph"><code>size</code>&nbsp;的值是一个整数,表示&nbsp;<code>Set</code>&nbsp;对象有多少条目。<code>size</code>&nbsp;的 set 访问函数是&nbsp;<code>undefined</code>;你不能改变这个属性。 也就是只能读不能写。</p><h3>2.4 遍历</h3><h4>2.4.1 forEach()</h4><p cid="n144" mdtype="paragraph">forEach()&nbsp;方法对&nbsp;<code>Set</code>&nbsp;对象中的每个值按插入顺序执行一次提供的函数。</p><pre class="prism-highlight prism-language-javascript">&nbsp;setObj.forEach(item&nbsp;=&gt;&nbsp;console.log(item))</pre><h4>2.4.2 for ... of</h4><pre class="prism-highlight prism-language-javascript">for(const&nbsp;item&nbsp;of&nbsp;setObj){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(item); }</pre><h3>2.5 应用场景</h3><h4>2.5.1 和数组的转换</h4><pre class="prism-highlight prism-language-javascript">//&nbsp;数组去重 const&nbsp;arr&nbsp;=&nbsp;[1,1,2,2,3,3,4,5]; //const&nbsp;newArr&nbsp;=&nbsp;Array.from(new&nbsp;Set(arr)); const&nbsp;newArr&nbsp;=&nbsp;[...new&nbsp;Set(arr)]; console.log(newArr);&nbsp;//&nbsp;[1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5]</pre><h4>2.5.2 和字符串相关</h4><pre class="prism-highlight prism-language-javascript">let&nbsp;str1&nbsp;=&nbsp;&#39;javascript&#39;; let&nbsp;str2&nbsp;=&nbsp;&#39;JAvaScript&#39;; let&nbsp;s1&nbsp;=&nbsp;new&nbsp;Set(str1); let&nbsp;s2&nbsp;=&nbsp;new&nbsp;Set(str2); //大小写敏感 console.log(s1);&nbsp;//Set(9)&nbsp;{&#39;j&#39;,&nbsp;&#39;a&#39;,&nbsp;&#39;v&#39;,&nbsp;&#39;s&#39;,&nbsp;&#39;c&#39;,&nbsp;…} console.log(s2);&nbsp;//Set(10)&nbsp;{&#39;J&#39;,&nbsp;&#39;A&#39;,&nbsp;&#39;v&#39;,&nbsp;&#39;a&#39;,&nbsp;&#39;S&#39;,&nbsp;…}</pre><h2>3、Map数据结构</h2><p cid="n155" mdtype="paragraph">Map&nbsp;对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值。</p><h3>3.1 对键值的操作</h3><pre class="prism-highlight prism-language-javascript">//&nbsp;创建一个map实例 const&nbsp;myMap&nbsp;=&nbsp;new&nbsp;Map(); //&nbsp;这种方式赋值不能改变map的数据结构,所以不推荐 //&nbsp;myMap.name&nbsp;=&nbsp;&#39;mrszhao&#39;; //&nbsp;正确的方式,使用set方法 myMap.set(&#39;name&#39;,&nbsp;&#39;mrszhao&#39;); myMap.set(&#39;age&#39;,&nbsp;18); myMap.set(&#39;city&#39;,&nbsp;&#39;成都&#39;); myMap.set(&#39;city&#39;,&nbsp;&#39;重庆&#39;); //&nbsp;使用get方法获取键的值 console.log(myMap.get(&#39;city&#39;)); //&nbsp;size属性获取键值对的数量 console.log(myMap.size); //&nbsp;删除键值对,返回布尔值 myMap.delete(&#39;age&#39;); //&nbsp;判断知否存在某个键,返回布尔值 console.log(myMap.has(&#39;name&#39;)) console.log(myMap);</pre><p>注意:键名具有唯一性,重复设置,后面的值会覆盖前面的值,而且,键值对是根据设置的顺序保存的。</p><h3>3.2 键名可以是任意的数据类型</h3><p cid="n162" mdtype="paragraph">object对象的键名只能是string和symbol,而map数据的键名可以是任意数据类型,包括复杂数据类型。</p><pre class="prism-highlight prism-language-javascript">//对象的键名会被转成字符串,对象转成字符串是[object&nbsp;Object] const&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;[Symbol()]:&nbsp;&#39;mrszhaoObj&#39;, &nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;&#39;诸葛&#39;, &nbsp;&nbsp;&nbsp;&nbsp;1:&nbsp;1, &nbsp;&nbsp;&nbsp;&nbsp;true:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;[{a:&nbsp;1}]:&nbsp;&#39;a&#39; } console.log(obj); obj[{b:&nbsp;1}]&nbsp;=&nbsp;&#39;b&#39;; console.log(Object.keys(obj)) console.log(obj[&#39;[object&nbsp;Object]&#39;])</pre><p>map的优势在于可以使用对象作为键名。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;o&nbsp;=&nbsp;{b:&nbsp;2}; myMap.set({a:&nbsp;1},&nbsp;&#39;a&#39;); myMap.set(o,&nbsp;&#39;b&#39;); myMap.set(function&nbsp;a(){}&nbsp;,&nbsp;1); myMap.set(true,&nbsp;1); //对象的key只能出现一次&nbsp;&nbsp;要用对象来设键名的时候,一定要在外面设变量 //&nbsp;因为{}&nbsp;===&nbsp;{}&nbsp;false console.log(map.get({a:&nbsp;1}));&nbsp;//undefined console.log(map.get(o));&nbsp;//&nbsp;&#39;b&#39;</pre><h3>3.3 map的遍历</h3><pre class="prism-highlight prism-language-javascript">//&nbsp;第一个参数是value,第二个参数是key &nbsp;myMap.forEach((value,&nbsp;key)&nbsp;=&gt;&nbsp;console.log(key,&nbsp;value));</pre><p>因为拥有迭代器属性,可以使用for...of</p><pre class="prism-highlight prism-language-javascript">//&nbsp;遍历出来的item是一个包含key和value的数组 //&nbsp;使用数组的解构方式 for(const&nbsp;[key,&nbsp;value]&nbsp;of&nbsp;myMap){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(key,&nbsp;value) }</pre><pre class="prism-highlight prism-language-javascript">//只遍历键名。myMap.keys()返回一个有迭代器的对象,所以可以用for...of for(const&nbsp;key&nbsp;of&nbsp;myMap.keys()){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(key) } //&nbsp;只遍历值 for(const&nbsp;value&nbsp;of&nbsp;myMap.values()){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(value) }</pre><h3>3.4 map和数组的转换</h3><pre class="prism-highlight prism-language-javascript">const&nbsp;arrMap&nbsp;=&nbsp;[[&#39;key1&#39;,&nbsp;&#39;value1&#39;],&nbsp;[&#39;key2&#39;,&nbsp;&#39;value2&#39;]]; //使用常规的&nbsp;Map&nbsp;构造函数可以将一个二维键值对数组转换成一个&nbsp;Map&nbsp;对象 const&nbsp;myMap1&nbsp;=&nbsp;new&nbsp;Map(arrMap);</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;const&nbsp;newArr&nbsp;=&nbsp;Array.from(myMap1); //最简单的是使用...扩展运算符展开对象,再放入数组。 &nbsp;&nbsp;&nbsp;const&nbsp;newArr&nbsp;=&nbsp;[...myMap];</pre><p cid="n179" mdtype="paragraph">更多Map和Object对象的差别,可以查看文档:</p><p cid="n181" mdtype="paragraph"><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map</a></p><h2>4、Object相关</h2><h3>4.1 Object.assign()</h3><pre class="prism-highlight prism-language-javascript">Object.assign(target,&nbsp;...sources)</pre><p cid="n188" mdtype="paragraph">Object.assign()&nbsp;方法将所有可枚举(<code>Object.propertyIsEnumerable()</code>&nbsp;返回 true)的自有(<code>Object.hasOwnProperty()</code>&nbsp;返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。</p><p cid="n190" mdtype="paragraph">如果目标对象与源对象具有相同的&nbsp;key,则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的属性。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;target&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;1, &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;2 } const&nbsp;source1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2, &nbsp;&nbsp;&nbsp;&nbsp;c:&nbsp;3 } const&nbsp;source2&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;d:&nbsp;4 } const&nbsp;result&nbsp;=&nbsp;Object.assign(target,&nbsp;source1,&nbsp;source2); console.log(result,&nbsp;result&nbsp;===&nbsp;target);</pre><p>点击空白页面产生小球,点击小球删除自己。<a href="http://www.mrszhao.com/zb_users/upload/2023/07/randomBall.html" rel="nofollow" target="_blank" title="点击页面产生随机颜色的小球">试试</a>。看到空白页面使劲点。</p><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Circle(option)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;option&nbsp;=&nbsp;option&nbsp;||&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.shape&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r:&nbsp;30, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bgColor:&nbsp;&#39;#f60&#39;, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;0, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object.assign(this.shape,&nbsp;option); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;Circle.prototype.removeCircle&nbsp;=&nbsp;function()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;我被干掉了&#39;); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oHTML&nbsp;=&nbsp;document.documentElement; &nbsp;&nbsp;&nbsp;&nbsp;oHTML.addEventListener(&#39;click&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;circle&nbsp;=&nbsp;new&nbsp;Circle({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r:&nbsp;getRandom(20,&nbsp;50), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bgColor:&nbsp;`rgba(${getRandom(0,&nbsp;255)},${getRandom(0,&nbsp;255)},${getRandom(0,&nbsp;255)},&nbsp;${Math.random()})`, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;e.x, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;e.y, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(circle); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oDiv&nbsp;=&nbsp;document.createElement(&#39;div&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oDiv.style.cssText&nbsp;=&nbsp;`width:${circle.shape.r&nbsp;*&nbsp;2}px;height:${circle.shape.r&nbsp;*&nbsp;2}px;background-color:${circle.shape.bgColor};border-radius:50%;position:absolute;left:${circle.shape.x&nbsp;-&nbsp;circle.shape.r}px;top:${circle.shape.y&nbsp;-&nbsp;circle.shape.r}px;transition:0.2s`; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.body.appendChild(oDiv); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oDiv.addEventListener(&#39;click&#39;,&nbsp;function(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.remove(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circle.removeCircle(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.stopPropagation(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;getRandom(min,&nbsp;max)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Math.floor(Math.random()&nbsp;*&nbsp;(max&nbsp;-&nbsp;min&nbsp;+&nbsp;1)&nbsp;+&nbsp;min); &nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>4.2 Object.is()</h3><p cid="n197" mdtype="paragraph">Object.is()&nbsp;方法判断两个值是否为同一个值。</p><pre class="prism-highlight prism-language-javascript">Object.is(value1,&nbsp;value2);</pre><p>Object.is的判断规则和==和===都不同。</p><pre class="prism-highlight prism-language-javascript">console.log(Object.is(+0,&nbsp;-0),&nbsp;+0&nbsp;===&nbsp;-0);&nbsp;//&nbsp;false&nbsp;true console.log(Object.is(NaN,&nbsp;NaN),&nbsp;NaN&nbsp;===&nbsp;NaN);&nbsp;//true&nbsp;false console.log(Object.is(undefined,&nbsp;null),&nbsp;undefined&nbsp;==&nbsp;null);&nbsp;//false&nbsp;true</pre><h3>4.3 Object.create()</h3><p cid="n204" mdtype="paragraph">Object.create()&nbsp;方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。</p><p>比如下面这个万博manbext3.0首页登录,点击页面产生一个圆,点击圆本身,会弹出它的面积。<a href="http://www.mrszhao.com/zb_users/upload/2023/07/borderCircle.html" rel="nofollow" target="_blank" title="点击页面产生圆">试试</a>。<br/></p><p>核心代码:</p><pre class="prism-highlight prism-language-javascript">//&nbsp;创建一个大类&nbsp;圆,有半径,x坐标,&nbsp;y坐标三个属性 &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Circle(r&nbsp;=&nbsp;20,&nbsp;x&nbsp;=&nbsp;0,&nbsp;y&nbsp;=&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.r&nbsp;=&nbsp;r; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.x&nbsp;=&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.y&nbsp;=&nbsp;y; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;有一个原型上的获取面积的方法 &nbsp;&nbsp;&nbsp;&nbsp;Circle.prototype.getArea&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Math.floor(Math.PI&nbsp;*&nbsp;(this.r&nbsp;**&nbsp;2)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;创建一个子类,产生有背景颜色的圆 &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;BgcolorCircle(bgcolor&nbsp;=&nbsp;&#39;#000&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.bgcolor&nbsp;=&nbsp;bgcolor; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;执行大类的构造函数,让子类也有这三个属性,并且有默认值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Circle.call(this); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;把大类的原型对象当作小类的原型对象的原型,小类的实例也可以访问大类原型上的方法 &nbsp;&nbsp;&nbsp;&nbsp;BgcolorCircle.prototype&nbsp;=&nbsp;Object.create(Circle.prototype); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果不指定构造函数,会默认指向Circle上级对象 &nbsp;&nbsp;&nbsp;&nbsp;BgcolorCircle.prototype.constructor&nbsp;=&nbsp;BgcolorCircle; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oHTML&nbsp;=&nbsp;document.documentElement; &nbsp;&nbsp;&nbsp;&nbsp;oHTML.addEventListener(&#39;click&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;cc&nbsp;=&nbsp;new&nbsp;BgcolorCircle(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cc.r&nbsp;=&nbsp;getRandom(10,&nbsp;100); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cc.x&nbsp;=&nbsp;e.x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cc.y&nbsp;=&nbsp;e.y; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cc.bgcolor&nbsp;=&nbsp;`rgba(${getRandom(70,&nbsp;255)},${getRandom(70,&nbsp;255)},${getRandom(70,&nbsp;255)})`; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oDiv&nbsp;=&nbsp;document.createElement(&#39;div&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oDiv.style.cssText&nbsp;=&nbsp;`width:&nbsp;${cc.r&nbsp;*&nbsp;2}px;height:${cc.r&nbsp;*&nbsp;2}px;position:absolute;left:${cc.x&nbsp;-&nbsp;cc.r}px;top:${cc.y&nbsp;-&nbsp;cc.r}px;background-color:&nbsp;${cc.bgcolor};border-radius:50%`; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.body.appendChild(oDiv); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oDiv.addEventListener(&#39;click&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(`我的面积是:${cc.getArea()}`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.stopPropagation(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;getRandom(min,&nbsp;max)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Math.floor(Math.random()&nbsp;*&nbsp;(max&nbsp;-&nbsp;min&nbsp;+&nbsp;1)&nbsp;+&nbsp;min); &nbsp;&nbsp;&nbsp;&nbsp;}</pre><h2>5、class类</h2><p>看看Class类这个语法糖有多甜。<br/></p><h3>5.1 声明类</h3><pre class="prism-highlight prism-language-javascript">//&nbsp;类声明,没有提升,先声明再实例化 class&nbsp;Circle&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//用于创建和初始化一个由class创建的对象 &nbsp;&nbsp;&nbsp;&nbsp;constructor(r&nbsp;=&nbsp;20,&nbsp;x&nbsp;=&nbsp;0,&nbsp;y&nbsp;=&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.r&nbsp;=&nbsp;r; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.x&nbsp;=&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.y&nbsp;=&nbsp;y; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;getter&nbsp;只读属性 &nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;area()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.getArea(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;原型方法 &nbsp;&nbsp;&nbsp;&nbsp;getArea()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(Math.PI&nbsp;*&nbsp;(this.r&nbsp;**&nbsp;2)).toFixed(2); &nbsp;&nbsp;&nbsp;&nbsp;} } const&nbsp;c&nbsp;=&nbsp;new&nbsp;Circle(50); console.log(c); console.log(c.area); console.log(c.getArea());</pre><h3>5.2 静态属性和方法</h3><p cid="n211" mdtype="paragraph">不能在类的实例上调用静态方法,而应该通过类本身调用。</p><pre class="prism-highlight prism-language-javascript">//&nbsp;类声明,没有提升,先声明再实例化 class&nbsp;Circle&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//用于创建和初始化一个由class创建的对象 &nbsp;&nbsp;&nbsp;&nbsp;constructor(r&nbsp;=&nbsp;20,&nbsp;x&nbsp;=&nbsp;0,&nbsp;y&nbsp;=&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.r&nbsp;=&nbsp;r; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.x&nbsp;=&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.y&nbsp;=&nbsp;y; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;getter&nbsp;只读属性 &nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;area()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.getArea(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;静态属性,只有类能访问,实例不能访问 &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;proname&nbsp;=&nbsp;&#39;Circle&#39;; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;原型方法 &nbsp;&nbsp;&nbsp;&nbsp;getArea()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(Math.PI&nbsp;*&nbsp;(this.r&nbsp;**&nbsp;2)).toFixed(2); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;静态方法 &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;createDefaultCircle()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Circle(); &nbsp;&nbsp;&nbsp;&nbsp;} } //&nbsp;只能类访问静态属性和静态方法 console.log(Circle.proname); console.log(Circle.createDefaultCircle());</pre><h3>5.3 extends扩展子类</h3><p cid="n215" mdtype="paragraph">extends&nbsp;关键字用于类声明中,以创建一个类,该类是另一个类的子类。</p><pre class="prism-highlight prism-language-javascript">class&nbsp;ChildClass&nbsp;extends&nbsp;ParentClass&nbsp;{&nbsp;...&nbsp;}</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;使用extends扩展内置对象,产生一个内置对象的子类 class&nbsp;myDate&nbsp;extends&nbsp;Date&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;constructor(date&nbsp;=&nbsp;new&nbsp;Date())&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;super&nbsp;关键字用于调用对象的父对象上的函数。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;调用超类构造函数并执行。相当于Circle.call(this); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;并把子类的参数传递给父类。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(date); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;getFormattedDate()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;week&nbsp;=&nbsp;[&#39;星期天&#39;,&nbsp;&#39;星期一&#39;,&nbsp;&#39;星期二&#39;,&nbsp;&#39;星期三&#39;,&nbsp;&#39;星期四&#39;,&nbsp;&#39;星期五&#39;,&nbsp;&#39;星期六&#39;]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;date&nbsp;=&nbsp;this.getDate(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;month&nbsp;=&nbsp;this.getMonth()&nbsp;+&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;year&nbsp;=&nbsp;this.getFullYear(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;date&nbsp;=&nbsp;date&nbsp;&lt;&nbsp;10&nbsp;?&nbsp;&#39;0&#39;&nbsp;+&nbsp;date&nbsp;:&nbsp;date; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;month&nbsp;=&nbsp;month&nbsp;&lt;&nbsp;10&nbsp;?&nbsp;&#39;0&#39;&nbsp;+&nbsp;month&nbsp;:&nbsp;month; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;`${year}.${month}.${date}&nbsp;${week[this.getDay()]}`; &nbsp;&nbsp;&nbsp;&nbsp;} }&nbsp; const&nbsp;mydate&nbsp;=&nbsp;new&nbsp;myDate(); console.log(mydate.getFormattedDate()); const&nbsp;mydate1&nbsp;=&nbsp;new&nbsp;myDate(&#39;2023-10-1&#39;) console.log(mydate1.getFormattedDate());</pre><p>扩展Circle的子类对象</p><pre class="prism-highlight prism-language-javascript">class&nbsp;ColorCircle&nbsp;extends&nbsp;Circle&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;constructor(bgcolor&nbsp;=&nbsp;&#39;#000&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果子类中定义了构造函数,那么它必须先调用&nbsp;super()&nbsp;才能使用&nbsp;this&nbsp;。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(super());//返回了子对象,后面才能使用this来指向子对象。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.bgcolor&nbsp;=&nbsp;bgcolor; &nbsp;&nbsp;&nbsp;&nbsp;} } const&nbsp;bgcircle&nbsp;=&nbsp;new&nbsp;ColorCircle(&#39;#f30&#39;); console.log(bgcircle); bgcircle.r&nbsp;=&nbsp;30; console.log(bgcircle.area); class&nbsp;BorderCircle&nbsp;extends&nbsp;Circle&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;constructor(border&nbsp;=&nbsp;&#39;1px&nbsp;solid&nbsp;#000&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.border&nbsp;=border; &nbsp;&nbsp;&nbsp;&nbsp;} } const&nbsp;bordercircle&nbsp;=&nbsp;new&nbsp;BorderCircle(); console.log(bordercircle); bordercircle.border&nbsp;=&nbsp;`5px&nbsp;solid&nbsp;${bgcircle.bgcolor}` bordercircle.r&nbsp;=&nbsp;40; console.log(bordercircle.area);</pre><p>现在Class类的写法比起以前原型的复杂写法看起来要清爽很多。</p><p>还有一些高级的内容,比如Promise异步、代理等等,后面有时间再写了。<br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/341.html" rel="nofollow" target="_blank">继续阅读《JavaScript(ES6)的常用特性!(下)》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-319.html">ES6</a>, rel="nofollow" rel="nofollow"<a href="http://www.mrszhao.com/tags-320.html">Set</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-321.html">Map</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-322.html">Class</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/341.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/341.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/235.html">JavaScript基础5:NaN和isNaN到底是啥?</a> (2019-07-12) </li><li><a href="http://www.mrszhao.com/post/339.html" rel="nofollow">用原型重写数组迭代方法(下)</a> rel="nofollow" (2023-07-15) </li><li><a href="http://www.mrszhao.com/post/260.html">DOM基础7:事件绑定的第二种方式addEventListener</a> rel="nofollow" (2019-08-26) </li><li><a href="http://www.mrszhao.com/post/243.html">JavaScript基础11:Function函数的基础介绍</a> (2019-08-06) </li><li><a href="http://www.mrszhao.com/post/300.html">正则这个火星文!!!</a> rel="nofollow" rel="nofollow" (2021-11-05) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Thu, 20 Jul 2023 17:25:06 +0800一半设计一半前端http://www.mrszhao.com/post/342.html<p>这个版本算是JavaScript划时代的一个升级了,从ES3、ES5、ES6,为什么没有ES4,其实ES5和ES6加起来就是曾经因为跨度太大导致流产的ES4.<br/></p><p>这个版本升级的力度很大,有了很多新东西,需要好好掌握。</p><h2>1、ES6介绍</h2><p cid="n41" mdtype="paragraph">ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。</p><p cid="n43" mdtype="paragraph">2011 年,ECMAScript 5.1 版发布后,就开始制定 6.0 版了。因此,ES6 这个词的原意,就是指 JavaScript 语言的下一个版本。</p><p cid="n45" mdtype="paragraph">标准在每年的 6 月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的 6 月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。</p><p cid="n47" mdtype="paragraph">ES6 的第一个版本,就这样在 2015 年 6 月发布了,正式名称就是《ECMAScript 2015 标准》(简称 ES2015)。2016 年 6 月,小幅修订的《ECMAScript 2016 标准》(简称 ES2016)如期发布,这个版本可以看作是 ES6.1 版,因为两者的差异非常小(只新增了数组实例的<code>includes</code>方法和指数运算符),基本上是同一个标准。根据计划,2017 年 6 月发布 ES2017 标准。</p><p cid="n49" mdtype="paragraph">因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”。</p><h2>2、块作用域声明</h2><p cid="n52" mdtype="paragraph">在ES6以前,只有全局和函数局部作用域,需要创建局部作用域,最普通的方法除了普通的函数声明之外,就是立即调用函数表达式(IIFE)。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;a&nbsp;=&nbsp;10; (function&nbsp;IIFE(){ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;a&nbsp;=&nbsp;20; &nbsp;&nbsp;&nbsp;&nbsp;console.log(a); })(); console.log(a);</pre><h3>2.1 let声明</h3><p cid="n56" mdtype="paragraph">在ES6中,只需要一对{}就可以创建一个块作用域。</p><pre class="prism-highlight prism-language-javascript">{ &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;a&nbsp;=&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;if(a&nbsp;&gt;&nbsp;1){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;b&nbsp;=&nbsp;a&nbsp;*&nbsp;3; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(b);&nbsp;//&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(let&nbsp;i&nbsp;=&nbsp;a;&nbsp;i&nbsp;&lt;=&nbsp;b;&nbsp;i++){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;j&nbsp;=&nbsp;i&nbsp;+&nbsp;10; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(j); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;c&nbsp;=&nbsp;a&nbsp;+&nbsp;b; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(c); &nbsp;&nbsp;&nbsp;&nbsp;} } 思考:哪些变量只存在于if语句内部?哪些变量只存在于for循环内部?</pre><h4>2.1.1 var变量提升,let变量暂时性死区</h4><pre class="prism-highlight prism-language-javascript">{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(a);&nbsp;//undefined &nbsp;&nbsp;&nbsp;&nbsp;console.log(b);&nbsp;//ReferenceError&nbsp;临时死亡区(TDZ) &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;a; &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;b; }</pre><p cid="n61" mdtype="paragraph">不管是否显性赋值,都不能在let b语句运行之前访问b。</p><p cid="n63" mdtype="paragraph">对于TDZ值和未声明值(以及声明过的),typeof结果是不相同的。</p><pre class="prism-highlight prism-language-javascript">{ &nbsp;&nbsp;&nbsp;&nbsp;//a未声明 &nbsp;&nbsp;&nbsp;&nbsp;if(typeof&nbsp;a&nbsp;===&nbsp;&#39;undefined&#39;){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;变量没有声明&#39;); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//b声明了,但是还处于TDZ &nbsp;&nbsp;&nbsp;&nbsp;if(typeof&nbsp;b&nbsp;===&nbsp;&#39;undefined&#39;){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ReferenceError &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;b; }</pre><p>这里a是未声明的,所以typeof是检查它是否存在的唯一安全的方法,而typeof b 会抛出TDZ错误,因为代码后面有一个let b 声明。</p><h4>2.1.2 let + for</h4><pre class="prism-highlight prism-language-javascript">var&nbsp;funcs&nbsp;=&nbsp;[]; for&nbsp;(var&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;5;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funcs.push(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(i); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); } funcs[0]();&nbsp;//&nbsp;5 funcs[1]();&nbsp;//&nbsp;5 //let&nbsp;方法 var&nbsp;funcs&nbsp;=&nbsp;[]; for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;5;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funcs.push(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(i); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); } funcs[0]();&nbsp;//&nbsp;0 funcs[1]();&nbsp;//&nbsp;1</pre><p cid="n70" mdtype="paragraph">for循环头部的let i 不只为for循环本身声明了一个i,而是为循环的每一次迭代都重新声明了一个新的i。这意味着循环迭代的函数会封闭一个新的i。</p><p cid="n72" mdtype="paragraph">等同于如下代码的功能:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;funcs&nbsp;=&nbsp;[]; for&nbsp;(var&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;5;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;j&nbsp;=&nbsp;i; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funcs.push(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(j); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); } funcs[0]();&nbsp;//&nbsp;0 funcs[1]();&nbsp;//&nbsp;1</pre><p>let放在for...in和for...of循环中也是一样的。</p><h3>2.2 const声明</h3><p cid="n78" mdtype="paragraph">用于创建常量。</p><p cid="n80" mdtype="paragraph">常量是一个设定了初始值之后就只读的变量。</p><p cid="n82" mdtype="paragraph">这个变量的值在声明时设定之后就不允许改变。const声明必须要有显式的初始值。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;PI&nbsp;=&nbsp;3.14; const&nbsp;a&nbsp;=&nbsp;undefined;&nbsp;//&nbsp;如果需要一个值为undefined的常量,就要声明并初始化。 console.log(PI);//&nbsp;3.14 PI&nbsp;=&nbsp;3.1415926;&nbsp;//&nbsp;TypeError</pre><p cid="n85" mdtype="paragraph">常量不是对这个值本身的限制,而是对赋值的那个变量的限制。</p><p cid="n87" mdtype="paragraph">这个值并没有因为const被锁定或者不可变,只是赋值本身不可变。</p><p cid="n89" mdtype="paragraph">如果这个值是复杂值,比如数组或者对象,其内容仍然是可以修改的。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;a&nbsp;=&nbsp;[1,2]; a.push(3); console.log(a);&nbsp;//&nbsp;[1,2,3] a&nbsp;=&nbsp;10;&nbsp;//&nbsp;TypeError</pre><p cid="n92" mdtype="paragraph">变量a持有一个指向数组的地址引用,数组本身是可以改变的,只是这个地址引用不可以变化。</p><p cid="n94" mdtype="paragraph">将一个对象或数组作为常量赋值,意味着这个值在这个常量的词法作用域结束之前不会被垃圾回收,因为指向这个值的引用没有清除。所以如果不想出现这种情况,最好不要用常量指向复杂数据类型。</p><h3>2.3 块作用域函数</h3><p cid="n97" mdtype="paragraph">从ES6开始,块内声明的函数,其作用域在这个块内。</p><pre class="prism-highlight prism-language-javascript">{ &nbsp;&nbsp;&nbsp;&nbsp;foo();&nbsp;//可以调用 &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;} } foo();&nbsp;//&nbsp;ReferenceError</pre><p>要注意以下这种行为,在ES6中会报错</p><pre class="prism-highlight prism-language-javascript">if(something){ &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;1&#39;); &nbsp;&nbsp;&nbsp;&nbsp;} }else{ &nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;2&#39;); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; } foo();&nbsp;//&nbsp;在ES6以前,不管something是什么,foo()都会打印2,因为两个函数声明都会被提升到块外面,第二个总是会覆盖前面的函数声明。在ES6中,最后一行会抛出ReferenceError</pre><h2>3、spread/rest</h2><p cid="n104" mdtype="paragraph">ES6引入的新运算符...,通常称为spread或rest(展开或收集)运算符,取决于它在哪里如何使用。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(x,y,z){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(x,y,z); } foo(...[1,2,3]); let&nbsp;arr&nbsp;=&nbsp;[1,2,3]; //&nbsp;老方法,用apply实现,数组可以作为参数。 //&nbsp;let&nbsp;oNull&nbsp;=&nbsp;Object.create(null); //&nbsp;console.log(Math.max.apply(oNull,arr)); //&nbsp;当...用在可以被遍历的对象前,比如数组,它会把这个变量展开spread为各个独立的值。 let&nbsp;max&nbsp;=&nbsp;Math.max(...arr); console.log(max);</pre><p>还可以在其他上下文中用来展开一个值,比如:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;a&nbsp;=&nbsp;[1,2,3]; let&nbsp;b&nbsp;=&nbsp;[&#39;a&#39;,...a,&#39;b&#39;]; console.log(b);&nbsp;//[&#39;a&#39;,&nbsp;1,&nbsp;2,&nbsp;3,&nbsp;&#39;b&#39;] //&nbsp;老方法,用concat合并数组。 console.log([&#39;a&#39;].concat(a,&#39;b&#39;));</pre><p>除了spread展开之外,还可以反向操作,把一系列值收集到一起成为一个数组。</p><pre class="prism-highlight prism-language-javascript">//z表示:把剩下的参数收集到一起组成一个名为z的数组 function&nbsp;foo(x,y,...z){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(x,y,z); } foo(1,2,3,4,5);&nbsp;//&nbsp;1&nbsp;2&nbsp;[3,4,5]</pre><p>如果没有命名参数的话,就会收集所有的参数:</p><pre class="prism-highlight prism-language-javascript">//这里的...表示收集,可以叫做rest参数,表示收集其余的参数。 function&nbsp;foo(...args){ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;老方法,获得除第一个后面所有的参数 &nbsp;&nbsp;&nbsp;&nbsp;console.log(Array.prototype.slice.call(arguments,1)); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;新方法 &nbsp;&nbsp;&nbsp;&nbsp;console.log(args.slice(1));&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;console.log(args);&nbsp;//[1,&nbsp;2,&nbsp;3,&nbsp;4] &nbsp;&nbsp;&nbsp;&nbsp;//这里的...表示扩展,把数组扩展成单个的值。这里很好的展示了...运算符对称而又相反的用法。 &nbsp;&nbsp;&nbsp;&nbsp;console.log(...args);&nbsp;//1&nbsp;2&nbsp;3&nbsp;4 } foo(1,2,3,4);</pre><h2>4、默认参数值</h2><p cid="n117" mdtype="paragraph">当函数的参数可以缺省的时候,需要设置一个默认的值。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(x,&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//这种默认值设置,当参数可以为0的时候会出错。 &nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;x&nbsp;||&nbsp;10; &nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;=&nbsp;y&nbsp;||&nbsp;20; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x&nbsp;+&nbsp;y; } console.log(foo()); //&nbsp;当x为0的时候,会出错,因为&nbsp;0&nbsp;||&nbsp;10&nbsp;,会返回10 console.log(foo(0,&nbsp;10)); console.log(foo(10))</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;修正参数可以为0的时候,也意味着除了undefined之外的任何值都可以传入。 //&nbsp;如果传入undefined,在这里还是表示该参数缺省。 function&nbsp;foo(x,&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;(x&nbsp;!==&nbsp;undefined)&nbsp;?&nbsp;x&nbsp;:&nbsp;10; &nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;=&nbsp;(y&nbsp;!==&nbsp;undefined)&nbsp;?&nbsp;y&nbsp;:&nbsp;20; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x&nbsp;+&nbsp;y; } console.log(foo()); console.log(foo(0,&nbsp;10)); console.log(foo(10)); //&nbsp;表示第一个参数缺省。 console.log(foo(undefined,10));&nbsp;//&nbsp;20</pre><pre class="prism-highlight prism-language-javascript">//但是如果参数需要传递undefined&nbsp;,可以通过它不存在于arguments中来确定这个参数是否被省略。 function&nbsp;foo(x,y){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(arguments); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这里&nbsp;in&nbsp;表示属性是否存在于对象中,0表示的是下标。 &nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;(0&nbsp;in&nbsp;arguments)&nbsp;?&nbsp;x&nbsp;:&nbsp;10; &nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;=&nbsp;(1&nbsp;in&nbsp;arguments)&nbsp;?&nbsp;y&nbsp;:&nbsp;20; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x&nbsp;+&nbsp;y; } console.log(foo());&nbsp;//&nbsp;30 console.log(foo(10,undefined));&nbsp;//&nbsp;NaN</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;但是如果不能传递任何值,甚至undefined也不行,来表明“我省略了这个参数”,那么如何省略第一个参数呢? //&nbsp;foo(,10)这是不合法的语法,而在函数参数中,undefined和缺失是无法区分的 //&nbsp;所以,只能缺省右侧的参数,而不能省略位于参数列表中间或者起始处的参数。 //&nbsp;ES6新增了一个有用的语法来改进为缺失参数赋默认值的流程。 //&nbsp;这里的x&nbsp;=&nbsp;10更像是x&nbsp;!==&nbsp;undefined&nbsp;?&nbsp;x&nbsp;:&nbsp;10 function&nbsp;foo(x&nbsp;=&nbsp;10,y&nbsp;=&nbsp;20){ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x&nbsp;+&nbsp;y; } console.log(foo());&nbsp;//&nbsp;30 console.log(foo(5));&nbsp;//&nbsp;25 console.log(foo(0,10));&nbsp;//&nbsp;10 console.log(foo(5,undefined));&nbsp;//&nbsp;25&nbsp;,丢掉undefined,用默认值 console.log(foo(5,null));&nbsp;//&nbsp;null转成了0 console.log(foo(undefined,5));&nbsp;//&nbsp;15&nbsp;,undefined转成默认值。 console.log(foo(null,5));&nbsp;//&nbsp;5 console.log(foo(null,undefined));&nbsp;//&nbsp;20 console.log(foo(&#39;&#39;,undefined));&nbsp;//&nbsp;&#39;20&#39; console.log(foo(&#39;&nbsp;&#39;,undefined));&nbsp;//&nbsp;&#39;&nbsp;20&#39; console.log(foo(true,undefined));&nbsp;//&nbsp;21&nbsp;true被强制转成1 console.log(foo(true,false));&nbsp;//&nbsp;1&nbsp;true被强制转成1,false强制转成0</pre><h2>5、解构</h2><p cid="n126" mdtype="paragraph">ES6引入了一个新的语法特性,名为解构(destructuring),把这个功能看作是一个结构化赋值(structured assignment)方法。</p><p cid="n128" mdtype="paragraph">以前的手动赋值方法:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } let&nbsp;temp&nbsp;=&nbsp;foo(); //手动赋值 let&nbsp;a&nbsp;=&nbsp;temp[0],&nbsp;b&nbsp;=&nbsp;temp[1],&nbsp;c&nbsp;=&nbsp;temp[2]; console.log(a,&nbsp;b,&nbsp;c); function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;tmp&nbsp;=&nbsp;bar(); //手动赋值 let&nbsp;x&nbsp;=&nbsp;tmp.x,&nbsp;y&nbsp;=&nbsp;tmp.y,&nbsp;z&nbsp;=&nbsp;tmp.z; console.log(x,&nbsp;y,&nbsp;z)</pre><p cid="n131" mdtype="paragraph">可以把将<strong>数组或者对象属性中带索引的值手动赋值</strong>看做结构化赋值。</p><p cid="n133" mdtype="paragraph">ES6为解构新增了一个专门语法,专用于<strong>数组解构</strong>和<strong>对象解构</strong>。</p><p cid="n135" mdtype="paragraph">这个语法消除了前面代码中对临时变量tmp的需求,使代码简洁更多。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;[a,&nbsp;b,&nbsp;c]&nbsp;=&nbsp;foo(); let&nbsp;{&nbsp;x:&nbsp;x,&nbsp;y:&nbsp;y,&nbsp;z:&nbsp;z&nbsp;}&nbsp;=&nbsp;bar(); console.log(a,&nbsp;b,&nbsp;c); console.log(x,&nbsp;y,&nbsp;z);</pre><h3>5.1 对象属性赋值模式</h3><p cid="n139" mdtype="paragraph">当对象的属性名和要赋值的变量名相同,语法还可以更简洁一些:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;{&nbsp;x,y,z&nbsp;}&nbsp;=&nbsp;bar(); console.log(x,&nbsp;y,&nbsp;z);</pre><p>省略了x:这个部分,如果有需要把属性赋值给非同名变量,则:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;{&nbsp;x:&nbsp;bam,&nbsp;y:&nbsp;baz,&nbsp;z:&nbsp;bap&nbsp;}&nbsp;=&nbsp;bar(); console.log(bam,baz,bap);</pre><p cid="n145" mdtype="paragraph">在对象字面量或者常规的赋值语句中,都是target:source模式,或者说是:property-alias( 属性别名 ):value模式。</p><p cid="n147" mdtype="paragraph">但是在对象解构赋值的时候,反转了target:source模式。变成了source:target。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;aa&nbsp;=&nbsp;10;&nbsp;bb&nbsp;=&nbsp;20; //&nbsp;对象字面量是target:source模式 let&nbsp;o&nbsp;=&nbsp;{&nbsp;x:&nbsp;aa,&nbsp;y:&nbsp;bb&nbsp;}; //&nbsp;对象解构赋值是source:target模式 //&nbsp;如果省略了x:&nbsp;,相当于把aa的值赋值给了AA,bb的值赋值给了BB。 //&nbsp;对称性可以帮助解释为什么ES6这个语法模式进行了反转,虽然脑子有点不习惯。 let&nbsp;{&nbsp;x:&nbsp;AA,&nbsp;y:&nbsp;BB&nbsp;}&nbsp;=&nbsp;o; console.log(AA,&nbsp;BB);&nbsp;//&nbsp;10&nbsp;20</pre><p>可以不用临时变量解决“交换两个变量”这个经典问题:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;x&nbsp;=&nbsp;10,&nbsp;y&nbsp;=&nbsp;20; //&nbsp;老方法 //&nbsp;let&nbsp;temp&nbsp;=&nbsp;0; //&nbsp;temp&nbsp;=&nbsp;x; //&nbsp;x&nbsp;=&nbsp;y; //&nbsp;y&nbsp;=&nbsp;temp; //&nbsp;console.log(x,y);&nbsp;//&nbsp;20&nbsp;10 //&nbsp;新方法 [y,x]&nbsp;=&nbsp;[x,y]; console.log(x,y);&nbsp;//&nbsp;20&nbsp;10</pre><h3>5.2 重复赋值</h3><p>对象解构形式允许多次列出同一个源属性。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;{a:x,a:y}&nbsp;=&nbsp;{a:1}; console.log(x,y);</pre><h3>5.3 缺省</h3><p cid="n162" mdtype="paragraph">对于数组解构赋值和对象解构赋值,不需要把存在的所有值都用来赋值。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } //&nbsp;因为数组是按照顺序解构的,所以第一个值不要的时候,还是要有占位。 let&nbsp;[,b]&nbsp;=&nbsp;foo(); let&nbsp;{x,z}&nbsp;=&nbsp;bar(); console.log(b,x,z);&nbsp;//&nbsp;2&nbsp;4&nbsp;6</pre><p>当然,如果超过了可以解构的值,多余的值会被赋为undefined.</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;[,,c,d]&nbsp;=&nbsp;foo(); let&nbsp;{w,z}&nbsp;=&nbsp;bar(); console.log(c,d,w,z);&nbsp;//&nbsp;3&nbsp;undefined&nbsp;undefined&nbsp;6</pre><p cid="n168" mdtype="paragraph">这个特性也是符合“undefined就是缺失”的原则。</p><p cid="n170" mdtype="paragraph">...运算符也可以执行解构赋值同样的操作:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } //&nbsp;...b收集了其余的值,组成一个数组。 //&nbsp;在ES6中还没有通过...展开和集合对象的特性。 let&nbsp;[a,...b]&nbsp;=&nbsp;foo(); console.log(a,b);&nbsp;//1&nbsp;[2,&nbsp;3]</pre><h3>5.4 默认值解构</h3><p cid="n174" mdtype="paragraph">使用和前面函数参数默认值类似的=语法,解构也可以提供一个用来赋值的默认值。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;[1,&nbsp;2,&nbsp;3]; } function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;[a&nbsp;=&nbsp;0,&nbsp;b&nbsp;=&nbsp;0,&nbsp;c&nbsp;=&nbsp;0,&nbsp;d&nbsp;=&nbsp;4]&nbsp;=&nbsp;foo(); console.log(a,&nbsp;b,&nbsp;c,&nbsp;d);&nbsp;//&nbsp;1&nbsp;2&nbsp;3&nbsp;4 let&nbsp;{&nbsp;x&nbsp;=&nbsp;0,&nbsp;y&nbsp;=&nbsp;0,&nbsp;z&nbsp;=&nbsp;0,&nbsp;w&nbsp;=&nbsp;10&nbsp;}&nbsp;=&nbsp;bar(); console.log(x,&nbsp;y,&nbsp;z,&nbsp;w);&nbsp;//&nbsp;4&nbsp;5&nbsp;6&nbsp;10</pre><p>或者,属性名和变量名不同的时候:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;bar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:&nbsp;4, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z:&nbsp;6 &nbsp;&nbsp;&nbsp;&nbsp;}; } let&nbsp;{&nbsp;x,&nbsp;y,&nbsp;z,&nbsp;w:&nbsp;WW&nbsp;=&nbsp;20&nbsp;}&nbsp;=&nbsp;bar(); console.log(x,&nbsp;y,&nbsp;z,&nbsp;WW);&nbsp;//4&nbsp;5&nbsp;6&nbsp;20</pre><h3>5.5 嵌套解构</h3><p cid="n181" mdtype="paragraph">如果解构的值中有嵌套的对象或者数组,也可以解构这些嵌套的值:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;a1&nbsp;=&nbsp;[1,&nbsp;[2,&nbsp;3,&nbsp;4],&nbsp;5]; let&nbsp;o1&nbsp;=&nbsp;{&nbsp;x:&nbsp;{&nbsp;y:&nbsp;{&nbsp;z:&nbsp;6&nbsp;}&nbsp;}&nbsp;}; let&nbsp;[a,&nbsp;[b,&nbsp;c,&nbsp;d],&nbsp;e]&nbsp;=&nbsp;a1; let&nbsp;{&nbsp;x:&nbsp;{&nbsp;y:&nbsp;{&nbsp;z:&nbsp;w&nbsp;}&nbsp;}&nbsp;}&nbsp;=&nbsp;o1; console.log(a,b,c,d,e);&nbsp;//&nbsp;1&nbsp;2&nbsp;3&nbsp;4&nbsp;5 console.log(w);&nbsp;//&nbsp;6</pre><p>把嵌套解构当作一种展平对象名字空间的简单方法 .</p><pre class="prism-highlight prism-language-javascript">let&nbsp;App&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;model:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User:&nbsp;function&nbsp;()&nbsp;{//...} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} } //&nbsp;老方法 let&nbsp;User&nbsp;=&nbsp;App.model.User; //&nbsp;新方法 let&nbsp;{&nbsp;model:&nbsp;{&nbsp;User&nbsp;}&nbsp;}&nbsp;=&nbsp;App;</pre><pre class="prism-highlight prism-language-javascript">const&nbsp;APP&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;methods:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;say1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#39;hello&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;say2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#39;world&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} } console.log(APP.methods.say1()); console.log(APP.methods.say2()); //&nbsp;const&nbsp;say1&nbsp;=&nbsp;APP.methods.say1; //&nbsp;const&nbsp;say2&nbsp;=&nbsp;APP.methods.say2; //&nbsp;console.log(say1()); //&nbsp;console.log(say2()); const&nbsp;{&nbsp;methods:&nbsp;{&nbsp;say1&nbsp;},&nbsp;methods:&nbsp;{&nbsp;say2&nbsp;}&nbsp;}&nbsp;=&nbsp;APP; console.log(say1()); console.log(say2());</pre><pre class="prism-highlight prism-language-javascript">const&nbsp;APP&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;say1()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#39;hello&#39;; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;say2()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#39;world&#39;; &nbsp;&nbsp;&nbsp;&nbsp;} } const&nbsp;{&nbsp;say1,&nbsp;say2&nbsp;}&nbsp;=&nbsp;APP; console.log(say1()); console.log(say2());</pre><h2>6、对象字面量扩展</h2><p cid="n192" mdtype="paragraph">ES6为普通{}对象字面量新增了几个重要的便利扩展。</p><h3>6.1 简洁属性</h3><pre class="prism-highlight prism-language-javascript">var&nbsp;x&nbsp;=&nbsp;2,y&nbsp;=&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;o&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x:x, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y:y &nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>当需要定义一个与某个标识符同名的属性的时候,可以把x:x简写成x。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;x&nbsp;=&nbsp;2,y&nbsp;=&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;o&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y &nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>6.2 简洁方法</h3><p cid="n200" mdtype="paragraph">关联到对象字面量属性上的函数也有简洁形式。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;o&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;x:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//... &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;y:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//... &nbsp;&nbsp;&nbsp;&nbsp;} }</pre><p>在ES6中可以简写:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;o&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;x(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//... &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;y(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//... &nbsp;&nbsp;&nbsp;&nbsp;} }</pre><p>这种简洁方式都是使用了匿名函数表达式,所以针对需要递归,需要函数的词法标识符的时候就不可取了。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;getSum:&nbsp;function&nbsp;getSum(num)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(num&nbsp;===&nbsp;1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;num&nbsp;+&nbsp;getSum(num&nbsp;-&nbsp;1); &nbsp;&nbsp;&nbsp;&nbsp;} } console.log(obj.getSum(5))</pre><p>比如下面的这段代码:产生两个随机数字,然后用大的减去小的。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;run(o)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;x&nbsp;=&nbsp;getRandom(0,&nbsp;100); &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;y&nbsp;=&nbsp;getRandom(0,&nbsp;100); &nbsp;&nbsp;&nbsp;&nbsp;console.log(`x:${x},y:${y}`); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(o.calc.name); &nbsp;&nbsp;&nbsp;&nbsp;//通过o.属性名来调用函数,是函数的公开名称 &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;o.calc(x,&nbsp;y); } let&nbsp;result&nbsp;=&nbsp;run({ &nbsp;&nbsp;&nbsp;&nbsp;calc:&nbsp;function&nbsp;calc(x,&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(x&nbsp;&gt;&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//递归,调用函数本身,calc是函数自身的词法标识符,不是对象的属性名称。用于在其自身内部递归调用函数。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;calc(y,&nbsp;x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;y&nbsp;-&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;} }) function&nbsp;getRandom(min,&nbsp;max)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Math.floor(Math.random()&nbsp;*&nbsp;(max&nbsp;-&nbsp;min&nbsp;+&nbsp;1)&nbsp;+&nbsp;min); } console.log(result);</pre><p>如果把上面的代码进行ES6简洁:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;result&nbsp;=&nbsp;run({ &nbsp;&nbsp;&nbsp;&nbsp;calc(x,&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(x&nbsp;&gt;&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这种ES6的简洁形式,失去了函数本身的词法标识符,就不能递归调用自身了。会报ReferenceError错误。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;calc(y,&nbsp;x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;y&nbsp;-&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;} })</pre><p>这段ES6的代码会被解释成:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;result&nbsp;=&nbsp;run({ &nbsp;&nbsp;&nbsp;&nbsp;calc:&nbsp;function&nbsp;(x,&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(x&nbsp;&gt;&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这时候calc作为属性就不能这样使用了。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;calc(y,&nbsp;x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;y&nbsp;-&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;} })</pre><p>所以对于简洁方法应该只在不需要它们执行递归或者事件绑定/解绑定的时候使用。否则的话,还是按照老式的calc:function calc(...)方法来定义吧。</p><h3>6.3 Getter/Setter</h3><p cid="n223" mdtype="paragraph">曾经的getter和setter的写法:</p><pre class="prism-highlight prism-language-javascript">//&nbsp;&nbsp;曾经的getter&nbsp;setter let&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;10, } Object.defineProperty(obj,&nbsp;&#39;id&#39;,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this._id&nbsp;++; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set:&nbsp;function&nbsp;(val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._id&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;} }) console.log(obj.id);&nbsp;//&nbsp;NaN&nbsp;&nbsp;&nbsp;undefined++&nbsp;=&gt;&nbsp;NaN obj.id&nbsp;=&nbsp;12; console.log(obj.id);&nbsp;//&nbsp;12 console.log(obj.id);&nbsp;//&nbsp;13 console.log(obj.id);&nbsp;//&nbsp;14</pre><p>简写形式:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;10, &nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;id()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this._id++; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;id(val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._id&nbsp;=&nbsp;val; &nbsp;&nbsp;&nbsp;&nbsp;} } console.log(obj.id);&nbsp;//&nbsp;NaN obj.id&nbsp;=&nbsp;12; console.log(obj.id);&nbsp;//&nbsp;12 console.log(obj.id);&nbsp;//&nbsp;13 console.log(obj.id);&nbsp;//&nbsp;14</pre><h3>7、插入字符串字面量(模板字面量)</h3><p cid="n230" mdtype="paragraph">使用`作为界定符,这样的字符串字面值支持嵌入基本的字符串插入表达式,会被自动解析和求值。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;name&nbsp;=&nbsp;&#39;诸葛亮&#39;; //&nbsp;用``来包围,会被解释为一个字符串字面量,其中任何${}形式的表达式都会被立即在线解析求值。 //&nbsp;这种形式的解析求值就是插入(比模板要精确一些) let&nbsp;greeting&nbsp;=&nbsp;`Hello,${name}`; console.log(greeting)</pre><p>插入字符串字面量的一个优点就是可以分散在多行:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;name&nbsp;=&nbsp;&#39;诸葛亮&#39;; //&nbsp;用``来包围,会被解释为一个字符串字面量,其中任何${}形式的表达式都会被立即在线解析求值。 //&nbsp;这种形式的解析求值就是插入(比模板要精确一些) let&nbsp;greeting&nbsp;=&nbsp;`Hello,${name}, 你是我的偶像,羽扇纶巾,运筹帷幄之中,决胜千里之外,鞠躬尽瘁,死而后已!`; console.log(greeting)</pre><h3>7.1 插入表达式</h3><p cid="n237" mdtype="paragraph">在${...}内可以出现任何合法的表达式,包括函数调用、在线函数表达式调用、设置其它插入字符串字面量</p><pre class="prism-highlight prism-language-javascript">function&nbsp;getUpper(str){ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str.toUpperCase(); } let&nbsp;name&nbsp;=&nbsp;&#39;daisy&#39;; let&nbsp;str&nbsp;=&nbsp;`Hello,${getUpper(name)}`; console.log(str)</pre><h2>8、箭头函数</h2><p cid="n243" mdtype="paragraph">理解使用普通函数基于this带来的困扰,这是新的ES6箭头函数=&gt;特性引入的主要动因。</p><p cid="n245" mdtype="paragraph">箭头函数定义包括一个参数列表(零个或多个参数,如果参数个数不是一个的话要用(...)包围起来),然后是标识=&gt;,函数体放在最后。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(x,y){ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x&nbsp;+&nbsp;y; } //箭头函数 var&nbsp;foo&nbsp;=&nbsp;(x,y)&nbsp;=&gt;&nbsp;x&nbsp;+&nbsp;y;</pre><p cid="n248" mdtype="paragraph">只有在函数体的表达式个数多于1个,或者函数体包含非表达式语句的时候才需要用{...}包围。</p><p cid="n250" mdtype="paragraph">如果只有一个表达式,并且省略了包围的{...}的话,则意味着表达式前面有一个隐含的return。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;fn1&nbsp;=&nbsp;()&nbsp;=&gt;&nbsp;12; var&nbsp;fn2&nbsp;=&nbsp;x&nbsp;=&gt;&nbsp;x&nbsp;*&nbsp;12; var&nbsp;fn3&nbsp;=&nbsp;(x,y)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;z&nbsp;=&nbsp;x&nbsp;*&nbsp;2&nbsp;+&nbsp;y; &nbsp;&nbsp;&nbsp;&nbsp;y++; &nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;*=&nbsp;3; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(x&nbsp;+&nbsp;y&nbsp;+&nbsp;z)&nbsp;/&nbsp;2 }</pre><p cid="n253" mdtype="paragraph">箭头函数总是函数表达式,并不存在箭头函数声明。</p><p cid="n255" mdtype="paragraph">箭头函数是匿名函数表达式,它们没有用于递归或者事件绑定/解绑定的命名引用。</p><p cid="n257" mdtype="paragraph">箭头函数支持普通函数参数的所有功能,包括默认值、解构、rest参数等。</p><p cid="n259" mdtype="paragraph">箭头函数的简洁,使得它很适合这种情况:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;a&nbsp;=&nbsp;[1,2]; var&nbsp;result&nbsp;=&nbsp;a.map(v&nbsp;=&gt;&nbsp;v&nbsp;*&nbsp;2);</pre><p cid="n262" mdtype="paragraph">但是=&gt;箭头函数带来的可读性提升与被转化函数的长度负相关。</p><p cid="n264" mdtype="paragraph">函数越长,箭头函数带来的好处就越小,函数越短,箭头函数带来的好处就越大。</p><p cid="n266" mdtype="paragraph">所以,更合理的做法是只在确实需要简短的在线函数表达式的时候才采用箭头函数,而对于那些一般长度的函数则无需改变。</p><p cid="n268" mdtype="paragraph">不只是更短的语法,而是this。</p><p cid="n270" mdtype="paragraph">箭头函数的主要设计目的就是以特定的方式改变this的行为特性,解决this相关的一个特殊而又常见的痛点。</p><pre class="prism-highlight prism-language-javascript">const&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;&#39;诸葛亮&#39;, &nbsp;&nbsp;&nbsp;&nbsp;fn()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this.name); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//针对定时器的this &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this.name); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;1000) &nbsp;&nbsp;&nbsp;&nbsp;} } obj.fn();</pre><pre class="prism-highlight prism-language-javascript">//&nbsp;点击按钮,每次加一个1 const&nbsp;oBtn&nbsp;=&nbsp;document.querySelector(&#39;button&#39;); var&nbsp;controller&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;makeRequest:&nbsp;function&nbsp;(num)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oBtn.innerText&nbsp;=&nbsp;num; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保存this对象 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_this&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oBtn.onclick&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当有点击事件的调试,让程序在这里进入调试 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;debugger; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(this);&nbsp;//oBtn &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;controller.makeRequest(num);&nbsp;//这种方式不安全,有可能对象和标识符的引用关系发生了变化。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;通过闭包访问外层函数的变量_this &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_this.makeRequest(num); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} } controller.makeRequest(10);</pre><p>在箭头函数内部,this绑定不是动态的,而是词法的。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;controller&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;makeRequest:&nbsp;function&nbsp;(num)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oBtn.innerText&nbsp;=&nbsp;num; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oBtn.onclick&nbsp;=&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;箭头函数内部的this指向外层环境的this。这是词法绑定,这时的this不是动态的。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.makeRequest(num); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} }</pre><p>如果想灵活运用this,就不要胡乱使用箭头函数,比如:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;firstName:&nbsp;&#39;诸葛&#39;, &nbsp;&nbsp;&nbsp;&nbsp;lastName:&nbsp;&#39;孔明&#39;, &nbsp;&nbsp;&nbsp;&nbsp;fullName()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.firstName&nbsp;+&nbsp;this.lastName; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;sayName()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;`Hi,&nbsp;my&nbsp;name&nbsp;is&nbsp;${this.fullName()}` &nbsp;&nbsp;&nbsp;&nbsp;} } console.log(window.obj.fullName()) console.log(window.obj.sayName())</pre><pre class="prism-highlight prism-language-javascript">var&nbsp;controller&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//箭头函数里面的this从包围的作用域中词法继承而来。外围的作用域是全局作用域。 &nbsp;&nbsp;&nbsp;&nbsp;makeRequest:&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this);//window &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.helper();&nbsp;//报错 &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;helper:&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this); &nbsp;&nbsp;&nbsp;&nbsp;} } //虽然是对象.方法的隐式this绑定方式,但是makeRequest方法是箭头函数,它里面的this不指向这个对象了。 controller.makeRequest();</pre><p cid="n285" mdtype="paragraph">如果有一个简短单句在线函数表达式,其中唯一的语句是return某个计算出的值,且这个函数内部没有this引用,且没有自身引用(递归、事件绑定/解绑定),且不会要求函数执行这些,那么可以安全地把它重构成箭头函数。</p><p cid="n287" mdtype="paragraph">如果有一个内层函数表达式,依赖于在包含它的函数中调用var _this = this或者.bind(this)来确保适当的this绑定,那么这个内层函数表达式应该可以安全地转换为箭头函数。</p><p cid="n289" mdtype="paragraph">如果内层函数表达式依赖于封装函数中某种像var args = Array.prototype.slice.call(arguments)来保证arguments的词法复制,那么这个内层函数可以安全转成箭头函数。</p><p cid="n291" mdtype="paragraph">所有的其它情况,函数声明、较长的多语句函数表达式、需要词法名称标识符(递归)的函数,以及任何不符合以上几点特征的函数,一般都应该避免箭头函数语句。</p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/342.html" rel="nofollow" target="_blank">继续阅读《 JavaScript(ES6)的常用特性!(上)》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-319.html">ES6</a>, rel="nofollow" rel="nofollow" | <a href="http://www.mrszhao.com/post/342.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/342.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/343.html" rel="nofollow" rel="nofollow">用ES6写了一个todos,本地任务清单!</a> (2023-07-22) </li><li><a href="http://www.mrszhao.com/post/341.html" rel="nofollow">JavaScript(ES6)的常用特性!(下)</a> (2023-07-20) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Tue, 18 Jul 2023 17:38:17 +0800一半设计一半前端http://www.mrszhao.com/post/340.html<p>现在都是框架和组件库的天下,很多学生一上来就说要学框架,对于原生代码嗤之以鼻,觉得都是上古时期的内容,枯燥难懂,效率低下,哪有框架用起来直接起飞。</p><p>现在前端这个岗位在2023年仿佛冰冻了一样,这段时间整理以前的资料,有时候也觉得干嘛不直接整理自动化构建和框架的内容,还把几年前的老内容放上来。</p><p>也许只是个情怀吧,毕竟自己在这上面走了很久的路,算是鞭尸了……</p><h2>1、对象的属性和方法</h2><p cid="n41" mdtype="paragraph">如果访问的对象属性是一个函数,大家喜欢使用不一样的叫法以作区分。由于函数很容易被认为是属于某个对象,于是把这种函数称为“方法”。</p><p cid="n43" mdtype="paragraph">从技术角度来说,函数永远不会“属于”一个对象,所以把对象内部引用的函数称为对象的方法有点不妥。</p><p cid="n45" mdtype="paragraph">虽然函数具有this引用,有时候这些this确实会指向调函位置的对象引用。但是这种用法从本质上并没有把一个函数变成一个对象的“方法”,因为this是在运行时根据调用位置动态绑定的,所以函数和对象的关系最多也只能说是间接关系。</p><p cid="n47" mdtype="paragraph">无论对象访问属性返回什么值,每次访问对象的属性就是属性访问,如果属性访问返回的是一个函数,那它也并不是对象的一个“方法”。属性访问返回的函数和其它函数没有任何区别(除了可能发生的隐式绑定this)。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;foo&#39;); } var&nbsp;someFoo&nbsp;=&nbsp;foo; var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;someFoo:foo } foo;&nbsp;//&nbsp;function&nbsp;foo(){...} someFoo;&nbsp;//function&nbsp;foo(){...} obj.someFoo;&nbsp;//function&nbsp;foo(){...}</pre><p cid="n50" mdtype="paragraph">someFoo和obj.someFoo只是对于同一个函数的不同引用,并不能说明这个函数是特别的或者“属性”某个对象。</p><p cid="n52" mdtype="paragraph">如果foo()定义时内部有一个this引用,那这两个函数引用的唯一区别就是obj.someFoo中的this会被隐式绑定到一个对象。</p><p cid="n54" mdtype="paragraph">即使在对象中声明一个函数表达式,这个函数也不会“属性”这个对象,它们只是对于相同函数对象的多个引用。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myobj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;foo:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;foo&#39;); &nbsp;&nbsp;&nbsp;&nbsp;} } var&nbsp;someFoo&nbsp;=&nbsp;myobj.foo; console.log(someFoo);&nbsp;//&nbsp;function&nbsp;foo(...) console.log(myobj.foo);//&nbsp;function&nbsp;foo(...)</pre><h2>2、对象的复制</h2><h3>2.1 深复制</h3><pre class="prism-highlight prism-language-javascript">function&nbsp;anotherFunction(){ &nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;...&nbsp;*/ } var&nbsp;anotherObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;c:true } var&nbsp;anotherArr&nbsp;=&nbsp;[]; var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;b:anotherObj,&nbsp;//&nbsp;引用,不是副本 &nbsp;&nbsp;&nbsp;&nbsp;c:anotherArr,&nbsp;//&nbsp;引用 &nbsp;&nbsp;&nbsp;&nbsp;d:anotherFunction&nbsp;//引用 } anotherArr.push(anotherObj,myObj);</pre><p cid="n60" mdtype="paragraph">对象之间互相引用,对于深复制来说,会由于循环引用导致死循环。</p><p cid="n62" mdtype="paragraph">对于JSON安全的对象来说,有一种巧妙的复制方法:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;newObj&nbsp;=&nbsp;JSON.parse(JSON.stringfy(someObj));</pre><p>这种方法需要保证对象是JSON安全的,所以只适用于部分情况。</p><h3>2.2 浅复制</h3><p cid="n68" mdtype="paragraph">ES6定义了Object.assign()方法来实现浅复制。</p><p cid="n70" mdtype="paragraph">该方法的第一个参数是目标对象,后面是一个或者多个源对象。它会遍历一个或多个源对象的所有可枚举(enumerable)的自有键并把它们复制(使用=操作符赋值)到目标对象,最后返回目标对象。</p><p cid="n72" mdtype="paragraph">就好像这样:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;anotherFunction(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//.. } var&nbsp;anotherObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;c:true } var&nbsp;anotherArr&nbsp;=&nbsp;[]; var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;b:anotherObj,&nbsp;//&nbsp;引用,不是副本 &nbsp;&nbsp;&nbsp;&nbsp;c:anotherArr,&nbsp;//&nbsp;引用 &nbsp;&nbsp;&nbsp;&nbsp;d:anotherFunction&nbsp;//引用 } anotherArr.push(anotherObj,myObj); var&nbsp;newObj&nbsp;=&nbsp;Object.assign({},myObj); console.log(newObj.a);&nbsp;&nbsp;&nbsp;//&nbsp;2 console.log(newObj.b&nbsp;===&nbsp;myObj.b);&nbsp;&nbsp;//true console.log(newObj.c&nbsp;===&nbsp;myObj.c);&nbsp;&nbsp;//true console.log(newObj.d&nbsp;===&nbsp;myObj.d);&nbsp;&nbsp;//true</pre><h2>3、属性描述符</h2><p cid="n76" mdtype="paragraph">在ES5之前,JavaScript语言本身并没有提供可以直接检测属性特性的方法,比如判断属性是否是只读。</p><p cid="n78" mdtype="paragraph">在ES5之后,所有的属性都具备了属性描述符。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } var&nbsp;result&nbsp;=&nbsp;Object.getOwnPropertyDescriptor(myObj,&#39;a&#39;); console.log(result);&nbsp;//{value:&nbsp;2,&nbsp;writable:&nbsp;true,&nbsp;enumerable:&nbsp;true,&nbsp;configurable:&nbsp;true}</pre><p cid="n81" mdtype="paragraph">这个普通的对象myObj的属性描述符不仅仅只有一个value值2,还包含另外三个特性:writable(可写)、enumerable(可枚举)、configurable(可配置)。</p><p cid="n83" mdtype="paragraph">在我们创建普通属性时属性描述符会使用默认值。就等于如下代码:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{}; Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:2, &nbsp;&nbsp;&nbsp;&nbsp;writable:true, &nbsp;&nbsp;&nbsp;&nbsp;configurable:true, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }); console.log(myObj.a);&nbsp;//&nbsp;2</pre><p>我们可以使用Object.defineProperty()来添加一个新属性,或者修改一个已有属性(如果这个属性是configurable)并对特性进行配置。</p><h3>3.1 writable</h3><p cid="n89" mdtype="paragraph">writable决定是否可以修改属性的值。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{}; Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:2, &nbsp;&nbsp;&nbsp;&nbsp;writable:false,&nbsp;//不可写 &nbsp;&nbsp;&nbsp;&nbsp;configurable:true, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }); console.log(myObj.a);&nbsp;//&nbsp;2 myObj.a&nbsp;=&nbsp;3; console.log(myObj.a);&nbsp;//&nbsp;2</pre><h3>3.2 configurable</h3><p cid="n93" mdtype="paragraph">只要属性是可以配置的,就可以使用defineProperty()方法来修改属性描述符。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; myObj.a&nbsp;=&nbsp;3; console.log(myObj.a);//3 Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:4, &nbsp;&nbsp;&nbsp;&nbsp;writable:true,&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;configurable:false,&nbsp;//不可配置 &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }); console.log(myObj.a);&nbsp;//&nbsp;4 myObj.a&nbsp;=&nbsp;5; console.log(myObj.a);&nbsp;//&nbsp;5 Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:6, &nbsp;&nbsp;&nbsp;&nbsp;writable:true, &nbsp;&nbsp;&nbsp;&nbsp;configurable:true, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true })&nbsp;&nbsp;//Uncaught&nbsp;TypeError:&nbsp;Cannot&nbsp;redefine&nbsp;property:&nbsp;a</pre><p cid="n96" mdtype="paragraph">尝试修改一个不可配置的属性描述符会出错。</p><p cid="n98" mdtype="paragraph">把configurable修改成false是单向操作,无法撤销!!</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; myObj.a&nbsp;=&nbsp;3; console.log(myObj.a);//3 Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:4, &nbsp;&nbsp;&nbsp;&nbsp;writable:true,&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;configurable:false,&nbsp;//不可配置 &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }); console.log(myObj.a);&nbsp;//&nbsp;4 myObj.a&nbsp;=&nbsp;5; console.log(myObj.a);&nbsp;//&nbsp;5 Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:6, &nbsp;&nbsp;&nbsp;&nbsp;writable:false,&nbsp;&nbsp;//&nbsp;即使不可配置,还是可以把writable的状态由true改成false,但是无法由false改成true。 &nbsp;&nbsp;&nbsp;&nbsp;configurable:false,&nbsp;//不可配置 &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true })&nbsp;&nbsp; console.log(myObj.a);&nbsp;//&nbsp;6 myObj.a&nbsp;=&nbsp;7;&nbsp;//不可再修改 console.log(myObj.a);&nbsp;//&nbsp;6</pre><p>configurable:false还会禁止删除这个属性:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } console.log(myObj.a);&nbsp;//&nbsp;2 delete&nbsp;myObj.a; console.log(myObj.a);&nbsp;//&nbsp;undefined Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:3, &nbsp;&nbsp;&nbsp;&nbsp;writable:true, &nbsp;&nbsp;&nbsp;&nbsp;configurable:false, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }); console.log(myObj.a);&nbsp;//&nbsp;3 delete&nbsp;myObj.a;&nbsp;//失效了,因为属性是不可配置的。 console.log(myObj.a);&nbsp;//&nbsp;3</pre><p>delete只用来删除对象的可删除的属性。如果对象的某个属性是某个对象/函数的最后一个引用者,当delete这个属性之后,这个未引用的对象/函数就可以被垃圾回收。</p><h3>3.3 enumerable</h3><p cid="n107" mdtype="paragraph">这个属性描述符控制的是属性是否会出现在对象的属性枚举中。</p><p cid="n109" mdtype="paragraph">比如说for...in循环,如果把enumerable设置为false,这个属性就不会出现在枚举中,虽然仍然可以正常访问它。</p><p cid="n111" mdtype="paragraph">在谷歌调试工具中,不可枚举的属性是淡紫红色,可枚举的属性是深紫红色的。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{}; Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:2, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true&nbsp;//让a像普通属性一样可以枚举 }) Object.defineProperty(myObj,&#39;b&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:3, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:false,&nbsp;//&nbsp;让b不可枚举 }) //可访问 console.log(myObj.b);&nbsp;//&nbsp;3 //b这个属性在myObj对象中是否存在 console.log(&#39;b&#39;&nbsp;in&nbsp;myObj);&nbsp;//&nbsp;true //检测b这个属性是不是myObj自身的属性,而不是继承的属性 console.log(myObj.hasOwnProperty(&#39;b&#39;));&nbsp;//&nbsp;true for(var&nbsp;attr&nbsp;in&nbsp;myObj){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(attr,myObj[attr]);&nbsp;//&nbsp;a&nbsp;2&nbsp;,b没有被遍历出来 &nbsp;&nbsp;&nbsp;&nbsp;}</pre><p cid="n114" mdtype="paragraph">myObj.b可以被访问,确实存在,但是不会出现在for...in循环中,因为只有可枚举的属性才能出现在对象属性的遍历中。</p><p cid="n116" mdtype="paragraph">还有一些方法可以区分属性是否可枚举:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{}; Object.defineProperty(myObj,&#39;a&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:2, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true, }) Object.defineProperty(myObj,&#39;b&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;value:3, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:false, }) console.log(myObj); //&nbsp;propertyIsEnumerable()检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足enumerable:true console.log(myObj.propertyIsEnumerable(&#39;a&#39;));&nbsp;//&nbsp;true console.log(myObj.propertyIsEnumerable(&#39;b&#39;));&nbsp;//&nbsp;false //返回所有可枚举的属性的数组。只查找对象直接包含的属性,不查找原型链。 console.log(Object.keys(myObj));&nbsp;//[&#39;a&#39;] //返回一个数组,包含所有属性,无论是否可枚举。只查找对象直接包含的属性,不查找原型链。 console.log(Object.getOwnPropertyNames(myObj));&nbsp;//[&#39;a&#39;,&nbsp;&#39;b&#39;]</pre><h2>4、遍历</h2><p cid="n122" mdtype="paragraph">Object.keys(obj)可以返回obj对象自身可遍历的属性的数组。</p><p cid="n124" mdtype="paragraph">Object.getOwnPropertyNames(obj) 可以返回对象自身所有属性,包括不可遍历的属性,也是返回数组。</p><p cid="n126" mdtype="paragraph">也可以用for循环去遍历对象属性。</p><p cid="n128" mdtype="paragraph">for...in可以遍历对象的可枚举属性(包括prototype原型链),无法直接获取属性值,需要手动获取属性值。</p><h3>4.1 for...in</h3><p cid="n131" mdtype="paragraph">对于数组来说,使用标准的for循环来遍历值:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;arr&nbsp;=&nbsp;[1,2,3]; for(let&nbsp;i&nbsp;=&nbsp;0;i&nbsp;&lt;&nbsp;arr.length;&nbsp;i++){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(arr[i]); }</pre><p cid="n134" mdtype="paragraph">ES5中增加了一些数组的辅助迭代器,包括forEach()、every()、some()、map()、filter()、reduce()等。每种辅助迭代器都可以接受一个回调函数并把它应用到数组的每个元素上,唯一的区别就是它们对于回调函数返回值的处理方式不同。</p><p cid="n136" mdtype="paragraph">forEach()会遍历数组中的所有值并忽略回调函数的返回值。</p><p cid="n138" mdtype="paragraph">every()会一直运行直到回调函数返回false。</p><p cid="n140" mdtype="paragraph">some()会一直运行直到回调函数返回true。</p><p cid="n142" mdtype="paragraph">不要用for...in遍历数组,因为它不仅遍历数字索引,还会遍历出数组的其它属性。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;arr&nbsp;=&nbsp;[1,2,3]; arr.name&nbsp;=&nbsp;&#39;myArr&#39;; arr.id&nbsp;=&nbsp;&#39;001&#39;; for(let&nbsp;attr&nbsp;in&nbsp;arr){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(attr);//&#39;0&#39;&nbsp;&#39;1&#39;&nbsp;&#39;2&#39;&nbsp;&#39;name&#39;&nbsp;&#39;id&#39; }</pre><p cid="n145" mdtype="paragraph">用for循环或者forEach()这种迭代器,遍历数组下标时采用的是数字顺序,但是遍历对象属性时的顺序是不确定的。在不同的JavaScript引擎中可能不一样。</p><p cid="n147" mdtype="paragraph">因此,在任何不同的环境中需要保证一致性时,一定不要相信任何观察到的属性的顺序,它们是不可靠的。</p><h3>4.2 for...of</h3><p cid="n150" mdtype="paragraph">ES6增加了一种用来遍历数组的for...of循环语句,可以直接遍历值而不是数组的下标(或者对象的属性,如果对象本身定义了迭代器的话也可以遍历对象)。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;arr&nbsp;=&nbsp;[1,2,3]; for(let&nbsp;val&nbsp;of&nbsp;arr){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(val); }</pre><p cid="n153" mdtype="paragraph">for...of循环首先会向被访问的对象请求一个迭代器对象,然后通过调用迭代器对象的next()方法来遍历所有返回值。</p><p cid="n155" mdtype="paragraph">数组有内置的@@iterator,因此for...of可以直接应用在数组上。</p><p cid="n157" mdtype="paragraph">使用内置的@@iterator来手动遍历数组,看看它是如何工作的:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;arr&nbsp;=&nbsp;[1,2,3]; //数组的实例有这个属性:Symbol(Symbol.iterator):f&nbsp;values() let&nbsp;it&nbsp;=&nbsp;arr[Symbol.iterator](); console.log(it.next());&nbsp;//&nbsp;{value:&nbsp;1,&nbsp;done:&nbsp;false} console.log(it.next());&nbsp;//&nbsp;{value:&nbsp;2,&nbsp;done:&nbsp;false} console.log(it.next());&nbsp;//&nbsp;{value:&nbsp;3,&nbsp;done:&nbsp;false} console.log(it.next());&nbsp;//&nbsp;{value:&nbsp;undefined,&nbsp;done:&nbsp;true}</pre><p cid="n160" mdtype="paragraph">使用ES6中的符号Symbol.iterator来获取对象的@@iterator内部属性,引用类似iterator这种特殊的属性时要使用Symbol符号名。</p><p cid="n162" mdtype="paragraph">@@iterator本身并不是一个迭代器对象,而是一个返回迭代器对象的函数。函数执行之后,返回的才是迭代器对象。</p><p cid="n164" mdtype="paragraph">然后调用迭代器对象的next()方法会返回{value:..,done:..}的值,value是当前遍历的值,done是一个布尔值,表示是否还有可以遍历的值。</p><p cid="n166" mdtype="paragraph">和数组不同,普通的对象没有内置的@@iterator,所以无法自动完成for...of遍历,主要是为了避免影响未来的对象类型。</p><p cid="n168" mdtype="paragraph">可以为任何想遍历的对象定义@@iterator。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2, &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;3 } Object.defineProperty(myObj,&nbsp;Symbol.iterator,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//这种属性不需要被枚举 &nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;//设置该迭代器的值是一个函数 &nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;o&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;idx&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//返回所有可枚举的自身属性的数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;ks&nbsp;=&nbsp;Object.keys(o); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//迭代器函数执行之后返回一个对象 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//对象里面包含一个next函数,函数返回一个对象 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里构成了闭包 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;o[ks[idx++]], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done:&nbsp;(idx&nbsp;&gt;&nbsp;ks.length) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;} }); //手动遍历对象 let&nbsp;it&nbsp;=&nbsp;myObj[Symbol.iterator](); console.log(it.next());//{value:&nbsp;2,&nbsp;done:&nbsp;false} console.log(it.next());//{value:&nbsp;3,&nbsp;done:&nbsp;false} console.log(it.next());//{value:&nbsp;undefined,&nbsp;done:&nbsp;true} //用for...of遍历对象 for(let&nbsp;val&nbsp;of&nbsp;myObj){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(val); }</pre><p>定义一个“无限”迭代器,它永远不会“结束”并且总会返回一个新值(随机数、递增数、唯一标识符等等)。</p><pre class="prism-highlight prism-language-javascript">//&nbsp;无限迭代器 let&nbsp;randoms&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;[Symbol.iterator]:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{value:Math.random()}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;} } let&nbsp;pool&nbsp;=&nbsp;[]; for(let&nbsp;val&nbsp;of&nbsp;randoms){ &nbsp;&nbsp;&nbsp;&nbsp;pool.push(val); &nbsp;&nbsp;&nbsp;&nbsp;//防止无限运行 &nbsp;&nbsp;&nbsp;&nbsp;if(pool.length&nbsp;===&nbsp;100)&nbsp;break; } console.log(pool) //简写形式 let&nbsp;nums&nbsp;=&nbsp;[]; for(;;){ &nbsp;&nbsp;&nbsp;&nbsp;nums.push(Math.random()); &nbsp;&nbsp;&nbsp;&nbsp;if(nums.length&nbsp;==&nbsp;100){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;} } console.log(nums);</pre><h2>5、[[Get]]和[[Put]]</h2><h3>5.1 [[Get]]</h3><p cid="n178" mdtype="paragraph">属性访问在实现时有一个微妙却非常重要的细节:</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } console.log(myObj.a);</pre><p cid="n181" mdtype="paragraph">这是一次属性的访问,但是并不仅仅是在myObj中查找名字为a的属性。</p><p cid="n183" mdtype="paragraph">myObj.a在myObj上实际上是实现了[[Get]]操作。对象默认的内置[[Get]]操作首先在对象中查找是否有相同名称的属性,如果找到就会返回这个属性的值。</p><p cid="n185" mdtype="paragraph">如果没有找到名称相同的属性,按照[[Get]]算法的定义会执行另外一种非常重要的行为。就是遍历可能存在的[[Prototype]]原型链。</p><p cid="n187" mdtype="paragraph">如果无论如何都没有找到名称相同的属性,那[[Get]]操作会返回值undefined。</p><p cid="n189" mdtype="paragraph">这种方法和访问变量不一样。如果引用了一个当前词法作用域中不存在的变量,并不会像对象属性一样返回undefined,而是会抛出一个ReferenceError异常。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:undefined } console.log(myObj.a);&nbsp;//undefined console.log(myObj.b);&nbsp;//undefined console.log(&#39;a&#39;&nbsp;in&nbsp;myObj);&nbsp;//&nbsp;true console.log(&#39;b&#39;&nbsp;in&nbsp;myObj);&nbsp;//false console.log(myObj.hasOwnProperty(&#39;a&#39;));&nbsp;//&nbsp;true console.log(myObj.hasOwnProperty(&#39;b&#39;));&nbsp;//false</pre><p>in操作符会检查属性是否在对象及其[[Prototype]]原型链上。hasOwnProperty()只会检查属性是否在myObj对象上,不会检查[[Prototype]]原型链。</p><h3>5.2 [[Put]]</h3><p cid="n195" mdtype="paragraph">既然有获取属性值的[[Get]]操作,就有对应的[[Put]]操作。</p><p cid="n197" mdtype="paragraph">给对象的属性赋值会触发[[Put]]操作,实际的行为取决于许多因素,包括对象中是否已经存在这个属性。</p><p cid="n199" mdtype="paragraph">如果已经存在这个属性,[[Put]]算法大致会检查下面这些内容:</p><p cid="n201" mdtype="paragraph">1、属性是否是访问描述符?如果是并且存在setter就调用setter。</p><p cid="n203" mdtype="paragraph">2、属性的数据描述符中writable是否为false?如果是,在非严格模式下写入失败,严格模式下抛出异常。</p><p cid="n205" mdtype="paragraph">3、如果都不是,将该值设置为属性的值。</p><p cid="n207" mdtype="paragraph">如果对象中不存在这个属性,[[Put]]操作会更加复杂。</p><h2>6、Getter和Setter</h2><p cid="n212" mdtype="paragraph">对象默认的[[Get]]和[[Put]]操作分别可以控制对象的属性值的获取和设置。</p><p cid="n214" mdtype="paragraph">在ES5中可以适用getter和setter改写默认操作。getter是一个隐藏函数,会在获取属性值时调用。setter也是一个隐藏函数,会在设置属性值时调用。</p><p cid="n216" mdtype="paragraph">当为一个属性定义getter、setter时,这个属性会被定义为&quot;访问描述符&quot;。对于访问描述符来说,JavaScript会忽略它们的value和writable特性,取而代之的是关心set和get(还有configurable和enumerable特性)。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//给属性a定义一个getter &nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;a(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;} } Object.defineProperty(myObj,&#39;b&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;//给b定义一个getter &nbsp;&nbsp;&nbsp;&nbsp;get:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.a&nbsp;*&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;//属性b可以枚举 &nbsp;&nbsp;&nbsp;&nbsp;enumerable:true }) console.log(myObj.a);&nbsp;//&nbsp;2 console.log(myObj.b);&nbsp;//&nbsp;4</pre><p>不管是对象文字语法中的get a(){},还是defineProperty()中的显式定义,二者都会在对象中创建一个不包含值的属性。对于这个属性的访问会自动调用一个隐藏函数,它的返回值会被当作属性访问的返回值。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//默认的[[Get]]操作会被getter覆盖 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a:22, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//给属性a定义一个getter &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;a(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;} &nbsp;Object.defineProperty(myObj,&#39;b&#39;,{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//给b定义一个getter &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get:function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.a&nbsp;*&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//属性b可以枚举 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:true &nbsp;}) console.log(myObj.a);&nbsp;//&nbsp;2 //只定义了getter,对属性a进行设置时set操作会忽略赋值操作 myObj.a&nbsp;=&nbsp;3; console.log(myObj.a);&nbsp;//&nbsp;2 console.log(myObj.b);&nbsp;//&nbsp;4</pre><p cid="n222" mdtype="paragraph">为了让属性更合理,还应当定义setter,setter会覆盖单个属性默认的[[Put]]赋值操作。</p><p cid="n224" mdtype="paragraph">通常来说getter和setter是成对出现的。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;myObj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;a()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//this._a,不能是this.a,否则会接着调用get,然后陷入死循环报错,超过堆栈大小范围。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this._a; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;a(val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._a&nbsp;=&nbsp;val&nbsp;*&nbsp;2; &nbsp;&nbsp;&nbsp;&nbsp;} }; myObj.a&nbsp;=&nbsp;2; console.log(myObj.a);</pre><h2>7、原型链</h2><h3>7.1[[Prototype]]</h3><p cid="n229" mdtype="paragraph">JavaScript中的对象有一个特殊的[[Prototype]]内置属性,其实就是对于其他对象的引用。</p><p cid="n231" mdtype="paragraph">几乎所有的对象在创建时[[Prototype]]属性都会被赋予一个非空的值,除了Object.create(null)。</p><p cid="n233" mdtype="paragraph">我们在访问对象的属性时:</p><pre class="prism-highlight prism-language-javascript">let&nbsp;myObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } myObject.a;//2</pre><p cid="n236" mdtype="paragraph">当试图访问对象的属性时会触发[[Get]]操作,对于默认的[[Get]]操作来说,第一步就是检查对象本身是否有这个属性, 如果有的话就使用它。</p><p cid="n238" mdtype="paragraph">如果a不在myObject中,就需要使用[[Prototype]]原型链了。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;anotherObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; //创建一个关联到anotherObject的对象 let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); console.log(myObject.a);&nbsp;//&nbsp;2</pre><p cid="n241" mdtype="paragraph">Object.create()会创建一个对象并把这个对象的[[Prototype]]关联到指定的对象。是ES5新增的函数。</p><p cid="n243" mdtype="paragraph">相当于如下代码:</p><pre class="prism-highlight prism-language-javascript">//polyfill //&nbsp;如果这个函数不存在 if(!Object.create){ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;创建一个函数 &nbsp;&nbsp;&nbsp;&nbsp;Object.create&nbsp;=&nbsp;function(o){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;创建一个构造函数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;F(){} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;把构造函数的prototype原型对象指向传递进来的o对象 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;F.prototype&nbsp;=&nbsp;o; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回构造函数的一个实例 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;F(); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre><p cid="n246" mdtype="paragraph">如果anotherObject也找不到a,并且[[Prototype]]原型链不为空null的话,就会继续查找下去。如果找完了整条原型链都没有,则会返回undefined.</p><p cid="n248" mdtype="paragraph">for...in遍历对象,任何可以通过 原型链访问到的可枚举的属性都会被遍历。使用in操作符来检查属性是否在对象中存在时,同样会检查对象的整条原型链。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;supperObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 }; //supperObject是anotherObject的原型 let&nbsp;anotherObject&nbsp;=&nbsp;Object.create(supperObject,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true &nbsp;&nbsp;&nbsp;&nbsp;} }); //anotherObject是myObject的原型对象 let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); myObject.c&nbsp;=&nbsp;4; for&nbsp;(let&nbsp;attr&nbsp;in&nbsp;myObject)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(attr);&nbsp;//&nbsp;c&nbsp;a&nbsp; } console.log(&#39;b&#39;&nbsp;in&nbsp;myObject);&nbsp;//&nbsp;true</pre><h3>7.2 Object.prototype</h3><p cid="n252" mdtype="paragraph">所有对象的[[Prototype]]链最终都会指向内置的Object.prototype。由于所有的对象都源于这个Object.prototype对象,所以它包含JavaScript中许多通用的功能。</p><p cid="n254" mdtype="paragraph">比如valueOf()、toString()、hasOwnProperty()等都是任何对象实例可以访问的方法。</p><p cid="n256" mdtype="paragraph">原型对象中的方法[[Prototype]]: Object 是所有实例可以访问的,constructor属性指向的构造函数下面的方法,比如constructor: ƒ&nbsp;Object() 构造函数下面的方法只有Object对象本身才能访问,实例不能访问。</p><h3>7.3 属性设置和屏蔽</h3><p cid="n259" mdtype="paragraph">给一个对象设置属性并不仅仅是添加一个新属性或者修改已有的属性值。</p><pre class="prism-highlight prism-language-javascript">myObject.b&nbsp;=&nbsp;4;</pre><p cid="n262" mdtype="paragraph">如果myObject对象中包含名为b的普通数据访问属性,这条赋值语句只会修改已有的属性值。</p><p cid="n264" mdtype="paragraph">如果b不是直接存在于myObject中,[[Prototype]]链就会被遍历,类似[[Get]]操作,如果原型链上找不到b,则把b直接添加到myObject上。</p><p cid="n266" mdtype="paragraph">如果b存在于原型链上层,赋值语句的行为就会有些 不同。</p><p cid="n268" mdtype="paragraph">如果属性名b即出现在myObject中,也出现在myObject的[[Prototype]]链上层,就会发生屏蔽。</p><p cid="n270" mdtype="paragraph">myObject中出现的b属性会屏蔽原型链上层的所有b属性,因为myObject.b总是会选择原型链中最底层的b属性。</p><p cid="n272" mdtype="paragraph">如果在[[Prototype]]链上层存在名为b的普通数据访问属性,并且没有被标记为只读(writable:false),那就会直接在myObject上添加一个名为b的新属性,它是屏蔽属性。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;supperObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 }; let&nbsp;anotherObject&nbsp;=&nbsp;Object.create(supperObject,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true &nbsp;&nbsp;&nbsp;&nbsp;} }); let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); myObject.b&nbsp;=&nbsp;4; console.log(myObject.b);&nbsp;//&nbsp;4</pre><p>如果在[[Prototype]]链上层存在名为b的普通数据访问属性,并且被标记为只读(writable:false),那么无法修改已有属性或者在myObject上创建屏蔽属性。这条赋值语句会被忽略,不会发生屏蔽。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;supperObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 }; let&nbsp;anotherObject&nbsp;=&nbsp;Object.create(supperObject,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true &nbsp;&nbsp;&nbsp;&nbsp;} }); let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); myObject.b&nbsp;=&nbsp;4; console.log(myObject.b);&nbsp;//&nbsp;3</pre><p>如果在[[Prototype]]链上层存在b,并且它是一个setter,那就一定会调用这个setter,b不会被添加到myObject上。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;supperObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 }; let&nbsp;anotherObject&nbsp;=&nbsp;Object.create(supperObject,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;} }); Object.defineProperty(anotherObject,&nbsp;&#39;b&#39;,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//_b避免直接使用b导致死循环&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this._b; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set:&nbsp;function&nbsp;(val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._b&nbsp;=&nbsp;val&nbsp;*&nbsp;3; &nbsp;&nbsp;&nbsp;&nbsp;} }) let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); myObject.b&nbsp;=&nbsp;4;&nbsp; console.log(myObject.b);&nbsp;//&nbsp;12</pre><p>上面的限制只存在于myObject.b = 4这种赋值语句中,使用Object.defineProperty()则不受限制。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;supperObject&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 }; let&nbsp;anotherObject&nbsp;=&nbsp;Object.create(supperObject,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;b:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;false, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;} }); Object.defineProperty(anotherObject,&nbsp;&#39;b&#39;,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;get:&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this._b; &nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;set:&nbsp;function&nbsp;(val)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._b&nbsp;=&nbsp;val&nbsp;*&nbsp;3; &nbsp;&nbsp;&nbsp;&nbsp;} }) let&nbsp;myObject&nbsp;=&nbsp;Object.create(anotherObject); myObject.b&nbsp;=&nbsp;4; console.log(myObject.b);&nbsp;//&nbsp;12 //这种方式则会产生屏蔽,不受writable:false和setter的影响。 Object.defineProperty(myObject,&nbsp;&#39;b&#39;,&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;5, &nbsp;&nbsp;&nbsp;&nbsp;writable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;enumerable:&nbsp;true, &nbsp;&nbsp;&nbsp;&nbsp;configurable:&nbsp;true }) console.log(myObject.b)&nbsp;//&nbsp;5</pre><p><br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/340.html" rel="nofollow" target="_blank">继续阅读《对象属性的访问、遍历、getter和setter等高级特性!》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-313.html">对象</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-314.html">writable</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-315.html">enumerable</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-316.html">configurable</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-317.html">getter</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-318.html">setter</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/340.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/340.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/235.html">JavaScript基础5:NaN和isNaN到底是啥?</a> (2019-07-12) </li><li><a href="http://www.mrszhao.com/post/251.html">JavaScript基础14:var、let、const的区别</a> (2019-08-16) </li><li><a href="http://www.mrszhao.com/post/127.html">导航栏页面跳转时,如何为当前页添加选中状态的样式?</a> rel="nofollow" (2017-08-21) </li><li><a href="http://www.mrszhao.com/post/342.html" rel="nofollow"> JavaScript(ES6)的常用特性!(上)</a> (2023-07-18) </li><li><a href="http://www.mrszhao.com/post/318.html">点击空白处隐藏某个元素最好的方法不是阻止冒泡</a> rel="nofollow" (2023-07-07) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Sun, 16 Jul 2023 16:37:19 +0800一半设计一半前端http://www.mrszhao.com/post/339.html<p>继续把数组后面迭代的方法用原型写出来……</p><h3>1、forEach</h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;forEach(回调函数) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:就是遍历数组的每一项,并且每一项都要执行一次回调函数的功能. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;不返回值,所以返回函数默认的undefined. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;遍历的是数组的快照,如果中途修改或者删除了数组,不会改变遍历的顺序,所以不要修改数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myForEach&nbsp;=&nbsp;function&nbsp;(callback)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arg2&nbsp;=&nbsp;arguments[1]&nbsp;||&nbsp;window; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;第一个参数必须是函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arr.length&nbsp;==&nbsp;0)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;arr.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callback.call(arg2,&nbsp;arr[i],&nbsp;i,&nbsp;arr); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>2、map<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;map(function(item,index){}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:遍历数组的每一项,每一项都要执行回调函数. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:返回一个新数组,数组的长度和原数组一样. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myMap&nbsp;=&nbsp;function&nbsp;(callback,&nbsp;scope)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;参数1必须是一个函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;result&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arr.length&nbsp;==&nbsp;0)&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scope&nbsp;=&nbsp;scope&nbsp;||&nbsp;window; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;arr.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(callback.call(scope,&nbsp;arr[i],&nbsp;i,&nbsp;arr)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>3、filter<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;filter(function(item,index){}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:对数组的每一项进行筛选,每一项都要执行回调函数,通过函数筛选成功的值,返回到新数组中. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回一个新数组,数组的长度可能比原数组要小. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myFilter&nbsp;=&nbsp;function&nbsp;(callback,&nbsp;scope)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;参数1必须是一个函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;result&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scope&nbsp;=&nbsp;scope&nbsp;||&nbsp;window; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(callback.call(scope,&nbsp;arr[i],&nbsp;i,&nbsp;arr))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(arr[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>4、every</h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;every(function(item,index){}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:每一项都要执行回调函数,通过了函数的条件,每一项都为true,才返回&nbsp;true,如果有一项为假,则返回false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:布尔值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myEvery&nbsp;=&nbsp;function&nbsp;(callback,&nbsp;scope)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;参数1必须是一个函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scope&nbsp;=&nbsp;scope&nbsp;||&nbsp;window; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果有一个不满足,返回false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!callback.call(scope,&nbsp;arr[i],&nbsp;i,&nbsp;arr))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>5、some<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;some(function(item,index){}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:数组的某一项通过了函数的条件判断,则返回true,如果都没有通过,才返回false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:布尔值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.mySome&nbsp;=&nbsp;function&nbsp;(callback,&nbsp;scope)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;参数1必须是一个函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scope&nbsp;=&nbsp;scope&nbsp;||&nbsp;window; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果有一个满足,返回true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(callback.call(scope,&nbsp;arr[i],&nbsp;i,&nbsp;arr))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>6、reduce<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;reduce(function(sum,i){},0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:累计 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myReduce&nbsp;=&nbsp;function&nbsp;(callback,&nbsp;init)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;callback&nbsp;!==&nbsp;&#39;function&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;参数1必须是一个函数&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果长度为0,又没有设置初始值,报错 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0&nbsp;&amp;&amp;&nbsp;init&nbsp;===&nbsp;undefined)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(&#39;数组为空时必须设置初始值&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果长度为0,返回初始值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;init; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;总的值默认为初始值,没有初始值,默认为0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;total&nbsp;=&nbsp;init&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;没有设置初始值的时候,total默认为第一个数组的值,选项从第二个开始遍历。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(init&nbsp;===&nbsp;undefined)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total&nbsp;=&nbsp;arr[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total&nbsp;=&nbsp;callback(total,&nbsp;arr[i],&nbsp;i,&nbsp;arr) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置了初始值,则从第一个项开始遍历 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total&nbsp;=&nbsp;callback(total,&nbsp;arr[i],&nbsp;i,&nbsp;arr) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;total; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>还有includes、find、findIndex等等新增的方法就不写了,差别不大,好吧,其实是我想偷懒了,累觉不爱……</p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/339.html" rel="nofollow" target="_blank">继续阅读《用原型重写数组迭代方法(下)》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-208.html">数组</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-291.html">原型</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-311.html">迭代</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-312.html">方法</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/339.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/339.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/238.html">JavaScript基础7:数组Arrays常用的迭代方法</a> (2019-07-25) </li><li><a href="http://www.mrszhao.com/post/338.html" rel="nofollow">用原型重写数组基础方法(上)</a> rel="nofollow" (2023-07-13) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Sat, 15 Jul 2023 16:12:59 +0800一半设计一半前端http://www.mrszhao.com/post/338.html<p>通过用原型的方式重写数组的方法,加深对数组和原型的掌握。</p><p>先从最简单的开始:<br/></p><h3>1、push</h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;push(val1,val2,...) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1、数组的方法,只能数组对象调用 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2、功能是在数组的尾部添加数据 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3、可以添加多个数据,逗号隔开 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;4、返回的是数组的length值,是数字类型 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;5、改变了原始数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myPush&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保存长度,减少对数组长度的反复查找,节约性能 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;arguments.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[len++]&nbsp;=&nbsp;arguments[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>2、pop<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;pop() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1、功能是:删除数组尾部的一个值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2、返回被删除的数据 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3、改变的是原数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myPop&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;必须要判断数组的长度,如果为0,直接返回undefined &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;lastItem&nbsp;=&nbsp;arr[len&nbsp;-&nbsp;1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数组的长度少一个1,就会直接删除最后一个值。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length--; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;lastItem; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>3、unshift<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;unshift(val,val,...)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;shift() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;在数组的头部添加数据和删除数据,是先后先出的模式。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myUnshift&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;argL&nbsp;=&nbsp;arguments.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;加入参数长度为0,返回数组的长度,不用操作后面 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(argL&nbsp;==&nbsp;0)&nbsp;return&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;先把原始数组的值往右移动参数的个数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[argL&nbsp;+&nbsp;i]&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;再把参数的值一一对应到数组中 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;argL;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i]&nbsp;=&nbsp;arguments[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;len++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>4、shift</h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;shift &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myShift&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果数组长度为0,则不执行,返回undefined。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;取出第一个值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;firstItem&nbsp;=&nbsp;arr[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;遍历后面所有值,往前移动一个位置。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i&nbsp;-&nbsp;1]&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;数组长度减1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length--; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;返回第一个值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;firstItem; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>5、join<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;join(分隔符) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能是:把数组的值转成字符串,用分隔符拼接。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;参数是可以缺省,默认是逗号隔开。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果是空字符串,直接把数组拼接成字符串 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回的是字符串 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myJoin&nbsp;=&nbsp;function&nbsp;(sep)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(sep&nbsp;||&nbsp;sep&nbsp;===&nbsp;&#39;&#39;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sep&nbsp;=&nbsp;sep; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sep&nbsp;=&nbsp;&#39;,&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;str&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;str; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(i&nbsp;&lt;&nbsp;len&nbsp;-&nbsp;1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str&nbsp;+=&nbsp;arr[i]&nbsp;+&nbsp;sep; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str&nbsp;+=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>6、concat<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;concat(val,val,...) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能是:把多个值合并在新数组中返回 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;参数:任意数据类型的值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:一个新数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;不改变原数组,返回新数组,但是是浅拷贝 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;能够拆开第一层数组。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myConcat&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;argsL&nbsp;=&nbsp;arguments.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;newArr&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;先把原数组遍历出来,把值赋值给新数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr[i]&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果参数长度为0,返回新数组。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(argsL&nbsp;==&nbsp;0)&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;遍历参数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;argsL;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果参数中有数组,则解开第一层数组的值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arguments[i]&nbsp;instanceof&nbsp;Array)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;arguments[i].length;&nbsp;j++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr[len++]&nbsp;=&nbsp;arguments[i][j]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr[len++]&nbsp;=&nbsp;arguments[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>7、slice<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;slice(start,end) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:截取数组的一段值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;参数:start表示开始的索引值,end表示结束的索引值,不包括结束的索引值。[start,end),可以为负值。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:返回一个截取出来的新数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;参数缺省,表示把所有的值都截取出来,返回到一个新数组,可以用来对数组进行浅拷贝。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;没有修改原数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;slice &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.mySlice&nbsp;=&nbsp;function&nbsp;(start,&nbsp;end)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;argsL&nbsp;=&nbsp;arguments.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;newArr&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果数值长度为0,返回新的空数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数缺省,默认值为0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;arguments[0]&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第二个参数缺省,默认值为数组的长度 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;=&nbsp;arguments[1]&nbsp;||&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数小于0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arguments[0]&nbsp;&lt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;len&nbsp;+&nbsp;arguments[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第二个参数小于0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arguments[1]&nbsp;&lt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;=&nbsp;len&nbsp;+&nbsp;arguments[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数大于等于第二个参数,返回新的空数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(start&nbsp;&gt;=&nbsp;end)&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;遍历start到end之间的值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&lt;&nbsp;end;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr.push(arr[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>8、splice<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;splice(index,howmany,val,val,....) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:对数组任意位置进行增加,删除,修改值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;修改原数组,返回被删除的值构成的新数组,如果没有删除值,返回空数组。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;可以添加或者替换数组的一部分 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.mySplice&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;argsL&nbsp;=&nbsp;arguments.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;newArr&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果没有参数,返回空数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(argsL&nbsp;==&nbsp;0)&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;第一个参数作为起始位置 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;start&nbsp;=&nbsp;arguments[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数小于0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(start&nbsp;&lt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;start&nbsp;+&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数不是数字,或者是NaN,默认0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;start&nbsp;!==&nbsp;&#39;number&#39;&nbsp;||&nbsp;start&nbsp;!==&nbsp;start&nbsp;||&nbsp;start&nbsp;&lt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第一个参数大于数组的最大下标值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(start&nbsp;&gt;&nbsp;len&nbsp;-&nbsp;1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;len; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;第二个参数作为删除的个数。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;let&nbsp;howmany&nbsp;=&nbsp;(arguments[1]&nbsp;!==&nbsp;undefined)&nbsp;?&nbsp;arguments[1]&nbsp;:&nbsp;len&nbsp;-&nbsp;start; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;howmany&nbsp;=&nbsp;arguments[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果没有传参第二个参数,默认为删除起始位置后面的所有值。如果为0,不删除。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这里不要用短路||运算符,否则参数为0的时候,也会返回后面len&nbsp;-&nbsp;start的值。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arguments[1]&nbsp;===&nbsp;undefined)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;howmany&nbsp;=&nbsp;len&nbsp;-&nbsp;start; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果第二个参数不是数字或者是NaN,默认为0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof&nbsp;howmany&nbsp;!==&nbsp;&#39;number&#39;&nbsp;||&nbsp;howmany&nbsp;!==&nbsp;howmany)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;howmany&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果被删除的个数大于了可以删除的个数,则只能截取到末尾。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(howmany&nbsp;&gt;&nbsp;len&nbsp;-&nbsp;start)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;howmany&nbsp;=&nbsp;len&nbsp;-&nbsp;start; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;把要删除的值添加到新数组中 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&lt;&nbsp;start&nbsp;+&nbsp;howmany;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr.push(arr[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取第三个以后的参数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;addArgs&nbsp;=&nbsp;Array.prototype.slice.call(arguments,&nbsp;2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;要添加的参数的长度 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;addArgsL&nbsp;=&nbsp;addArgs.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果有参数,则根据howmany来看,是添加还是替换。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果是插入或替换,只需用替换元素长度减去删除的个数即可得出向后移动的位置数,把插入替换的元素在移动出空缺的位置上对号入座; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(addArgsL&nbsp;&gt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;添加的个数和删除的个数的差值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;num&nbsp;=&nbsp;addArgsL&nbsp;-&nbsp;howmany; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果添加的个数大于删除的个数,则是从后面扩展数组。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(num&nbsp;&gt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;必须是从后面往前面遍历,否则前面的数会把后面的数覆盖 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;len&nbsp;-&nbsp;1;&nbsp;i&nbsp;&gt;=&nbsp;start;&nbsp;i--)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i&nbsp;+&nbsp;num]&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果添加的个数少于要删除的个数,则从起始位置加上删除个数的位置开始往前移动 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start&nbsp;+&nbsp;howmany;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i&nbsp;+&nbsp;num]&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;改变数组的长度,如果添加的参数少于删除的个数,数组要把后面多余的数删除。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数组原始的长度加上添加和删除的差值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length&nbsp;=&nbsp;len&nbsp;+&nbsp;num; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(addArgsL,&nbsp;howmany,&nbsp;arr.length,&nbsp;start); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;再把要添加的数对应到相应的位置上。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;addArgsL;&nbsp;j++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[start++]&nbsp;=&nbsp;addArgs[j] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;没有要添加的参数,值直接删除。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i]&nbsp;=&nbsp;arr[i&nbsp;+&nbsp;howmany]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length&nbsp;=&nbsp;arr.length&nbsp;-&nbsp;howmany; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;newArr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>9、reverse<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;reverse() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:翻转数组的值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;没有参数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回原数组 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myReverse&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;arr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;centerpos&nbsp;=&nbsp;Math.floor(len&nbsp;/&nbsp;2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;temp&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;centerpos;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;=&nbsp;arr[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i]&nbsp;=&nbsp;arr[len&nbsp;-&nbsp;1&nbsp;-&nbsp;i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[len&nbsp;-&nbsp;1&nbsp;-&nbsp;i]&nbsp;=&nbsp;temp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;arr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>10、sort<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;sort &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;v8的sort源代码使用的是数组小于10,插入排序,大于10,快速排序,大于1000,插入和快排混合。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;https://zhuanlan.zhihu.com/p/33626637 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;https://zhuanlan.zhihu.com/p/24050357 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这里使用的是冒泡排序 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.mySort&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果没有传参数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;默认字符串排序 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!arguments[0])&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;arr.length&nbsp;-&nbsp;1;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;arr.length&nbsp;-&nbsp;1&nbsp;-&nbsp;i;&nbsp;j++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果是默认排序,则转成字符串,升序排列 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(String(arr[j])&nbsp;&gt;&nbsp;String(arr[j&nbsp;+&nbsp;1]))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;temp&nbsp;=&nbsp;arr[j&nbsp;+&nbsp;1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[j&nbsp;+&nbsp;1]&nbsp;=&nbsp;arr[j]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[j]&nbsp;=&nbsp;temp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;arr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;fn&nbsp;=&nbsp;arguments[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;arr.length&nbsp;-&nbsp;1;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;arr.length&nbsp;-&nbsp;1&nbsp;-&nbsp;i;&nbsp;j++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;调用比较函数,计算相邻两个数的差值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;result&nbsp;=&nbsp;fn(arr[j],&nbsp;arr[j&nbsp;+&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果差值大于0,则交换两个数的位置 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(result&nbsp;&gt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;temp&nbsp;=&nbsp;arr[j&nbsp;+&nbsp;1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[j&nbsp;+&nbsp;1]&nbsp;=&nbsp;arr[j]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[j]&nbsp;=&nbsp;temp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;arr; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>11、indexOf<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;indexOf(item,start) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能:查找数组里面是否有item这个项.可以指定从哪个索引位置开始查找,start缺省,表示0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回值:如果找到了,返回这个item项的索引值,没找到,返回-1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这个方法不能判断数组里面是否有NaN,因为NaN&nbsp;===&nbsp;NaN,返回false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myIndexOf&nbsp;=&nbsp;function&nbsp;(ele,&nbsp;start)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arr.length&nbsp;==&nbsp;0)&nbsp;return&nbsp;-1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;start&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;result&nbsp;=&nbsp;-1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&lt;&nbsp;arr.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果元素相等,返回第一个相等的元素的下标值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ele&nbsp;===&nbsp;arr[i])&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;i; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><h3>12、lastIndexOf<br/></h3><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;lastIndexOf(item,start) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;功能和indexOf()类似,只不过是从数组的右边往左边查找 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数组的元素的索引值是不变的,只是从右边往左边查找,返回的依然是值固定的索引值. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array.prototype.myLastIndexOf&nbsp;=&nbsp;function&nbsp;(ele,&nbsp;start)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;arr&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;arr.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(len&nbsp;==&nbsp;0)&nbsp;return&nbsp;-1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start&nbsp;=&nbsp;start&nbsp;||&nbsp;len&nbsp;-&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;result&nbsp;=&nbsp;-1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(let&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&gt;=&nbsp;0;&nbsp;i--)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果元素相等,返回第一个相等的元素的下标值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ele&nbsp;===&nbsp;arr[i])&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;i; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>写了好久终于把常规的数组方法写完了,还有后面迭代的方法没有……</p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/338.html" rel="nofollow" target="_blank">继续阅读《用原型重写数组基础方法(上)》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-208.html">数组</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-291.html">原型</a>,<a rel="nofollow" rel="nofollow" href="http://www.mrszhao.com/tags-207.html">数组方法</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/338.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/338.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/330.html">面向对象(构造函数、原型、实例、原型链的关系)</a> rel="nofollow" (2021-12-03) </li><li><a href="http://www.mrszhao.com/post/339.html" rel="nofollow">用原型重写数组迭代方法(下)</a> rel="nofollow" (2023-07-15) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Thu, 13 Jul 2023 15:46:32 +0800一半设计一半前端http://www.mrszhao.com/post/334.html<p>今天翻资料,发现一个还算完整的播放器万博manbext3.0首页登录,主要是练习H5提供的Audio API,结合jQuery+Ajax完成。</p><p><a href="http://www.mrszhao.com/zb_users/upload/2023/09/player/player.html" rel="nofollow" target="_blank" title="播放器audio API练习"><img src="http://www.mrszhao.com/zb_users/upload/2023/09/202309041693833117456761.jpg" title="1.jpg" alt="1.jpg"/></a></p><p>点击图片看效果。</p><p>功能:</p><p>1、默认不播放,点击播放按钮,播放音乐。</p><p>2、点击暂停按钮,暂停播放。</p><p>3、点击上一首,下一首播放音乐。</p><p>4、点击停止,进度条归零,停止播放音乐。</p><p>5、可以拖拉播放进度条。</p><p>6、点击列表可以切换音乐并播放。</p><p>7、播放完后自动播放下一首。</p><p>核心代码:</p><pre class="prism-highlight prism-language-javascript">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;ajax获取本地json数据 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$.get(&#39;data/music.json&#39;,&nbsp;function&nbsp;(data)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;musicList&nbsp;=&nbsp;data.music; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1、初始化界面 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;num&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化音乐和图片 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.playerImg&#39;).html(` &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;img&nbsp;src=&quot;${musicList[num].coverSrc}&quot;&nbsp;alt=&quot;&quot;&nbsp;width=&quot;150&quot;&nbsp;height=&quot;150&quot;&nbsp;id=&quot;cover&quot;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;audio&nbsp;id=&quot;audio&quot;&nbsp;src=&quot;${musicList[num].videoSrc}&quot;&gt;&lt;/audio&gt;`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化音乐列表 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;str&nbsp;=&nbsp;&#39;&#39;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;musicList.forEach(function&nbsp;(item,&nbsp;index)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str&nbsp;+=&nbsp;`&nbsp;&lt;li&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&nbsp;class=&quot;mr10&quot;&gt;${index&nbsp;+&nbsp;1}&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;${item.title}&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;-&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;${item.author}&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/li&gt;` &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#musicList&#39;).html(str); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化高亮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;len&nbsp;=&nbsp;musicList.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#musicList&nbsp;&gt;&nbsp;li&#39;).removeClass(&#39;active&#39;).eq(num).addClass(&#39;active&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2、点击播放按钮,让音乐播放,点击切换成暂停,点击暂停 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取对象或者值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;totalWidth&nbsp;=&nbsp;$(&#39;#progrees&#39;).width(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;oAudio&nbsp;=&nbsp;document.querySelector(&#39;#audio&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;默认没有播放 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;isOn&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;播放和暂停功能 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).on(&#39;click&#39;,&nbsp;playAndPause); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;停止播放 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.stop&#39;).on(&#39;click&#39;,&nbsp;stop); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;timeupdate&nbsp;事件在音频/视频(audio/video)的播放位置发生改变时触发。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.addEventListener(&#39;timeupdate&#39;,&nbsp;setProgress); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3、点击下一首播放 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.next&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;autoPlay(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3、点击上一首播放 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.prev&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isOn&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num--; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(num&nbsp;&lt;=&nbsp;-1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;=&nbsp;len&nbsp;-&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init(num); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playAndPause(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;4、点击切换歌曲 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#musicList&nbsp;&gt;&nbsp;li&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;=&nbsp;$(this).index(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isOn&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init(num); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playAndPause(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;5、点击进度条改变播放的位置 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#progrees&#39;).on(&#39;click&#39;,&nbsp;function&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取被点击的偏移值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;offsetX&nbsp;=&nbsp;e.offsetX; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取被点击的位置和整个进度条长度的比例 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;radio&nbsp;=&nbsp;offsetX&nbsp;/&nbsp;totalWidth; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;totalTime&nbsp;=&nbsp;oAudio.duration; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;通过比例乘以总的时间,得到当前时间,赋值给audio对象。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.currentTime&nbsp;=&nbsp;totalTime&nbsp;*&nbsp;radio; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;currentTime变化之后,会自动触发timeupdate事件,会去执行setProgress函数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;setProgress函数会设置进度条的宽度样式等。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;6、自动播放下一首 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.addEventListener(&#39;ended&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;autoPlay(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;autoPlay&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(num&nbsp;&gt;=&nbsp;len)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isOn&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init(num); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playAndPause(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;播放或者暂停的切换函数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;playAndPause()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isOn&nbsp;=&nbsp;!isOn; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;播放和暂停按钮的切换 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(isOn)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.play(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).removeClass(&#39;play1&#39;).addClass(&#39;play2&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).attr(&#39;title&#39;,&nbsp;&#39;暂停&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.pause(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).removeClass(&#39;play2&#39;).addClass(&#39;play1&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).attr(&#39;title&#39;,&nbsp;&#39;播放&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;停止播放功能 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;点击停止按钮,停止播放,进度条归零 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;stop()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.pause(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;状态归为初始状态 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isOn&nbsp;=&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当前的时间归0,同时触发timeupdate事件。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.currentTime&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).removeClass(&#39;play2&#39;).addClass(&#39;play1&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#play&#39;).attr(&#39;title&#39;,&nbsp;&#39;播放&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;进度条和时间的更新,当currentTime更新的时候,会触发timeupdate这个事件 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这个事件触发的时候,不断更新进度条的宽度和当前的播放时间 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;setProgress()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;currentTime&nbsp;=&nbsp;this.currentTime; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;totaltime&nbsp;=&nbsp;this.duration; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;radio&nbsp;=&nbsp;currentTime&nbsp;/&nbsp;totaltime; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;currentWidth&nbsp;=&nbsp;totalWidth&nbsp;*&nbsp;radio; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#curProgrees&#39;).css(&#39;width&#39;,&nbsp;currentWidth); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#totalTime&#39;).html(formate(totaltime)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;console.log(currentTime&nbsp;,&nbsp;totaltime) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#presentTime&#39;).html(formate(currentTime)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化界面和当前音乐的总时间 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;init(num)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;隐藏时间,避免看到NaN &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#playTime&#39;).hide(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;出现音乐加载loading &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.loading&#39;).show(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.src&nbsp;=&nbsp;musicList[num].videoSrc; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#cover&#39;).attr(&#39;src&#39;,&nbsp;musicList[num].coverSrc); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#musicList&nbsp;&gt;&nbsp;li&#39;).removeClass(&#39;active&#39;).eq(num).addClass(&#39;active&#39;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当音乐加载完毕,才获取总的时间,去掉loading &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oAudio.addEventListener(&#39;loadedmetadata&#39;,&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;隐藏loading &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;.loading&#39;).hide(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;totaltime&nbsp;=&nbsp;this.duration; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;显示时间 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#playTime&#39;).show(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(&#39;#totalTime&#39;).html(formate(totaltime)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&quot;json&quot;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;格式化时间 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;formate(time)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;min&nbsp;=&nbsp;Math.floor(time&nbsp;/&nbsp;60); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;sec&nbsp;=&nbsp;Math.floor(time&nbsp;%&nbsp;60); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min&nbsp;=&nbsp;min&nbsp;&lt;&nbsp;10&nbsp;?&nbsp;&#39;0&#39;&nbsp;+&nbsp;min&nbsp;:&nbsp;min; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sec&nbsp;=&nbsp;sec&nbsp;&lt;&nbsp;10&nbsp;?&nbsp;&#39;0&#39;&nbsp;+&nbsp;sec&nbsp;:&nbsp;sec; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;`${min}:${sec}`; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p><br/></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/334.html" rel="nofollow" target="_blank">继续阅读《H5 Audio API+jQuery+ajax实现一个迷你播放器!》的全文内容...</a></p><p>分类: JavaScript万博manbext3.0首页登录集 | Tags: <a href="http://www.mrszhao.com/tags-300.html">audio</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-301.html">HTML5</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-269.html">jQuery</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-299.html">ajax</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-302.html">播放器</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/334.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/334.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/333.html">利用ajax+mock.js+echarts.js模拟汽车销量饼状图</a> (2021-12-20) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Wed, 12 Jul 2023 19:34:59 +0800一半设计一半前端http://www.mrszhao.com/post/337.html<p>函数中的this是一个刚开始接触比较头疼的概念,总感觉它变来变去,害怕一不留神它就不是原来的它了。</p><p>ES6用了箭头函数干脆把this固定住,不允许它变,但是在更复杂的场景中,我们恰恰需要this的多变性,所以,还是必须把this的绑定规则搞定。</p><h2>1、this对象</h2><p>this是JavaScript中一个很特别的关键字,被自动定义在所有函数的作用域中。在函数被调用的时候,this才具有指向性。this引用的是函数执行时的环境对象,也就是函数执行时的作用域对象。不是函数声明时的作用域对象。</p><h3>1.1、调用位置</h3><p cid="n292" mdtype="paragraph">this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。</p><p cid="n294" mdtype="paragraph">在理解this的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置)。</p><p cid="n296" mdtype="paragraph">最重要的是要分析调用栈,就是为了到达当前执行位置所调用的所有函数,我们关心的调用位置就在当前正在执行的函数的前一个调用中。</p><pre class="prism-highlight prism-language-javascript">//&nbsp;调用栈就是当前正在执行的函数 //&nbsp;调用位置就在当前正在执行的函数的前一个调用中。 function&nbsp;baz(){ &nbsp;&nbsp;&nbsp;&nbsp;//当前调用栈是:baz &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;因此,当前调用位置是全局作用域 &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;baz&#39;); &nbsp;&nbsp;&nbsp;&nbsp;bar();&nbsp;//bar的调用位置 &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;baz&#39;); } function&nbsp;bar(){ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当前调用栈是baz-&gt;bar &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;因此,当前调用位置在baz中。 &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;bar&#39;); &nbsp;&nbsp;&nbsp;&nbsp;foo();//foo的调用位置 &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;bar&#39;); } function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;//调试命令,可以让程序停留在这里 &nbsp;&nbsp;&nbsp;&nbsp;debugger; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当前调用栈是baz-&gt;bar-&gt;foo &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;因此,当前调用位置在bar中。 &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;foo&#39;); } baz();&nbsp;//baz的调用位置</pre><h3>1.2、绑定规则</h3><h4>1.2.1、默认绑定</h4><p>最常用的函数调用类型:独立函数调用。可以把这条规则看作是无法应用其它规则时的默认规则。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } //声明在全局作用域中的变量就是全局对象的一个属性。 var&nbsp;a&nbsp;=&nbsp;2; //&nbsp;函数被调用时应用了this的默认绑定,this指向全局对象window foo();&nbsp;//&nbsp;2</pre><h4>1.2.2、隐式绑定</h4><p>另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo } obj.foo();&nbsp;//&nbsp;2</pre><p cid="n308" mdtype="paragraph">函数foo()被当做引用属性添加到obj中,但是无论是直接在obj中定义还是先定义再添加为引用属性,这个函数严格来说都不属于obj对象。</p><p cid="n310" mdtype="paragraph">然而,调用位置会使用obj上下文来引用函数,因为可以说函数被调用时obj对象“拥有”或者包含”它。</p><p cid="n312" mdtype="paragraph">当foo()被调用时,它的前面加上了对obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用时的this绑定到这个上下文对象。</p><p cid="n314" mdtype="paragraph">对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo } var&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:3, &nbsp;&nbsp;&nbsp;&nbsp;obj2:obj, } obj1.obj2.foo();//2</pre><h4>1.2.3、隐式丢失</h4><p>一个最常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把this绑定到全局对象或者undefined中。取决于是否是严格模式。(非严格模式绑定到全局对象,严格模式绑定到undefined中)</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo, } //bar是obj.foo的一个引用,但是实际上,它引用的是函数foo本身。函数引用的上下文丢失 var&nbsp;bar&nbsp;=&nbsp;obj.foo;&nbsp;//&nbsp;函数别名! var&nbsp;a&nbsp;=&nbsp;&#39;全局属性的值&#39;; //此时bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。 bar();&nbsp;//&nbsp;全局属性的值</pre><p>一种更常见的情况发生在传入回调函数时:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } //传入回调函数 function&nbsp;doFoo(fn){ &nbsp;&nbsp;&nbsp;&nbsp;//fn其实引用的是foo &nbsp;&nbsp;&nbsp;&nbsp;fn();&nbsp;//foo的调用位置 } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo } var&nbsp;a&nbsp;=&nbsp;&#39;全局属性的值&#39;; //传递参数其实也是一种隐式赋值,传入函数时也会被隐式赋值。 //&nbsp;fn&nbsp;=&nbsp;obj.foo&nbsp;函数别名 doFoo(obj.foo);//全局属性的值</pre><p>把函数传入语言内置的函数,情况也是一样的。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;:&nbsp;2, &nbsp;&nbsp;&nbsp;&nbsp;foo&nbsp;:&nbsp;foo } var&nbsp;a&nbsp;=&nbsp;&quot;全局属性的值&quot;; setTimeout(obj.foo,1000);&nbsp;//全局属性的值 //和下面的代码原理相似: //fn&nbsp;=&nbsp;obj.foo&nbsp;函数别名 function&nbsp;setTimeout(fn,delay){ &nbsp;&nbsp;&nbsp;&nbsp;//等待delay毫秒 &nbsp;&nbsp;&nbsp;&nbsp;fn();&nbsp;//调用位置 }</pre><p>回调函数丢失this绑定是非常常见的。那么如何固定this呢?</p><h4>1.2.4、显式绑定</h4><p cid="n330" mdtype="paragraph">隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上。</p><p cid="n332" mdtype="paragraph">如果不想在对象内部包含函数引用,只想在某个对象上强制调用函数,该怎么做呢?</p><p cid="n334" mdtype="paragraph">函数作为对象,也拥有自己的方法,call()和apply()方法,JavaScript提供的函数和自己创建的所有函数都可以使用call()和apply()方法。</p><p cid="n336" mdtype="paragraph">方法的第一个参数是一个对象,是给this准备的,在调用函数时将其绑定到this。因为可以直接指定this的绑定对象,这种方法称之为显式绑定。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } foo.call(obj);&nbsp;//&nbsp;2</pre><p cid="n339" mdtype="paragraph">通过foo.call(),可以在调用foo()函数时强制把foo里面的this绑定到obj上。</p><p cid="n341" mdtype="paragraph">如果传入了一个原始值(字符串类型、布尔值类型、数字类型)来当作this的绑定对象,这个原始值会被转换成它的对象形式(new String()、new Boolean()、new Number()),这通常被称为“装箱”。</p><p cid="n341" mdtype="paragraph"><strong>1、硬绑定</strong></p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:&nbsp;2 } //显式的强制绑定叫做硬绑定 var&nbsp;bar&nbsp;=&nbsp;function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;foo.call(obj); } bar();&nbsp;//&nbsp;2&nbsp; setTimeout(bar,&nbsp;100);&nbsp;//&nbsp;2 var&nbsp;a&nbsp;=&nbsp;&#39;全局&#39;; //硬绑定的bar不可能再修改它的this bar.call(window);&nbsp;//&nbsp;2</pre><p cid="n341" mdtype="paragraph">硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值:<br/></p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(something){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a,something); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.a&nbsp;+&nbsp;something; } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } var&nbsp;bar&nbsp;=&nbsp;function(){ &nbsp;&nbsp;&nbsp;&nbsp;//把bar的arguments参数传递给foo,apply支持传递arguments参数。 &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;foo.apply(obj,arguments); } var&nbsp;b&nbsp;=&nbsp;bar(3);&nbsp;//&nbsp;2&nbsp;3 console.log(b);&nbsp;//&nbsp;5</pre><p>另一种方法是创建一个可以重复使用的辅助函数:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(something){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a,something); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.a&nbsp;+&nbsp;something; } //简单的辅助绑定函数 function&nbsp;bind(fn,obj){ &nbsp;&nbsp;&nbsp;&nbsp;//返回一个新函数,形成闭包 &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;fn.apply(obj,arguments); &nbsp;&nbsp;&nbsp;&nbsp;} } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } var&nbsp;bar&nbsp;=&nbsp;bind(foo,obj); var&nbsp;b&nbsp;=&nbsp;bar(3);&nbsp;//&nbsp;2&nbsp;3&nbsp; console.log(b);&nbsp;//&nbsp;5</pre><p>由于硬绑定是一种非常常见的模式,所以ES5提供了内置的方法Function.prototype.bind,它的用法如下:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(something){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a,something); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.a&nbsp;+&nbsp;something; } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 } //利用JavaScript提供的bind函数直接硬绑定 var&nbsp;bar&nbsp;=&nbsp;foo.bind(obj); var&nbsp;b&nbsp;=&nbsp;bar(3);&nbsp;//&nbsp;2&nbsp;3 console.log(b);//5 console.log(bar&nbsp;===&nbsp;foo);&nbsp;//&nbsp;false</pre><p>bind()会返回一个新函数,它会把你指定的参数设置为this的上下文并调用原始函数。</p><p cid="n357" mdtype="paragraph"><strong>2、API调用的“上下文”</strong></p><p cid="n359" mdtype="paragraph">第三方库的许多函数,以及JavaScript语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文(context)”,其作用和bind()一样,确保你的回调函数使用指定的this。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(el){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(el,this.id); } var&nbsp;obj&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;id:&#39;myid&#39; } var&nbsp;id&nbsp;=&nbsp;&#39;全局&#39;; //调用foo时把this绑定到obj [1,2,3].forEach(foo,obj);</pre><p>这些函数实际上就是通过call()等实现了显示绑定,可以少写一些代码实现this的绑定。</p><h4><strong>1.2.5、new绑定</strong></h4><p></p><p cid="n365" mdtype="paragraph">这是最后一条this的绑定规则。</p><p cid="n367" mdtype="paragraph">使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:</p><p cid="n369" mdtype="paragraph">1、创建一个全新的对象。</p><p cid="n371" mdtype="paragraph">2、这个新对象会被执行[[prototype]]连接。</p><p cid="n373" mdtype="paragraph">3、这个新对象会绑定到函数调用的this。</p><p cid="n375" mdtype="paragraph">4、如果函数没有返回其它对象,那么new表达式中的函数调用会自动返回这个新对象。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;Foo(a){ &nbsp;&nbsp;&nbsp;&nbsp;this.a&nbsp;=&nbsp;a&nbsp;; } //使用new调用foo函数,会构造出一个新对象,并把这个新对象绑定到foo函数调用中的this上。 var&nbsp;bar&nbsp;=&nbsp;new&nbsp;Foo(2); console.log(bar.a);&nbsp;//&nbsp;2</pre><p></p><p cid="n378" mdtype="paragraph">在JavaScript中,构造函数只是一些使用new操作符时被调用的函数,它们并不是一种特殊的函数类型,它们只是被new操作符调用的普通函数而已。</p><p cid="n380" mdtype="paragraph">所以,所有函数都可以用new来调用,这种函数调用被称为构造函数调用,实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。</p><h3>1.3、优先级</h3><p cid="n383" mdtype="paragraph">默认绑定的优先级是四条规则中最低的。</p><p cid="n385" mdtype="paragraph">显示绑定的优先级高于隐式绑定。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } var&nbsp;obj2&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:3, &nbsp;&nbsp;&nbsp;&nbsp;foo:foo&nbsp; } obj1.foo();&nbsp;//&nbsp;2 obj2.foo();&nbsp;//&nbsp;3 obj1.foo.call(obj2);&nbsp;//&nbsp;3 obj2.foo.call(obj1);&nbsp;//&nbsp;2</pre><p>new绑定比隐式绑定优先级高</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(something){ &nbsp;&nbsp;&nbsp;&nbsp;this.a&nbsp;=&nbsp;something; } var&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;foo:foo } var&nbsp;obj2&nbsp;=&nbsp;{}; obj1.foo(2); console.log(obj1.a);&nbsp;//&nbsp;2 //显示绑定比隐式绑定优先级高 obj1.foo.call(obj2,3); console.log(obj2.a);//3 //new绑定比隐式绑定的优先级高 var&nbsp;bar&nbsp;=&nbsp;new&nbsp;obj1.foo(4); console.log(bar.a);&nbsp;//&nbsp;4 console.log(obj1.a);//2</pre><p>new绑定的优先级高于显示绑定</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(something){ &nbsp;&nbsp;&nbsp;&nbsp;this.a&nbsp;=&nbsp;something; } var&nbsp;obj1=&nbsp;{}; var&nbsp;bar&nbsp;=&nbsp;foo.bind(obj1); bar(2); console.log(obj1.a);&nbsp;//&nbsp;2 var&nbsp;baz&nbsp;=&nbsp;new&nbsp;bar(3); console.log(obj1.a);&nbsp;//&nbsp;2 console.log(baz.a);&nbsp;//&nbsp;3</pre><p cid="n394" mdtype="paragraph">现在可以根据优先级来判断函数在某个调用位置应用的是哪条规则。</p><p cid="n396" mdtype="paragraph">可以按照下面的顺序进行判断:</p><p>1、函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;bar&nbsp;=&nbsp;new&nbsp;Foo()</pre><p>2、函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;bar&nbsp;=&nbsp;foo.call(obj2)</pre><p>3、函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;bar&nbsp;=&nbsp;obj.foo()</pre><p>4、如果都不是的话,使用默认绑定。如果是在严格模式下,就绑定到undefined,否则绑定到全局对象。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;bar&nbsp;=&nbsp;foo()</pre><h3>1.4、绑定例外</h3><p>如果把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); } var&nbsp;a&nbsp;=&nbsp;2; foo.call(null);&nbsp;//&nbsp;2</pre><p cid="n414" mdtype="paragraph">什么情况下会传入null呢?</p><p cid="n416" mdtype="paragraph">一种常用的做法是用apply()来展开一个数组,并当做参数传入一个函数。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(a,b){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(a&nbsp;+&nbsp;b); } //&nbsp;把数组展开成参数 foo.apply(null,[2,3]);&nbsp;//&nbsp;5 //使用bind()进行柯里化 var&nbsp;bar&nbsp;=&nbsp;foo.bind(null,2); bar(3);&nbsp;//&nbsp;5</pre><p>这两种方法都需要传入一个参数当做this的绑定对象,如果函数不关心this的话,仍然需要传入一个占位值,null非常方便。</p><pre class="prism-highlight prism-language-javascript">let&nbsp;arr&nbsp;=&nbsp;[12,45,14,38]; let&nbsp;max&nbsp;=&nbsp;Math.max.apply(null,arr); console.log(max);&nbsp;//&nbsp;45</pre><p>然而,总是使用null来忽略this绑定可能产生一些副作用,如果某个函数确实使用了this(比如第三方库中的一个函数),那默认绑定会把this绑定到全局对象window上,这可能会导致不可预计的后果(比如修改全局对象)。所以,使用null会导致难以分析和追踪的bug。</p><p><strong>更安全的this</strong></p><p>一种更安全的方法是传入一个特殊的对象,把this绑定到这个对象不会对程序产生任何副作用。</p><p cid="n428" mdtype="paragraph">通过创建一个空对象,就不会对全局对象产生任何影响。</p><pre class="prism-highlight prism-language-javascript">//&nbsp;创建一个空对象,这个空对象比{}更空,因为并不会创建Object.prototype对象。 var&nbsp;φ&nbsp;=&nbsp;Object.create(null); //&nbsp;console.log(φ,{}) function&nbsp;foo(a,b){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(a&nbsp;+&nbsp;b); } //&nbsp;把数组展开成参数 foo.apply(φ,[2,3]);&nbsp;//&nbsp;5 //使用bind()进行柯里化 var&nbsp;bar&nbsp;=&nbsp;foo.bind(φ,2); bar(3);&nbsp;//&nbsp;5</pre><h2>2、this词法</h2><p cid="n432" mdtype="paragraph">在ES6中有一种无法使用上面四种规则的特殊函数类型:箭头函数。</p><p cid="n434" mdtype="paragraph">箭头函数并不是使用function关键字定义的,而是使用被称为“胖箭头”的操作符=&gt;定义的。箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;//返回一个箭头函数 &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//this继承自foo() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); &nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;return&nbsp;function(a){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;*/ } let&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; let&nbsp;obj2&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:3 }; let&nbsp;bar&nbsp;=&nbsp;foo.call(obj1); bar.call(obj2);//&nbsp;2</pre><p cid="n437" mdtype="paragraph">foo()内部创建的箭头函数会捕获调用时foo()的 this,由于foo()的this绑定到了obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改。(new也不行!)</p><p cid="n439" mdtype="paragraph">箭头函数最常用于回调函数中,例如事件处理器或者定时器:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(()=&gt;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里的this在词法上继承自foo() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(this.a); &nbsp;&nbsp;&nbsp;&nbsp;},1000) } let&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; foo.call(obj1);&nbsp;//&nbsp;2</pre><p cid="n442" mdtype="paragraph">箭头函数可以像bind()一样确保函数的this被绑定到指定对象上,此外,其重要性还体现在它用更常见的词法作用域取代了传统的this机制。</p><p cid="n444" mdtype="paragraph">在ES6之前,有一种几乎和箭头函数完全一样的模式:</p><pre class="prism-highlight prism-language-javascript">function&nbsp;foo(){ &nbsp;&nbsp;&nbsp;&nbsp;//把this对象保存在变量中 &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_this&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//通过_this变量来使用保存好的this对象 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(_this.a); &nbsp;&nbsp;&nbsp;&nbsp;},1000) } let&nbsp;obj1&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;a:2 }; foo.call(obj1);&nbsp;//&nbsp;2</pre><h2>3、构造函数</h2><p cid="n448" mdtype="paragraph">其实,在JavaScript中,构造函数并不是一种特殊的函数,只是受到Java等面向对象,拥有类概念的语言的影响。</p><p cid="n450" mdtype="paragraph">构造函数首字母要大写这种规矩也是来源于对Java等语言的追随。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;Foo(){ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this; } let&nbsp;o&nbsp;=&nbsp;new&nbsp;Foo(); console.dir(Foo);//prototype是函数的一个属性,可以叫做原型对象。 //函数的prototype对象里面有一个constructor属性,又指向函数本身。 console.log(Foo.prototype.constructor&nbsp;===&nbsp;Foo);&nbsp;//&nbsp;true //o是一个实例,它有一个原型链[[Prototype]]属性,指向new出自己的函数的原型对象。 console.log(o); //通过__proto__可以访问实例的原型对象。 console.log(o.__proto__); //o实例并没有constructor属性,但是通过对原型链的往上层访问,可以访问到原型对象里面的constructor属性。 console.log(o.constructor&nbsp;===&nbsp;Foo);//&nbsp;true</pre><p>实际上,Foo函数与其他函数没有任何区别。函数本身不是构造函数,当在普通函数调用前面加上new关键字后,就会把这个函数调用变成一个“构造函数调用”。实际上,new会劫持所有普通函数并用构造对象的形式来调用它。</p><pre class="prism-highlight prism-language-javascript">function&nbsp;nothingSpecial(){ &nbsp;&nbsp;&nbsp;&nbsp;console.log(&#39;我是一个普通函数&#39;); } let&nbsp;obj&nbsp;=&nbsp;new&nbsp;nothingSpecial(); console.log(obj);&nbsp;//&nbsp;{}</pre><p cid="n456" mdtype="paragraph">nothingSpecial()只是一个普通函数,使用new调用的时候,就会产生一个对象并赋值给obj,使用new调用一个函数无论如何都会返回一个对象。这个new的调用是一个构造函数的调用,但是nothingSpecial()却不是一个 构造函数。</p><p cid="n458" mdtype="paragraph">可以理解为在JavaScript中,对于“构造函数”最准确的解释是:所有带new的函数调用。</p><p cid="n460" mdtype="paragraph">函数不是构造函数,但是当且仅当使用new时,函数调用会变成“构造函数调用”。</p><p cid="n460" mdtype="paragraph"><strong>当函数作为构造函数调用的时候,函数内部的this指向new返回出来的对象。</strong></p><p> © Copyright Birdol.Com 2006-2014.</p><p><a href="http://www.mrszhao.com/post/337.html" rel="nofollow" target="_blank">继续阅读《函数中的this对象的四种绑定规则和优先级!》的全文内容...</a></p><p>分类: JavaScript万博manbext备用网址 | Tags: <a href="http://www.mrszhao.com/tags-305.html">函数</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-309.html">this</a>,<a rel="nofollow" href="http://www.mrszhao.com/tags-310.html">箭头函数</a>, rel="nofollow" | <a href="http://www.mrszhao.com/post/337.html#comment" rel="nofollow" rel="nofollow" target="_blank">添加评论</a>(0)</p><p><a href="http://www.mrszhao.com/post/337.html#comment" rel="nofollow" rel="nofollow" target="_blank">还没有评论,您来说两句?</a></p><h3>相关文章:</h3><ul><li><a href="http://www.mrszhao.com/post/336.html">函数作为对象的属性和方法(call、apply、bind)</a> rel="nofollow" (2023-07-10) </li><li><a href="http://www.mrszhao.com/post/258.html">DOM基础5:Event事件对象</a> rel="nofollow" (2019-08-23) </li><li><a href="http://www.mrszhao.com/post/256.html">DOM基础3:对元素节点的操作</a> rel="nofollow" (2019-08-20) </li><li><a href="http://www.mrszhao.com/post/250.html">JavaScript基础13:Object对象初了解</a> (2019-08-14) </li><li><a href="http://www.mrszhao.com/post/335.html">吞下作用域和闭包,感觉世界都清晰了!</a> rel="nofollow" (2023-07-09) </li></ul><a target="_blank" title="阿里云优惠" href="http://www.birdol.com/redirect/?s=6"><img rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" rel="nofollow" alt="Z-Blog" src="http://www.birdol.com/aliyun/qingdao950x90.jpg"></a>Wed, 12 Jul 2023 14:28:29 +0800