<pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;"> ES6 的解构赋值是一个重要的新特性,可以让我们方便地从数组或对象中取出元素并赋值给变量。本章节将介绍ES6解构赋值的用法和优势。</pre><hr/><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">1、数组的解构赋值</strong><br/>数组的解构赋值可以将数组中的值赋值给变量。例如,我们可以这样定义一个数组:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let arr = [1, 2, 3];</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">现在我们想把这个数组中的值分别赋值给三个变量,可以使用解构赋值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let [a, b, c] = arr;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,a、b、c三个变量的值分别为1、2、3。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">数组解构赋值还支持嵌套数组:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let arr = [1, [2, 3], 4];let [a, [b, c], d] = arr;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,a、b、c、d四个变量的值分别为1、2、3、4。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">数组解构赋值还支持默认值,当数组中没有对应的值时,可以使用默认值来赋值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let arr = [1, 2];let [a, b, c = 3] = arr;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,a、b、c三个变量的值分别为1、2、3。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">2、对象的解构赋值</strong><br/>对象的解构赋值可以将对象中的属性赋值给变量。例如,我们可以这样定义一个对象:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let obj = {name: '张三', age: 18};</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">现在我们想把这个对象中的属性值分别赋值给两个变量,可以使用解构赋值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let {name, age} = obj;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,name、age两个变量的值分别为’张三’、18。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">对象解构赋值还支持重命名,可以将属性值赋值给一个新的变量名:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let obj = {name: '张三', age: 18};let {name: newName, age: newAge} = obj;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,newName、newAge两个变量的值分别为’张三’、18。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">对象解构赋值也支持默认值,当对象中没有对应的属性时,可以使用默认值来赋值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let obj = {name: '张三'};let {name, age = 18} = obj;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,name、age两个变量的值分别为’张三’、18。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">3、在函数中使用解构赋值</strong><br/>解构赋值还可以用在函数的参数列表中,可以方便地传递对象或数组的部分值。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">例如,我们可以这样定义一个函数:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">function foo({name, age}) { console.log(name, age);}</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">现在我们可以传递一个对象作为参数:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">foo({name: '张三',age: 18});</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,函数foo就会输出’张三’和18。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">同样的,解构赋值也可以用在函数返回值的处理中:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">function bar() { return [1, 2, 3];}let [a, b, c] = bar();</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,a、b、c三个变量的值分别为1、2、3。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">4、解构赋值的优势</strong><br/>使用解构赋值的优势在于可以简化代码,使代码更加清晰易懂。对于传统的赋值方式,我们需要写很多冗长的代码来获取数组或对象中的值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let arr = [1, 2, 3];let a = arr[0];let b = arr[1];let c = arr[2];let obj = {name: '张三', age: 18};let name = obj.name;let age = obj.age;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">使用解构赋值可以将这些代码简化为一行:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let [a, b, c] = [1, 2, 3];let {name, age} = {name: '张三', age: 18};</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">另外,解构赋值还可以方便地交换两个变量的值:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let a = 1;let b = 2;[a, b] = [b, a];</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这样,a的值变成了2,b的值变成了1。</p><p style="box-sizing: border-box; margin-top: 0px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap; margin-bottom: 0px !important;"><strong style="box-sizing: border-box;">小结</strong><br/>ES6的解构赋值是一个非常方便的新特性,它可以使我们更加轻松地从数组和对象中获取值并赋值给变量。解构赋值不仅能够简化代码,还可以使代码更加清晰易懂。同时,解构赋值也支持嵌套、默认值、重命名等功能,使得代码编写更加灵活多变。建议开发者们在编写JavaScript代码时充分利用ES6的新特性,提高代码的质量和效率。</p><p><br/></p>
文章列表
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">重复 ng-repeat<br/>这算是唯一的一个控制标签么……,它的使用方法类型于:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">< div ng - controller = "TestCtrl" > <ul ng - repeat = "member in obj_list" > <li > { { member } } < /li> </ul > </div> var TestCtrl = function($scope){ $scope.obj_list = [1,2,3,4]; }/</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">除此之外,它还提供了几个变量可供使用:</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">$index 当前索引</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">$first 是否为头元素</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">$middle 是否为非头非尾元素</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">$last 是否为尾元素</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">< div ng - controller = "TestCtrl" > <ul ng - repeat = "member in obj_list" > <li > { { $index } }, { { member.name } } < /li> </ul > </div>var TestCtrl = function($scope){ $scope.obj_list = [{name: 'A'}, {name: 'B'}, {name: 'C'}];}/</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">7.2.2. 赋值 ng-init<br/>这个指令可以在模板中直接赋值,它作用于 angular.bootstrap 之前,并且,定义的变量与 $scope 作用域无关。</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap; margin-bottom: 0px !important;">< div ng - controller = "TestCtrl"ng - init = "a=[1,2,3,4];" > <ul ng - repeat = "member in a" > <li > { { member } } < /li> </ul > </div>/</pre><p><br/></p>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20231218/7ce467f4788d55dd3b26ccc2dd95ec25.jpg" alt=""/></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">第 4 章介绍了 JavaScript 的对象(object)。 在编程文化中,我们有一个名为面向对象编程(OOP)的东西,这是一组技术,使用对象(和相关概念)作为程序组织的中心原则。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">虽然没有人真正同意其精确定义,但面向对象编程已经成为了许多编程语言的设计,包括 JavaScript 在内。 本章将描述这些想法在 JavaScript 中的应用方式。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>封装</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">面向对象编程的核心思想是将程序分成小型片段,并让每个片段负责管理自己的状态。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">通过这种方式,一些程序片段的工作方式的知识可以局部保留。 从事其他方面的工作的人,不必记住甚至不知道这些知识。 无论什么时候这些局部细节发生变化,只需要直接更新其周围的代码。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这种程序的不同片段通过接口(interface),函数或绑定的有限集合交互,它以更抽象的级别提供有用的功能,并隐藏它的精确实现。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这些程序片段使用对象建模。 它们的接口由一组特定的方法(method)和属性(property)组成。 接口的一部分的属性称为公共的(public)。 其他外部代码不应该接触属性的称为私有的(private)。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">许多语言提供了区分公共和私有属性的方法,并且完全防止外部代码访问私有属性。 JavaScript 再次采用极简主义的方式,没有。 至少目前还没有 - 有个正在开展的工作,将其添加到该语言中。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">即使这种语言没有内置这种区别,JavaScript 程序员也成功地使用了这种想法。 通常,可用的接口在文档或数字一中描述。 在属性名称的的开头经常会放置一个下划线(<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">_</code>)字符,来表明这些属性是私有的。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">将接口与实现分离是一个好主意。 它通常被称为封装(encapsulation)。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>方法</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">方法不过是持有函数值的属性。 这是一个简单的方法:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">let rabbit = {};rabbit.speak = function(line) { console.log(`The rabbit says '${line}'`);};rabbit.speak("I'm alive.");// → The rabbit says 'I'm alive.'</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">方法通常会在对象被调用时执行一些操作。将函数作为对象的方法调用时,会找到对象中对应的属性并直接调用。当函数作为方法调用时,函数体内叫做<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>的绑定自动指向在它上面调用的对象。</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">function speak(line) { console.log(`The ${this.type} rabbit says '${line}'`);}let whiteRabbit = {type: "white", speak: speak};let fatRabbit = {type: "fat", speak: speak};whiteRabbit.speak("Oh my ears and whiskers, " + "how late it's getting!");// → The white rabbit says 'Oh my ears and whiskers, how// late it's getting!'hungryRabbit.speak("I could use a carrot right now.");// → The hungry rabbit says 'I could use a carrot right now.'</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">你可以把<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>看作是以不同方式传递的额外参数。 如果你想显式传递它,你可以使用函数的<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">call</code>方法,它接受<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>值作为第一个参数,并将其它处理为看做普通参数。</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">speak.call(hungryRabbit, "Burp!");// → The hungry rabbit says 'Burp!'</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这段代码使用了关键字<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>来输出正在说话的兔子的种类。我们回想一下<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">apply</code>和<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">bind</code>方法,这两个方法接受的第一个参数可以用来模拟对象中方法的调用。这两个方法会把第一个参数复制给<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">由于每个函数都有自己的<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>绑定,它的值依赖于它的调用方式,所以在用<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">function</code>关键字定义的常规函数中,不能引用外层作用域的<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">箭头函数是不同的 - 它们不绑定他们自己的<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>,但可以看到他们周围(定义位置)作用域的<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>绑定。 因此,你可以像下面的代码那样,在局部函数中引用<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">this</code>:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">function normalize() { console.log(this.coords.map(n => n / this.length));}normalize.call({coords: [0, 2, 3], length: 5});// → [0, 0.4, 0.6]</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">如果我使用<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">function</code>关键字将参数写入<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">map</code>,则代码将不起作用</p><p><br/></p>
<p>在学习 async/await 语法之前,您需要很好地了解 JavaScript promises。</p><p>async/await 的工作原理</p><p>async/await 语法是一种特殊语法,用于帮助您处理 promise 对象。它使您的代码更简洁、更清晰。</p><p>处理 时,需要将调用链接到返回 using 方法的函数或变量。PromisePromisethen/catch</p><p>当你有很多承诺时,你还需要很多方法链。例如,以下是使用该函数检索数据的方法:thenfetch()</p><p>fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)</p><p> .then(<span style="color: #569cd6;">response</span> => response.json())</p><p> .then(<span style="color: #569cd6;">json</span> => console.log(json))</p><p> .catch(<span style="color: #569cd6;">error</span> => console.log(error))<span style="color: #6a9955;">;</span></p><p>典型的 Fetch API 实现</p><p>在上面的代码中,该函数返回一个 ,我们使用该方法处理它。在第一种方法中,我们接受 from 请求并使用该方法将其转换为对象。fetch()Promisethen()then()responsejson()</p><p>在第二种方法中,我们从对方法的调用中接收返回的数据,然后将该数据记录到控制台。then()jsonjson()</p><p>我们还添加了该方法来处理运行请求时可能发生的任何错误。catch()</p><p>代码真的不难理解,但是我们可以通过删除 and 链来使其更漂亮,这也删除了回调函数。.then().catch()</p><p>Await 关键字</p><p>该关键字基本上使 JavaScript 等待对象被解析或拒绝。您不必在方法中使用回调模式,而是可以将已实现的承诺分配给如下所示的变量:awaitPromisethen()</p><p>const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;const json = await response.json();console.log(json)</span></p><p>使用 Await 代替 .then() 方法链接</p><p>关键字放在调用返回 promise 的函数或变量之前。它使 JavaScript 等待 promise 对象安定,然后再运行下一行中的代码。await</p><p>现在,如果运行上面的代码,可能会收到如下错误:</p><p>SyntaxError: await is only valid in async functions and the top level bodies of modules</p><p>在异步函数之外使用 Await 时出现语法错误</p><p>发生此错误的原因是必须在异步函数或模块中使用关键字。await</p><p>Async 关键字</p><p>若要创建异步函数,需要在函数名称前添加关键字。请看下面示例中的第 1 行:async</p><p>async function runProcess() {</p><p> const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p> console.log(json)}runProcess()<span style="color: #6a9955;">;</span></p><p>创建异步函数</p><p>在这里,我们创建了一个名为的异步函数,并将使用该关键字的代码放入其中。然后,我们可以通过调用它来运行异步函数,就像常规函数一样。runProcess()await</p><p>如何处理 Async/Await 中的错误</p><p>要处理 async/await 语法中可能发生的错误,可以使用 try/catch 块来捕获来自 promise 的任何拒绝。</p><p>请参阅以下示例:</p><p>async function runProcess() {</p><p> try {</p><p> const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p> console.log(json)<span style="color: #6a9955;">;</span></p><p> } catch (error) {</p><p> console.log(error)<span style="color: #6a9955;">;</span></p><p> }}runProcess()<span style="color: #6a9955;">;</span></p><p>在异步函数中添加 try/catch</p><p>放在函数内部的 try/catch 块将处理来自 promise 对象的拒绝。runProcess()</p><p>现在,我们有了之前创建的标准 Promise 代码的完整 async/await 版本。以下是两者之间的比较:</p><p>PROMISE---异步Promise 与 Async/Await 代码比较</p><p>在 async/await 版本中,promise 的结果直接分配给变量。在标准 promise 版本中,promise 的结果作为参数传递给方法。.then()</p><p>大多数开发人员更喜欢 async/await 版本,因为它看起来更简单。</p><p>如何在 IIFE 和箭头函数中使用 Async/Await</p><p>立即调用函数表达式 (IIFE) 是一种用于在定义函数后立即执行函数的技术。</p><p>与常规函数和变量不同,IIFE 在执行后将从正在运行的进程中删除。</p><p>除了标准函数之外,您还可以制作异步 IIFE。当您只需要运行一次异步函数时,这很有用:</p><p>(async function () {</p><p> try {</p><p> const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p> console.log(json)<span style="color: #6a9955;">;</span></p><p> } catch (error) {</p><p> console.log(error)<span style="color: #6a9955;">;</span></p><p> }})()<span style="color: #6a9955;">;</span></p><p>IIFE 异步函数示例</p><p>您还可以在创建异步函数时使用箭头语法,如下所示:</p><p>const <span style="color: #569cd6;">runProcess</span> = async () => {</p><p> try {</p><p> const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p> console.log(json)<span style="color: #6a9955;">;</span></p><p> } catch (error) {</p><p> console.log(error)<span style="color: #6a9955;">;</span></p><p> }}<span style="color: #6a9955;">;runProcess();</span></p><p>Arrow 异步函数示例</p><p>您可以在代码中随意使用所需的语法。</p><p>为什么使用 async/await 语法?</p><p>async/await 语法使您能够在不使用 and 方法链接的情况下处理 promise,这也消除了对嵌套回调的需求。.then().catch()</p><p>当您在确定承诺后有一个复杂的流程时,这种好处是显着的。</p><p>回到上面的示例,假设方法中有一个条件语句,如下所示:.then()</p><p>fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)</p><p> .then(<span style="color: #569cd6;">response</span> => response.json())</p><p> .then(<span style="color: #569cd6;">json</span> => {</p><p> if (<span style="color: #569cd6;">json.userId</span> == 1) {</p><p> <span style="color: #569cd6;">json.completed</span> == false<span style="color: #6a9955;">;</span></p><p> } else {</p><p> <span style="color: #569cd6;">json.completed</span> == true<span style="color: #6a9955;">;</span></p><p> }</p><p> })</p><p> .catch(<span style="color: #569cd6;">error</span> => console.log(error))<span style="color: #6a9955;">;</span></p><p>Promise 方法中的 if/else 块then()</p><p>在这里,您可以看到接受数据的回调函数内部有一个 if/else 块。json</p><p>与 async/await 版本相比,此代码很难推理和修改,如下所示:</p><p>(async function () {</p><p> try {</p><p> const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">'https://jsonplaceholder.typicode.com/todos/1'</span>)<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p> if (<span style="color: #569cd6;">json.userId</span> == 1) {</p><p> <span style="color: #569cd6;">json.completed</span> == false<span style="color: #6a9955;">;</span></p><p> } else {</p><p> <span style="color: #569cd6;">json.completed</span> == true<span style="color: #6a9955;">;</span></p><p> }</p><p> console.log(json)<span style="color: #6a9955;">;</span></p><p> } catch (error) {</p><p> console.log(error)<span style="color: #6a9955;">;</span></p><p> }})()<span style="color: #6a9955;">;</span></p><p>通过使用 async/await 语法,可以减少对方法链接和嵌套回调的需求。这会影响代码的可读性,尤其是当您有嵌套代码(如 if/else 和 for 循环块)时。</p><p>结论</p><p>现在,您已经了解了 async/await 语法的工作原理。该语法通过消除对 和 方法链接的需求,使使用 promise 变得更加容易,这也消除了对嵌套回调的需求。.then().catch()</p><p>即使关键字只能在函数内部使用,也可以使用 IIFE 仅调用异步函数一次。awaitasync</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>PNPM 类似于 npm,但它更快、更高效。毕竟,起始 p 代表 p性能。</p><p>根据其创建者 Zoltan Kochan 的说法,pnpm“允许您节省千兆字节的磁盘空间”。</p><p>许多流行的项目,包括Next.js,Vite,Svelte,甚至freeCodeCamp都使用pnpm。因此,如果您还没有,现在是尝试此工具的好时机。我相信你的时间不会被浪费。</p><p>在本文中,我不会详细介绍为什么 pnpm 比 npm 更快、更高效。如果您想了解更多信息,可以查看官方文档。</p><p>本文的目的是快速开始使用 pnpm,以便您可以执行以前使用 npm 或 yarn 执行的日常任务。拿起你最喜欢的一杯茶或咖啡,让我们开始吧!</p><p>如何安装 pnpm</p><p>我假设您的机器上已经安装了现代版本的 Node.js。这些现代版本带有一个名为 .它允许您管理您的 Node 包管理器。corepack</p><p>是的,你没看错!这是 Node 的一个实验性功能,但它运行良好。</p><p>因此,要开始使用它,您首先需要通过从终端输入以下命令来启用它,该命令具有在系统上安装 pnpm(以及 yarn)的效果:</p><p>corepack enable</p><p>就是这么简单。现在,如果您运行,您将看到您刚刚安装的版本。但这可能不是 pnpm 的最新版本。如果是这种情况,可以使用以下命令安装最新版本的 pnpm:pnpm --version</p><p>corepack prepare pnpm@latest --activate</p><p>请记住,有很多方法可以在您的系统上安装 pnpm,您可以在安装文档中阅读所有这些方法。我最喜欢的是我上面展示的公式。corepack</p><p>如何配置 Shell 以提高效率(可选)</p><p>好了,你现在已经安装了pnpm。但是可以改进默认的命令行体验,以节省一些精力。</p><p>请注意,此部分是可选的。如果需要,可以跳到下一部分。但是,如果您真的想设置它以使 CLI 体验愉快,让我们学习如何做到这一点。</p><p>pnpm很难输入 - 所以设置一个别名</p><p>如果你发现像我一样很难打字,你可以设置一个别名来节省你的一些精力。如果您使用的是 Linux 或 MacOS,只需将以下内容放入 shell 配置中(、 或):pnpm.bashrc.zshrcconfig.fish</p><p>alias <span style="color: #569cd6;">pn</span>=pnpm</p><p>如果要在 Powershell (Windows) 中设置别名,可以查看此文档。</p><p>如何设置制表符补全</p><p>在 pnpm 中,有两种方法可以做到这一点。两者都有其优点和缺点。</p><p>首先,我将与您分享我最喜欢的方法。它是一个名为 shell 插件,可用于 zsh、fish shell 和 Powershell 核心。它仅涵盖最常用的命令。如果你是 Arch Linux 和 zsh 用户,你可以用任何 AUR 助手来安装它。例如,如果使用 ,请运行以下命令进行安装:pnpm-shell-completionyay</p><p>yay -S pnpm-shell-completion</p><p>然后在文件中添加以下行以加载它:.zshrc</p><p>source /usr/share/zsh/plugins/pnpm-shell-completion/pnpm-shell-completion.zsh</p><p>现在它应该起作用了。如果您使用任何其他受支持的 shell,请按照插件的文档了解如何安装它。</p><p>第二种方法内置于 pnpm 中。若要设置此样式的自动完成,请运行以下命令:</p><p>pnpm install-completion</p><p>然后按照它给你的步骤操作。此方法比第一种方法涵盖更多的命令。但它有一些限制——例如,它不能自动完成你的脚本。例如,它也无法自动完成要卸载的任何依赖项名称。package.json</p><p>如何使用pnpm</p><p>现在,您应该安装了带有别名和 Tab 完成符的 pnpm。不再有延迟——让我们看看如何使用 pnpm。</p><p>如何使用初始化新项目pnpm</p><p>若要获取当前目录中的默认值,请运行以下命令:package.json</p><p>pnpm init</p><p>与 npm 不同,它不会以交互方式创建它,您无需为此指定标志。-y</p><p>如何安装软件包</p><p>若要将包安装为依赖项,语法为:</p><p>pnpm add <pkg></p><p>若要将包安装为开发依赖项,必须传递 (or ) 标志:-D--save-dev</p><p>pnpm add -D <pkg></p><p>若要全局安装包,请使用以下标志:-g</p><p>pnpm add -g <pkg></p><p>如何安装所有依赖项</p><p>假设您从 GitHub 克隆了一个项目。它确实有一个文件,但没有(你不应该用 Git 跟踪)。现在要安装其中的所有依赖项,该命令与以下命令非常相似:package.jsonnode_modulesnode_modulespackage.jsonnpm</p><p>pnpm install</p><p>或</p><p>pnpm i</p><p>如何运行脚本package.json</p><p>这个过程也与 非常相似。执行此操作的明确方法是使用该命令。如果您有一个名为 的脚本,则可以使用以下命令执行它:npmrunbuild</p><p>pnpm run build</p><p>你也可以用它来做同样的事情。这是一种速记格式,也可以做其他事情。在本文中,我们将很快了解有关速记的更多信息。pnpm build</p><p>如何运行依赖项附带的命令</p><p>您可以使用 运行依赖项附带的命令。pnpm exec</p><p>安装软件包时,如果它有 字段指定的命令 ,您将在目录中获得同名的可执行文件。其目的是执行相应的文件。binpackage.jsonnode_modules/.bin</p><p>pnpm exec在 (即 ) 之前,然后执行给定的命令。./node_modules/.<span style="color: #569cd6;">binPATHPATH</span>=./node_modules/.bin:$PATH</p><p>下面是一个示例,演示如何安装为开发依赖项,然后运行命令以创建文件:typescripttsctsconfig.json</p><p>pnpm add -D typescript</p><p>pnpm exec tsc --init</p><p>与命令类似,您也可以省略并仅用于执行相同的操作。当您的 .在下一节中,我们将仔细研究这种速记语法。pnpm runexecpnpm tsctscpackage.json</p><p>请注意,由于可以访问由 中指定的路径解析的所有命令,因此您可以访问许多系统命令,例如 、 等。pnpm execPATHrmls</p><p>如何工作pnpm <command></p><p>pnpm <command>工作原理如下:</p><p>如果是 pnpm 命令(即 ,依此类推),则执行该命令。<command>addinstall</p><p>否则,如果是在 中找到的脚本,请执行 .<command>package.jsonpnpm run <command></p><p>否则执行 .pnpm exec <command></p><p>因此,作为一个方便的快捷方式,其中和是没有回退的显式命令。pnpm <command>pnpm execpnpm run</p><p>如何更新程序包</p><p>要根据 中的指定范围将包更新到最新版本,请运行以下命令:package.json</p><p>pnpm up</p><p>要将所有依赖项更新到其最新版本,请忽略 中指定的范围,请运行以下命令:package.json</p><p>pnpm up --latest</p><p>如何删除包</p><p>要从 和 ur 中删除包,可以使用 。例如,如果您安装了 ,则可以使用以下命令将其删除:node_modulespackage.jsonpnpm rmexpress</p><p>pnpm rm express</p><p>若要删除全局安装的包,请使用该标志。以下是删除全局安装的软件包的示例:-gnodemon</p><p>pnpm rm -g nodemon</p><p>有没有其他选择?npx</p><p>是的,这是命令。它与 npx 非常相似。它从注册表下载指定的包,而不将其安装为依赖项,然后运行它公开的任何默认命令二进制文件。pnpm dlx</p><p>例如,您可以运行 package 公开的命令,如下所示,以打印一头牛的 ASCII 艺术,说出您传递的字符串:cowsay</p><p>pnpm dlx cowsay hi freeCodeCamp</p><p>现在您可能想知道,如果一个包公开了多个命令二进制文件,那么选择哪个命令作为默认值?或者如何显式指定命令二进制文件?pnpm dlx</p><p>让我们先看看默认命令二进制文件是如何确定的:</p><p>如果字段只有一个条目,则使用该条目。binpackage.json</p><p>否则,如果字段中有与包名称匹配的命令名称,则忽略作用域部分(如果有),则使用该命令。binpackage.json</p><p>否则,pnpm 无法确定默认命令,并抛出一个错误,其中包含一条有用的错误消息,该消息很可能会回答第二个问题。</p><p>要显式指定特定命令,您需要先使用该选项安装软件包,然后在 之后指定该命令。--packagedlx</p><p>例如,包向命令二进制文件和 .现在,如果你想在没有 或 的情况下运行来创建一个文件,你可以像下面这样使用:typescripttsctsservertsc --inittsconfig.jsontypescriptnode_modulespackage.jsonpnpm dlx</p><p>pnpm --<span style="color: #569cd6;">package</span>=typescript dlx tsc --init</p><p>结论</p><p>在本教程中,您已经了解了 pnpm 是什么以及如何安装它。我们还介绍了您每天很可能需要的几个常见的 pnpm 命令。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>浏览器中的 JavaScript 代码使用事件驱动的编程模式。这意味着,当浏览器中发生特定的 DOM 事件时,将执行一段代码作为对该操作的响应。</p><p>在本文中,我将帮助您了解和理解如何使用 JavaScript 监听和响应 DOM 事件。</p><p>如果你需要复习一下 DOM,我写了一篇文章来解释 DOM 是什么以及 JavaScript 如何与之交互。</p><p>什么是 DOM 事件,为什么它们有用?</p><p>DOM 事件是浏览器公开的信号,可用于运行一段 JavaScript 代码。</p><p>当用户与我们创建的应用程序交互时,例如单击按钮或在输入字段中键入字母,就会发生这些 DOM 事件。</p><p>作为 Web 开发人员,您可以指示 JavaScript 侦听特定事件并执行一些操作来响应该事件。</p><p>例如:</p><p>单击按钮时,请更改段落的文本。</p><p>提交表单后,使用 Fetch API 执行 POST 请求。</p><p>在本文中,我将帮助您了解和理解如何使用 JavaScript 监听和响应 DOM 事件。</p><p>如何侦听 DOM 事件</p><p>若要侦听事件,需要使用该方法将事件侦听器附加到元素。addEventListener()</p><p>该方法接受两个参数:addEventListener()</p><p>要听的活动type</p><p>触发事件时要运行的函数</p><p>Element.addEventListener(type, function)<span style="color: #6a9955;">;</span></p><p>addEventListener() 方法语法</p><p>回到示例,假设您要在单击元素时更改段落的文本。这是你如何做到的:button</p><p><body></p><p> <p <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"myParagraph"</span>>This is an example paragraph</p></p><p> <button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"changeText"</span>>Change Text</button></p><p> <script></p><p> const <span style="color: #569cd6;">button</span> = document.querySelector(<span style="color: #ce9178;">'#changeText'</span>)<span style="color: #6a9955;">;</span></p><p> function newText(event) {</p><p> const <span style="color: #569cd6;">p</span> = document.querySelector(<span style="color: #ce9178;">'#myParagraph'</span>)<span style="color: #6a9955;">;</span></p><p> <span style="color: #569cd6;">p.innerText</span> = <span style="color: #ce9178;">'The text has been changed'</span><span style="color: #6a9955;">;</span></p><p> }</p><p> button.addEventListener(<span style="color: #ce9178;">'click'</span>, newText)<span style="color: #6a9955;">; </script></body></span></p><p>使用 addEventListener() 方法的示例</p><p>要将 JavaScript 代码插入到 HTML 文档中,我们需要使用如上所示的标签。script</p><p>使用 method 选择按钮元素,然后在该元素上调用该方法。这意味着您将事件侦听器附加到按钮。document.querySelector()addEventListener()</p><p>首先,指定要侦听的事件,在本例中为事件。接下来,指定在发生该事件时要运行的函数。typeclick</p><p>在上面的代码中,函数将在事件被触发时执行。newTextclick</p><p>事件侦听器还将发送一个对象,该对象携带有关触发的事件的信息。这就是为什么上面的函数中有一个参数。eventeventnewText</p><p>您可以将事件记录到控制台以查看其详细信息:</p><p>function newText(event) {</p><p> console.log(event)<span style="color: #6a9955;">;}</span></p><p>记录事件对象</p><p>如果再次单击该按钮,将获得以下输出:</p><p>事件对象日志事件对象日志示例</p><p>根据触发事件时要执行的操作,可能需要使用对象中包含的信息。event</p><p>在这里,我们要做的就是更改段落的文本,因此不需要对象。稍后,我们将在处理键盘事件时看到使用该对象的示例。eventevent</p><p>您可以在浏览器中收听许多事件。以下是开发 Web 应用程序时可能需要的一些最常见的事件:</p><p>事件 事件被触发</p><p>点击 当您按下并松开鼠标主按钮时。用于跟踪按钮和可点击的电子设备</p><p>鼠标移动 移动鼠标光标时</p><p>鼠标悬停 当您将鼠标光标移到元素上时。这就像CSS悬停状态</p><p>鼠标输出 当鼠标光标移动到元素边界之外时</p><p>dblclick 当您点击两次时</p><p>DOMContentLoaded 当 DOM 内容完全加载时</p><p>键盘 当您按下键盘上的某个键时</p><p>键控 当您松开键盘上的某个键时</p><p>提交 提交表单时</p><p>如果您想阅读 DOM 事件类型的完整列表,可以访问此页面。</p><p>DOM 事件分为几类。在这里,我们将只看一下你可能在项目中使用的两个最常见的事件:键盘和鼠标事件。</p><p>键盘事件</p><p>对于键盘,您可以跟踪 和 事件,这些事件分别在您按下和释放键时运行。keydownkeyup</p><p>若要显示示例,请从控制台运行以下代码:</p><p>document.addEventListener(<span style="color: #ce9178;">'keydown'</span>, <span style="color: #569cd6;">event</span> => {</p><p> console.log(`A key is pressed: ${event.key}`)<span style="color: #6a9955;">;});document.addEventListener('keyup', event => {</span></p><p> console.log(`A key is released: ${event.key}`)<span style="color: #6a9955;">;});</span></p><p>捕获键盘事件</p><p>运行上述代码后,缓慢按下键盘上的一个键,然后缓慢松开。</p><p>您应看到如下所示的日志输出:</p><p>键盘事件日志记录键控和键控事件</p><p>请注意,只要您按下一个键,就会显示“keydown”日志,并且“keyup”日志仅在您松开该键时显示。</p><p>键盘事件通常附加到对象而不是特定元素,因为整个网站应该能够侦听该事件。document</p><p>鼠标事件</p><p>除了键盘事件之外,DOM 还提供了一种跟踪任何鼠标事件的方法。</p><p>您可以跟踪的最常见的鼠标事件是:</p><p>mousedown– 按下鼠标按钮</p><p>mouseup– 鼠标按钮被释放</p><p>click– 点击事件</p><p>dblclick– 双击事件</p><p>mousemove– 当鼠标移动到元素上时</p><p>contextmenu– 当上下文菜单打开时,例如单击鼠标右键</p><p>同样,您可以通过直接向对象添加事件侦听器来测试这些事件:document</p><p>document.addEventListener(<span style="color: #ce9178;">'mousedown'</span>, <span style="color: #569cd6;">event</span> => {</p><p> console.log(`The mouse is pressed`)<span style="color: #6a9955;">;});document.addEventListener('mouseup', event => {</span></p><p> console.log(`The mouse is released`)<span style="color: #6a9955;">;});</span></p><p>捕获鼠标事件</p><p>运行上面的代码,然后单击浏览器中的任意位置。您应该会看到分别记录的 和 事件。mousedownmouseup</p><p>如何删除事件侦听器</p><p>若要删除附加到元素的事件侦听器,需要调用该方法,将 of 事件和传递给该方法的 传递给该方法,如下所示:removeEventListener()typefunctionaddEventListener()</p><p>button.removeEventListener(<span style="color: #ce9178;">'click'</span>, newText)<span style="color: #6a9955;">;</span></p><p>删除事件侦听器的示例</p><p>上面的代码足以从元素中删除“click”事件侦听器。请注意,您需要如何在元素上调用方法,同时将函数传递给该方法。buttonremoveEventListener()newText</p><p>若要正确删除事件侦听器,需要具有对附加到事件的函数的引用。如果将无名函数传递给该方法,则无法删除该事件:addEventListener()</p><p>button.addEventListener(<span style="color: #ce9178;">'click'</span>, function (event) {</p><p> alert(<span style="color: #ce9178;">'Button save is clicked'</span>)<span style="color: #6a9955;">;});</span></p><p>无法删除无名称函数</p><p>如果没有上述示例中的函数名称,您将无法删除事件侦听器。</p><p>如何使用 HTML 属性侦听事件</p><p>除了使用该方法之外,您还可以通过将属性添加到 HTML 元素来侦听事件。addEventListener()on[eventname]</p><p>例如,假设您要收听按钮单击。您可以按如下方式将属性添加到按钮:onclick</p><p><body></p><p> <button <span style="color: #569cd6;">onclick</span>=<span style="color: #ce9178;">"handleClick()"</span>>Click Me!</button></p><p> <script></p><p> function handleClick(event) {</p><p> alert(<span style="color: #ce9178;">'The button is clicked!'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>使用 onclick HTML 属性侦听 click 事件</p><p>在上面的 button 元素中,我们添加属性并将函数传递给它。onclickhandleClick()</p><p>当我们单击该按钮时,该功能将被执行。handleClick()</p><p>您还可以使用 JavaScript 添加属性,如下所示:onclick</p><p><body></p><p> <button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"myBtn"</span>>Click Me!</button></p><p> <script></p><p> const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">'#myBtn'</span>)<span style="color: #6a9955;">;</span></p><p> <span style="color: #569cd6;">myBtn.onclick</span> = handleClick<span style="color: #6a9955;">;</span></p><p> function handleClick(event) {</p><p> alert(<span style="color: #ce9178;">'The button is clicked!'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>使用 onclick 属性的示例</p><p>在这里,我们使用 JavaScript 将对函数的引用分配给属性。handleClickonclick</p><p>若要删除 onclick 属性,可以将该属性分配给 null:</p><p>const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">'#myBtn'</span>)<span style="color: #6a9955;">;myBtn.onclick = null;</span></p><p>将 onclick 属性分配给 null</p><p>你应该使用哪一个?</p><p>正如你所看到的,有两种方法可以监听 DOM 事件:方法和 HTML 属性。你应该使用哪一个?addEventListener()on[eventname]</p><p>答案是,当您需要更多扩展性时可以使用该方法,当您希望事情简单时可以使用该方法。addEventListener()on[eventname]</p><p>在开发 Web 应用程序时,文件应仅用作页面的结构,而文件应定义 Web 应用程序可以具有的任何行为。.html.js</p><p>为了使应用程序更易于维护和扩展,JavaScript 应该可以访问 HTML 元素,但任何 HTML 元素都不能执行 JavaScript 函数。这就是为什么应该是推荐的方法。addEventListener()</p><p>但这并非没有代价:你用冗长来交换可扩展性,使你的代码阅读起来非常麻烦。addEventListener()</p><p>使用该属性时,只需在 HTML 元素中指定函数名称:on[eventname]</p><p><body></p><p> <button <span style="color: #569cd6;">onclick</span>=<span style="color: #ce9178;">"handleClick()"</span>>Click Me!</button></p><p> <script></p><p> function handleClick(event) {</p><p> alert(<span style="color: #ce9178;">'The button is clicked!'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>onclick 属性提供了简单性</p><p>但是当你使用该方法时,你需要查询你需要的元素,调用该方法,然后指定要运行的事件和回调函数:addEventListener()</p><p><body></p><p> <button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"myBtn"</span>>Click Me!</button></p><p> <script></p><p> const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">'#myBtn'</span>)<span style="color: #6a9955;">;</span></p><p> myBtn.addEventListener(<span style="color: #ce9178;">'click'</span>, handleClick)<span style="color: #6a9955;">;</span></p><p> function handleClick(event) {</p><p> alert(<span style="color: #ce9178;">'The button is clicked!'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>addEventListener() 方法提供可扩展性</p><p>如上所述,使用该属性时,还有两行不需要编写。on[eventname]</p><p>虽然它可能看起来微不足道,但当您处理具有许多 HTML 和 JS 文件的大型应用程序时,这将是一个严重的问题。</p><p>此外,该方法还允许您将多个侦听器附加到同一元素,如下所示:addEventListener()</p><p><body></p><p> <button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"myBtn"</span>>Click Me!</button></p><p> <script></p><p> const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">'#myBtn'</span>)<span style="color: #6a9955;">;</span></p><p> myBtn.addEventListener(<span style="color: #ce9178;">'click'</span>, handleClick)<span style="color: #6a9955;">;</span></p><p> myBtn.addEventListener(<span style="color: #ce9178;">'click'</span>, handleClickTwo)<span style="color: #6a9955;">;</span></p><p> function handleClick() {</p><p> console.log(<span style="color: #ce9178;">'Run from handleClick function'</span>)<span style="color: #6a9955;">;</span></p><p> }</p><p> function handleClickTwo() {</p><p> console.log(<span style="color: #ce9178;">'Run from handleClickTwo function'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>addEventListener() 允许您分配多个侦听器</p><p>当您单击上面的按钮时,JavaScript 将执行两个事件侦听器。</p><p>对于该属性,这是不可能的,因为一次只能将一个函数指定为引用:onclick</p><p><body></p><p> <button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">"myBtn"</span>>Click Me!</button></p><p> <script></p><p> const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">'#myBtn'</span>)<span style="color: #6a9955;">;</span></p><p> <span style="color: #569cd6;">myBtn.onclick</span> = handleClick<span style="color: #6a9955;">;</span></p><p> // when you assign a new function to onclick,</p><p> // the old function is overwritten</p><p> <span style="color: #569cd6;">myBtn.onclick</span> = handleClickTwo<span style="color: #6a9955;">;</span></p><p> function handleClick() {</p><p> console.log(<span style="color: #ce9178;">'Run from handleClick function'</span>)<span style="color: #6a9955;">;</span></p><p> }</p><p> function handleClickTwo() {</p><p> console.log(<span style="color: #ce9178;">'Run from handleClickTwo function'</span>)<span style="color: #6a9955;">;</span></p><p> } </script></body></p><p>但是我从来没有遇到过需要两次收听同一事件的情况,所以这个优势可能根本没有用。</p><p>结论</p><p>浏览器公开的 DOM 事件使您能够以适当的方式响应用户操作。</p><p>这种使用事件侦听器执行特定任务的模式称为事件驱动编程,在使用 JavaScript 开发 Web 应用程序时,您将经常使用此模式。</p><p>有两种方法可以侦听事件:使用 JavaScript 方法和 HTML 属性。每种方法都有其优点和缺点,因此最好同时熟悉两者。addEventListener()on[eventname]</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>Web 存储 API 是一组由浏览器公开的 API,以便您可以在浏览器中存储数据。</p><p>存储在 Web 存储中的数据使用键/值对格式,并且这两个数据都将存储为字符串。</p><p>Web 存储 API 中引入了两种类型的存储:本地存储和会话存储。</p><p>在本文中,我将向您展示如何使用 Web 存储 API,以及为什么它对 Web 开发人员有用。</p><p>Web 存储 API 的工作原理</p><p>Web 存储 API 公开了一组对象和方法,可用于在浏览器中存储数据。您存储在 Web 存储中的数据是私有的,这意味着其他网站无法访问它。</p><p>在 Google Chrome 中,您可以通过打开开发人员工具窗口并转到“应用程序”选项卡来查看 Web 存储,如下所示:</p><p>web-storage-location-1Google Chrome 中的 Web 存储位置</p><p>在上图中,您可以看到“存储”菜单还具有其他存储类型,例如索引数据库、Web SQL 和 cookie。Web SQL 标准已被弃用,并且 IndexedDB 很少使用,因为它太复杂了。存储在 IndexedDB 中的任何数据最好存储在服务器上。</p><p>至于 cookie,它是一种更传统的数据存储机制,最多只能存储 4 KB 的数据。相比之下,本地存储容量为 10 MB,会话存储容量为 5 MB。</p><p>这就是为什么我们在本文中只关注本地存储和会话存储的原因。</p><p>本地存储和会话存储说明</p><p>本地存储和会话存储是 Web 存储 API 支持的两种标准机制。</p><p>Web 存储是特定于域的,这意味着存储在一个域 (netflix.com) 下的数据不能被另一个域(www.netflix.com 或 members.netflix.com)访问</p><p>Web 存储也是特定于协议的。这意味着您存储在站点中的数据将无法在站点下使用。http://https://</p><p>本地存储和会话存储之间的主要区别在于本地存储将永久存储您的数据。如果要删除数据,则需要使用可用方法或从“应用程序”选项卡中手动清除数据。</p><p>相比之下,存储在会话存储中的数据仅在页面会话期间可用。当您关闭浏览器或选项卡时,将删除该特定选项卡的会话存储。</p><p>Local 和 Session Storage 都可以分别通过变量 和 下的对象进行访问。接下来,让我们看看这些存储类型的方法和属性。windowlocalStoragesesionStorage</p><p>本地存储和会话存储的方法和属性</p><p>本地存储和会话存储具有相同的方法和属性。若要在本地存储中设置新的键/值对,可以使用对象的方法:setItem()localStorage</p><p>localStorage.setItem(<span style="color: #ce9178;">'firstName'</span>, <span style="color: #ce9178;">'Nathan'</span>)<span style="color: #6a9955;">;</span></p><p>调用 setItem() 方法</p><p>如果您在浏览器中查看“本地存储”菜单,您应该会看到上述数据保存到存储中,如下所示:</p><p>本地存储集项目在本地存储中存储键/值对</p><p>您使用的密钥必须是唯一的。如果使用已存在的键设置另一个数据,则该方法会将以前的值替换为新值。localStoragesetItem()</p><p>若要从本地存储中获取值,需要调用该方法并传递保存数据时使用的密钥。如果密钥不存在,则将返回:getItem()getItem()null</p><p>const <span style="color: #569cd6;">firstName</span> = localStorage.getItem(<span style="color: #ce9178;">'firstName'</span>)<span style="color: #6a9955;">;console.log(firstName); // Nathanconst lastName = localStorage.getItem('lastName');console.log(lastName); // null</span></p><p>调用 getItem() 方法</p><p>若要删除本地存储中的数据,请调用该方法并传递指向要删除的数据的密钥:removeItem()</p><p>localStorage.removeItem(<span style="color: #ce9178;">'firstName'</span>)<span style="color: #6a9955;">;</span></p><p>调用 removeItem() 方法</p><p>该方法将始终返回 。当要删除的数据不存在时,该方法将不执行任何操作。removeItem()undefined</p><p>如果要清除存储,可以使用以下方法:clear()</p><p>localStorage.clear()<span style="color: #6a9955;">;</span></p><p>清除本地存储</p><p>该方法从您正在访问的存储对象中删除所有键/值对。clear()</p><p>本地存储和会话存储的属性</p><p>这两种存储类型都只有一个属性,即显示其中存储的数据量的属性。length</p><p>sessionStorage.setItem(<span style="color: #ce9178;">'firstName'</span>, <span style="color: #ce9178;">'Nathan'</span>)<span style="color: #6a9955;">;sessionStorage.setItem('lastName', 'Sebhastian');console.log(sessionStorage.length); // 2sessionStorage.clear();console.log(sessionStorage.length); // 0</span></p><p>访问会话存储的 length 属性</p><p>这就是您可以在 和 中访问的所有方法和属性。localStoragesessionStorage</p><p>如何在 Web 存储存储中存储 JSON 字符串</p><p>由于 Web 存储始终将数据存储为字符串,因此您可以将复杂数据存储为 JSON 字符串,然后在访问该字符串时将该字符串转换回对象。</p><p>例如,假设我想存储有关用户的以下信息:</p><p>const <span style="color: #569cd6;">user</span> = {</p><p> firstName: <span style="color: #ce9178;">'Nathan'</span>,</p><p> lastName: <span style="color: #ce9178;">'Sebhastian'</span>,</p><p> url: <span style="color: #ce9178;">'https://codewithnathan.com'</span>,}<span style="color: #6a9955;">;</span></p><p>对象数据示例</p><p>首先,我可能会将数据存储为一系列键/值对,如下所示:</p><p>localStorage.setItem(<span style="color: #ce9178;">'firstName'</span>, user.firstName)<span style="color: #6a9955;">;localStorage.setItem('lastName', user.lastName);localStorage.setItem('url', user.url);</span></p><p>将对象放入本地存储</p><p>但更好的方法是将 JavaScript 对象转换为 JSON 字符串,然后将数据存储在一个键下,如下所示:</p><p>const <span style="color: #569cd6;">user</span> = {</p><p> firstName: <span style="color: #ce9178;">'Nathan'</span>,</p><p> lastName: <span style="color: #ce9178;">'Sebhastian'</span>,</p><p> url: <span style="color: #ce9178;">'https://codewithnathan.com'</span>,}<span style="color: #6a9955;">;const userData = JSON.stringify(user);localStorage.setItem('user', userData);</span></p><p>使用 JSON.stringify() 将对象转换为 JSON 字符串</p><p>现在,本地存储将只有一个键/值对,其值为 JSON字符串。您可以打开“应用程序”选项卡来查看以下内容:</p><p>存储为JSON将 JSON 字符串存储在本地存储中</p><p>需要数据时,按如下方式调用 and 方法:getItem()JSON.parse()</p><p>const <span style="color: #569cd6;">getUser</span> = JSON.parse(localStorage.getItem(<span style="color: #ce9178;">'user'</span>))<span style="color: #6a9955;">;console.log(getUser);// {firstName: 'Nathan', lastName: 'Sebhastian', url: 'https://codewithnathan.com'}</span></p><p>检索和解析作为对象的 JSON 字符串</p><p>在这里,您可以看到数据作为常规 JavaScript 对象返回。</p><p>本地存储与会话存储 – 使用哪一个?</p><p>根据我的经验,是首选的 Web 存储机制,因为只要您需要,数据就会持续存在。当您不需要数据时,可以使用该方法将其删除。localStorageremoveItem()</p><p>sessionStorage仅当需要存储临时数据时才使用,例如跟踪是否已向用户显示弹出框。</p><p>但这也有待讨论,因为您可能不希望在用户每次登录 Web 应用程序时都显示弹出窗口,而只显示一次。在这种情况下,您应该改用。localStorage</p><p>我的经验法则是先使用,并在情况需要时使用。localStoragesessionStorage</p><p>使用 Web 存储 API 的好处</p><p>现在您已经了解了 Web 存储 API 的工作原理,您可以看到它有一些好处:</p><p>将数据存储在浏览器上可以减少向服务器请求一条信息的需要。这可以提高 Web 应用程序的性能。</p><p>简单的键/值对格式允许您存储用户首选项和本地设置,这些设置应在会话之间保留。</p><p>Web 存储 API 使用简单,仅提供几个方法和一个属性。使用 JavaScript 设置和检索数据非常简单</p><p>它有离线支持。通过在本地存储必要的数据,Web 存储使您的 Web 应用程序能够脱机工作。</p><p>Web 存储也是一个标准化的 API,这意味着您编写的代码可以在许多不同的浏览器中工作。</p><p>但是,当然,并非所有数据都应存储在 Web 存储 API 中。您仍然需要一个服务器数据库来保存对应用程序很重要的记录。</p><p>结论</p><p>Web Storage 是一个有用的 API,可让您从浏览器快速存储和检索数据。使用 Web 存储,您可以在访问应用程序时存储用户的首选项。</p><p>localStorage允许您永久存储数据,直到手动删除数据,而只要浏览器或选项卡打开,它就会一直存在。sessionStorage</p><p>使用 Web 存储 API 的一些好处包括减少服务器请求、离线支持和易于使用的简单 API。它也是标准化的,因此它可以在不同的浏览器上运行。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>JavaScript 中处理和使用函数的方式非常有趣。它们非常灵活——我们可以将函数作为值分配给变量,将它们作为值从另一个函数返回,并将它们作为参数传递给另一个函数。我们可以做到这一切,因为 JavaScript 将函数视为一等公民。</p><p>在本文中,我将介绍什么是高阶函数和回调,以及它们在 JavaScript 中是如何工作的。</p><p>在 JavaScript 中充当一等公民</p><p>函数在 JavaScript 中被定义为一等公民或一等对象,因为函数被视为变量。</p><p>这意味着 JavaScript 中的函数可以是:</p><p>作为参数传递给另一个函数。</p><p>作为值分配给变量。</p><p>作为函数的值返回。</p><p>了解函数在 JavaScript 中的处理方式至关重要,因为它们是理解 JavaScript 中高阶函数和回调函数以及它们如何工作的构建块。</p><p>什么是高阶函数?</p><p>高阶函数是将函数作为参数并返回函数作为值的函数。</p><p>JavaScript 中提供了许多内置的高阶函数。我们将看一些,并利用如何将函数视为一等公民。我们还将创建自己的高阶函数。</p><p>首先,让我们看一些内置高阶函数的例子。</p><p>数组方法</p><p>数组方法通常是开发人员在学习 JavaScript 时首次引入的高阶函数。这些方法包括但不限于 JavaScript 提供的 、 、 、 和 数组方法。</p><p>这些数组方法或函数有很多共同点,但最常见的特征之一是它们都接受函数作为参数。下面是一个代码片段,演示了数组方法的工作原理:mapfilterforEachfindfindIndexsomeeveryforEach</p><p>const <span style="color: #569cd6;">people</span> = [</p><p> { firstName: <span style="color: #ce9178;">"Jack"</span>, year: 1988 },</p><p> { name: <span style="color: #ce9178;">"Kait"</span>, year: 1986 },</p><p> { name: <span style="color: #ce9178;">"Irv"</span>, year: 1970 },</p><p> { name: <span style="color: #ce9178;">"Lux"</span>, year: 2015 },]<span style="color: #6a9955;">;people.forEach(function (person) {</span></p><p> console.log(person)<span style="color: #6a9955;">;});// Output: Logs every person object in the array</span></p><p>从上面的代码示例中,我们可以看到该方法接受一个函数作为参数,它在数组上的每次迭代中调用该函数。因此,数组方法是一个高阶函数。forEachforEach</p><p>计时器事件</p><p>另一组常用的内置高阶函数是 and 函数,在 JavaScript 中称为计时器事件。setIntervalsetTimeout</p><p>每个函数都接受一个函数作为其参数之一,并使用它来创建时标事件。</p><p>看看下面的代码示例,看看它是如何工作的:setTimeout</p><p>setTimeout(function () {</p><p> console.log(<span style="color: #ce9178;">"This is a higher order function"</span>)<span style="color: #6a9955;">;}, 1000);// Output: "This is a higher order function" after 1000ms / 1 second</span></p><p>上面的代码片段是函数工作原理的最基本示例。它接受函数和持续时间(以毫秒为单位),并在提供的持续时间过后执行该函数。setTimeout</p><p>从上面的示例中,在 1000 毫秒或一秒后打印到控制台。This is a higher order function</p><p>setInterval(function () {</p><p> console.log(<span style="color: #ce9178;">"This is a higher order function"</span>)<span style="color: #6a9955;">;}, 1000);// Output: "This is a higher order function" after every 1000ms / 1 second</span></p><p>该函数类似于函数,就像数组方法一样——尽管它的功能不同。但是我们可以看到一个共同的模式:它也接受一个函数作为它的参数之一。setIntervalsetTimeout</p><p>与(在提供的持续时间过后执行函数)不同,每 1000 毫秒或 1 秒一遍又一遍地执行函数。setTimeoutsetInterval</p><p>如何创建和使用高阶函数</p><p>高阶函数不限于 JavaScript 提供的内置函数。</p><p>由于 JavaScript 中的函数被视为第一类对象,因此我们可以利用这种行为并构建高性能和可重用的函数。</p><p>在下面的示例中,我们将构建几个函数。他们将接受客户的姓名和问候语,然后将该信息打印到控制台。</p><p>首先,这里有一个简单的函数可以同时执行这两件事:</p><p>function greetCustomer(firstName, lastName, salutation) {</p><p> const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p> console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer("Franklin", "Okolie", "Good Day");// Output: "Good Day Franklin Okolie"</span></p><p>greetCustomer接受 3 个参数:名字、姓氏和称呼。然后,它将对客户的问候语打印到控制台。</p><p>但是这个功能有一个问题——它做两件事:撰写客户的全名和打印问候语。</p><p>这不是最佳实践,因为函数应该只做一件事并把它做好。因此,我们将重构我们的代码。</p><p>另一个函数应包含客户的姓名,以便该函数只需将问候语打印到控制台。因此,让我们编写一个函数来处理这个问题:greetCustomer</p><p>function composeName(firstName, lastName) {</p><p> const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p> return fullName<span style="color: #6a9955;">;}</span></p><p>现在我们有一个结合了客户名字和姓氏的函数,我们可以在以下位置使用该函数:greetCustomer</p><p>function greetCustomer(composerFunc, firstName, lastName, salutation) {</p><p> const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p> console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer(composeName, "Franklin", "Okolie", "Good Day");// Output: "Good Day Franklin Okolie"</span></p><p>现在这看起来更干净了,每个函数只做一件事。该函数现在接受 4 个参数,并且由于其中一个参数是函数,因此它现在是一个高阶函数。greetCustomer</p><p>您之前可能想知道,一个函数是如何在另一个函数内部调用的,为什么?</p><p>现在,我们将深入探讨函数调用并回答这两个问题。</p><p>将函数作为值返回</p><p>请记住,高阶函数要么将函数作为参数,要么将函数作为值返回。</p><p>让我们重构函数以使用更少的参数并返回一个函数:greetCustomer</p><p>function getGreetingsDetails(composerFunc, salutation) {</p><p> return function greetCustomer(firstName, lastName) {</p><p> const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p> console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;</span></p><p> }<span style="color: #6a9955;">;</span></p><p>最后一个版本接受了太多的论点。四个论点并不多,但如果你搞砸了论点的顺序,仍然会令人沮丧。一般来说,你的论点越少越好。greetCustomer</p><p>因此,在上面的示例中,我们有一个名为 Function 的函数,它接受并代表内部函数。然后,它返回内部函数,该函数本身接受 和 作为参数。getGreetingDetailscomposerFuncsalutationgreetCustomergreetCustomerfirstNamelastName</p><p>通过这样做,总体上有更少的论点。greetCustomer</p><p>有了这个,让我们来看看如何使用该函数:getGreetingDetails</p><p>const <span style="color: #569cd6;">greet</span> = getGreetingsDetails(composeName, <span style="color: #ce9178;">"Happy New Year!"</span>)<span style="color: #6a9955;">;greet("Quincy", "Larson");// Output: "Happy New Year Quincy Larson"</span></p><p>现在退后一步,欣赏这个美丽的抽象。奇妙!我们利用高阶函数的魔力来简化函数。greetCustomer</p><p>让我们来看看一切是如何工作的。名为 Named 的高阶函数包含两个参数:一个用于组成客户名字和姓氏的函数,以及一个称呼。然后,它返回一个名为的函数,该函数接受客户的名字和姓氏作为参数。getGreetingDetailsgreetCustomer</p><p>返回的函数也使用接受的参数来执行某些操作。greetCustomergetGreetingDetails</p><p>在这一点上,您可能想知道,返回的函数如何使用提供给父函数的参数?特别是考虑到函数执行上下文的工作方式。这是可能的,因为关闭。现在让我们更多地了解它们。</p><p>闭合解释</p><p>闭包是一个函数,它有权访问创建它的范围内的变量,即使该范围在执行上下文中不再存在。这是回调的基本机制之一,因为在外部函数关闭后,回调仍然可以引用和使用在外部函数中创建的变量。</p><p>让我们举一个简单的例子:</p><p>function getTwoNumbers(num1, num2) {</p><p> return function add() {</p><p> const <span style="color: #569cd6;">total</span> = num1 + num2<span style="color: #6a9955;">;</span></p><p> console.log(total)<span style="color: #6a9955;">;</span></p><p> }<span style="color: #6a9955;">;}const addNumbers = getTwoNumbers(5, 2);addNumbers();//Output: 7;</span></p><p>此示例中的代码定义了一个名为的函数,并演示了闭包的工作原理。让我们更详细地探讨一下:getTwoNumbers</p><p>getTwoNumbers定义为采用两个参数的函数,并且 .num1num2</p><p>在里面,它返回另一个函数,这是一个名为 的内部函数。getTwoNumbersadd</p><p>调用该函数时,会计算 和 的总和,并将结果记录到控制台。addnum1num2</p><p>在函数之外,我们创建一个变量,调用它,并为其分配调用的结果。这有效地设置了一个闭包,现在“记住”值和 as 和 .getTwoNumbersaddNumbersgetTwoNumbers(5, 2)addNumbers52num1num2</p><p>最后,我们调用执行内部函数。由于是闭包,因此它仍然可以访问分别设置为 和 的值。它计算它们的总和并记录到控制台。addNumbers()addaddNumbersnum1num2527</p><p>如果您想了解有关关闭的更多信息,请在此处阅读更多内容。</p><p>回到我们的高阶函数。返回的函数作为值返回,我们将其存储在名为 的变量中。greetCustomergreet</p><p>这样做会使变量本身成为一个函数,这意味着我们可以将其作为函数调用并传入名字和姓氏的参数。greet</p><p>还有 violà 你有它。这些概念一开始可能有点复杂,但一旦你掌握了它们的窍门,它们就永远不会离开你。</p><p>我鼓励您再次通读前面的部分,在编辑器中播放代码,并掌握所有内容如何协同工作的窍门。</p><p>现在您已经深入了解了高阶函数的工作原理,让我们来谈谈回调函数。</p><p>什么是回调函数?</p><p>回调函数是作为参数传递到另一个函数的函数。</p><p>同样,作为一等公民的函数的决定性因素之一是它能够作为参数传递给另一个函数。这称为传递回调的行为。</p><p>让我们回过头来看看我们之前在学习 JavaScript 中提供的内置函数时讨论的计时事件。这又是函数:setTimeout</p><p>setTimeout(function () {</p><p> console.log(<span style="color: #ce9178;">"This is a higher order function"</span>)<span style="color: #6a9955;">;}, 1000);// Output: "This is a higher order function" after 1000ms / 1 seconds</span></p><p>我们已经确定该函数是一个高阶函数,因为它接受另一个函数作为参数。setTimeout</p><p>作为参数传递给函数的函数称为回调函数。这是因为它是在它传入的高阶函数中调用或执行的。setTimeout</p><p>为了更好地理解回调函数,让我们再看一下前面的函数:greetCustomer</p><p>// THIS IS A CALLBACK FUNCTION// IT IS PASSED AS AN ARGUMENT TO A FUNCTIONfunction composeName(firstName, lastName) {</p><p> const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p> return fullName<span style="color: #6a9955;">;}// THIS IS A HIGHER ORDER FUNCTION// IT ACCPEPTS A FUNCTION AS A ARGUMENTfunction greetCustomer(composerFunc, firstName, lastName, salutation) {</span></p><p> const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p> console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer(composeName, "Franklin", "Okolie", "Good Day");// Output: "Good Day Franklin Okolie"</span></p><p>是一个回调函数,它作为参数传递到函数中,这是一个高阶函数,并在此函数中执行。composeNamegreetCustomer</p><p>高阶函数和回调函数的区别</p><p>重要的是要了解这两个术语之间的区别,这样我们才能在技术面试中与队友进行更清晰的沟通:</p><p>高阶函数:接受函数作为参数和/或返回函数作为其值的函数。</p><p>回调函数:作为参数传递给另一个函数的函数。</p><p>一个包和一本书</p><p>为了进一步理解这些术语,我将分享一个简单的类比。</p><p>想象一下,你有一个包和一本书。你在参加聚会、上课、去教堂等时把书放在包里。</p><p>在这种情况下,袋子会接受您的书来携带它,并在您想使用它时将其归还。所以袋子就像一个高阶函数。</p><p>这本书一直放在袋子里,直到它准备好使用,所以它就像一个回调函数。</p><p>燃油和油箱</p><p>让我们看另一个类比<span style="color: #6a9955;">;燃料和油箱。</span></p><p>为了给汽车加油,我们必须将燃料倒入油箱,油箱接收燃料——就像高阶函数一样。</p><p>燃油被倒入油箱 - 就像一个回调函数。</p><p>我希望这些类比有助于进一步简化高阶函数和回调函数以及它们之间的区别。</p><p>结论</p><p>正如你所看到的,JavaScript中的函数非常灵活,可以以很多有用的方式使用。这种灵活性也导致了 JavaScript 中两个常见的技术术语,高阶函数和回调函数。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>在 JavaScript 中,有两种主要的函数编写方式。您可以使用常规函数语法创建函数。或者,您可以使用箭头函数语法。</p><p>在本文中,您将学习如何使用这两个选项。您还将了解两者之间的区别以及何时适合使用它们。</p><p>要了解这两个选项之间的区别,让我们从查看它们的语法开始。</p><p>常规函数语法</p><p>在 JavaScript 中声明函数的常用方法是使用关键字。下面是一个示例:function</p><p>function sayHello(name) {</p><p> return <span style="color: #ce9178;">'Hello '</span> + name}</p><p>若要从常规函数返回值,必须显式使用关键字。否则,该函数将返回 .returnundefined</p><p>箭头函数语法</p><p>箭头函数是在 ECMAScript 6 (ES6) 中引入的。它们为您提供了一种在 JavaScript 中定义函数的更简洁的方法。</p><p>使用上一个示例中的相同函数,让我们看看如何使用箭头函数语法创建它。sayHello</p><p>const <span style="color: #569cd6;">sayHello</span> = (name) => {</p><p> return <span style="color: #ce9178;">'Hello '</span> + name}</p><p>与常规函数不同,如果只有一个语句,如上面的例子,则不必使用显式返回。您可以像这样将函数写在一行上。</p><p>const <span style="color: #569cd6;">sayHello</span> = (name) => <span style="color: #ce9178;">'Hello '</span> + name</p><p>请注意,大括号也会被移除,以隐式返回表达式的结果。如果只有一个参数,您甚至可以删除括号。请参阅以下示例:</p><p>const <span style="color: #569cd6;">sayHello</span> = <span style="color: #569cd6;">name</span> => <span style="color: #ce9178;">'Hello '</span> + name</p><p>是函数采用的唯一参数。这意味着您可以从参数中删除括号,它仍然可以正常工作。name</p><p>如何访问传递给函数的参数</p><p>JavaScript 提供了一种访问传递给函数的所有参数的方法。但是,你处理这些参数的方式取决于你正在使用的函数类型。</p><p>如何使用常规函数访问参数</p><p>您可以使用该对象访问传递给常规函数的所有参数。该对象是一个类似数组的对象,它保存传递给函数的所有参数。argumentsarguments</p><p>例:</p><p>function logNumbers(num1, num2) {</p><p> console.log(arguments)}logNumbers(8, 24)</p><p>屏幕截图-2024-01-11-at-5.01.51-PMarguments 对象的日志结果</p><p>从日志结果中可以看出,该对象包含作为参数传递给函数的两个数字。argumentslogNumbers</p><p>如何使用箭头函数访问参数</p><p>该对象在箭头函数中不可用。如果您尝试在箭头函数中访问它,JavaScript 将抛出引用错误。arguments</p><p>const <span style="color: #569cd6;">logNumbers</span> = (num1, num2) => {</p><p> console.log(arguments)}logNumbers(8, 24) // Uncaught ReferenceError: arguments is not defined</p><p>若要访问传递给箭头函数的参数,可以使用 rest 参数语法 ()。...</p><p>例:</p><p>const <span style="color: #569cd6;">logNumbers</span> = (...args) => {</p><p> console.log(args)}logNumbers(8, 24)</p><p>屏幕截图-2024-01-11-at-11.13.39-PM记录箭头函数参数的结果</p><p>使用 rest 参数语法 (),您可以访问传递给函数的所有参数。...logNumbers</p><p>重复的命名参数</p><p>常规函数和箭头函数之间的另一个区别是它们如何处理命名参数中的重复项。</p><p>常规函数中的重复命名参数</p><p>当常规函数的参数中具有重复的名称时,具有重复名称的最后一个参数将优先。让我们看一个例子:</p><p>function exampleFunction(a, b, a) {</p><p> console.log(a, b)}exampleFunction(<span style="color: #ce9178;">"first"</span>, <span style="color: #ce9178;">"second"</span>, <span style="color: #ce9178;">"third"</span>)</p><p>屏幕截图-2024-01-12-at-9.50.00-AM记录命名重复参数的结果</p><p>在上面的示例中,参数会覆盖参数的值,因为最后一个重复参数是优先的参数。thirdfirst</p><p>但在“严格模式”下,使用重复的命名参数将导致语法错误。</p><p><span style="color: #ce9178;">"use strict"</span>function exampleFunction(a, b, a) {</p><p> console.log(a, b)}exampleFunction(<span style="color: #ce9178;">"first"</span>, <span style="color: #ce9178;">"second"</span>, <span style="color: #ce9178;">"third"</span>)</p><p>屏幕截图-2024-01-12-at-10.29.11-AM严格模式不允许多次使用参数名称</p><p>箭头函数中的命名参数重复</p><p>箭头函数不允许在参数列表中多次使用相同的参数名称。这样做将导致语法错误。</p><p>例:</p><p>const <span style="color: #569cd6;">exampleFunction</span> = (a, b, a) => {</p><p> console.log(a, b)}exampleFunction(<span style="color: #ce9178;">"first"</span>, <span style="color: #ce9178;">"second"</span>, <span style="color: #ce9178;">"third"</span>)</p><p>屏幕截图-2024-01-12-at-10.29.11-AM-1箭头函数不允许重复的参数名称</p><p>功能吊装</p><p>在 JavaScript 中,提升是一种行为,在编译期间,在执行代码之前,变量和函数被移动到其包含范围的顶部。</p><p>在常规函数中托管</p><p>常规功能被吊到顶部。您甚至可以在它们被声明之前访问和调用它们。</p><p>regularFunction()function regularFunction() {</p><p> console.log(<span style="color: #ce9178;">"This is a regular function."</span>)}</p><p>屏幕截图-2024-01-12-at-11.50.43-AM在声明常规函数之前记录调用常规函数的结果</p><p>以上是在声明常规函数之前调用该函数的示例。而且它工作正常,不会因为功能提升而抛出任何错误。</p><p>在箭头功能中提升</p><p>另一方面,箭头函数在初始化之前无法访问。</p><p>arrowFunction()const <span style="color: #569cd6;">arrowFunction</span> = () => {</p><p> console.log(<span style="color: #ce9178;">"This is an arrow function."</span>)}</p><p>屏幕截图-2024-01-12-at-12.07.39-PM在声明箭头函数之前记录调用该函数的结果</p><p>与常规函数不同,尝试在声明箭头函数之前调用箭头函数将导致引用错误,如上面的输出所示。</p><p>如何处理函数中的绑定this</p><p>常规函数有自己的上下文。这是根据您调用或执行函数的方式动态确定的。this</p><p>另一方面,箭头函数没有自己的此上下文。相反,它们从创建箭头函数的周围词法上下文中捕获值。this</p><p>以下是使用常规函数和箭头函数的两种不同方案。您将看到上下文是如何确定的。this</p><p>1. 在简单函数调用期间设置值this</p><p>对于常规函数,一个简单的函数调用将值设置为对象(如果使用“严格模式”,则设置为):thiswindowundefined</p><p>function myRegularFunction() {</p><p> console.log(this)}</p><p> myRegularFunction()</p><p>屏幕截图-2024-01-12-at-4.15.11-PM对窗口对象的常规函数集的简单调用this</p><p><span style="color: #ce9178;">"use strict"</span>function myFunction() {</p><p> console.log(this)}</p><p> myFunction() // udefined</p><p>使用箭头函数时,无论您是否使用严格模式,简单的函数调用都会将值设置为周围的上下文。在下面的示例中,周围的上下文是全局窗口对象。this</p><p>const <span style="color: #569cd6;">myArrowFunction</span> = () => {</p><p> console.log(this)<span style="color: #6a9955;">;};myArrowFunction()</span></p><p>屏幕截图-2024-01-12-at-4.15.11-PM-1对窗口对象的箭头函数集的简单调用this</p><p>2. 在对象上调用或调用方法时</p><p>调用值为正则函数的方法时,该值将设置为调用该方法的对象。但是,当方法的值是箭头函数时,该值将设置为全局窗口对象。thisthis</p><p>const <span style="color: #569cd6;">myObject</span> = {</p><p> regularExample: function() {</p><p> console.log(<span style="color: #ce9178;">"REGULAR: "</span>, this)</p><p> },</p><p> arrowExample: () => {</p><p> console.log(<span style="color: #ce9178;">"ARROW: "</span>, this)</p><p> }}</p><p> myObject.regularExample()myObject.arrowExample()</p><p>屏幕截图-2024-01-12-at-5.46.04-PM具有常规函数的方法和具有箭头函数的方法的日志结果</p><p>虽然具有常规函数的方法将对象记录到控制台,但具有箭头函数的方法则记录全局窗口对象。</p><p>如何使用函数作为构造函数</p><p>对于常规函数,您可以使用关键字创建新实例。这会将值设置为您创建的新实例。newthis</p><p>对于箭头函数,不能将它们用作构造函数。这是因为箭头函数的值是词法范围的,即由周围的执行上下文确定。这种行为使它们不适合用作构造函数。this</p><p>下面是一个示例:</p><p>function RegularFuncBird(name, color) {</p><p> <span style="color: #569cd6;">this.name</span> = name <span style="color: #569cd6;">this.species</span> = color</p><p> console.log(this)}const <span style="color: #569cd6;">ArrowFuncBird</span> = (name, color) => {</p><p> <span style="color: #569cd6;">this.name</span> = name <span style="color: #569cd6;">this.color</span> = color</p><p> console.log(this)}new RegularFuncBird(<span style="color: #ce9178;">"Parrot"</span>, <span style="color: #ce9178;">"blue"</span>) new ArrowFuncBird(<span style="color: #ce9178;">"Parrot"</span>, <span style="color: #ce9178;">"blue"</span>)</p><p>屏幕截图-2024-01-12-at-5.53.17-PM尝试使用常规函数和箭头函数作为构造函数的日志结果</p><p>构造函数可以很好地处理关键字,但会导致类型错误。RegularFuncBirdnewArrowFuncBird</p><p>那么你应该使用哪一个呢?</p><p>对此没有直接的答案。您使用常规函数还是箭头函数取决于具体的用例。</p><p>建议在以下任何一种情况下使用常规函数:</p><p>当您需要使用带有关键字的构造函数时new</p><p>当需要动态作用域绑定时this</p><p>当您想要使用对象时arguments</p><p>您可以在以下任何情况下使用箭头函数:</p><p>当您想要更简洁的函数语法时</p><p>当您需要维护this</p><p>对于非方法函数(在大多数情况下)</p><p>正如您从本文中了解到的,两者都是在 JavaScript 中定义函数的有效方法。请记住,在它们之间进行选择并不总是个人喜好的问题。相反,它取决于您期望从函数中获得的行为类型。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>
<p>对人工智能驱动的应用程序的需求正在快速增长。作为前端开发人员,您可以利用这一趋势,通过将您在前端开发中的技能与 AI 技术相结合来推进您的职业生涯。</p><p>通过这种集成,您可以构建智能应用程序,以改善用户体验并提供有价值的见解,从而对用户的决策产生积极影响。</p><p>为了突出目前令人兴奋的机会,请考虑以下统计数据:</p><p>2023 年,超过 60% 的初创公司被著名的 Y Combinator 录取,专注于人工智能。</p><p>尽管全球投资放缓,但人工智能初创公司的资金激增,并在 2023 年达到了令人印象深刻的 500 亿美元。</p><p>在本指南中,我们将介绍以下内容:</p><p>前端开发人员在推进 AI 创新中的作用。</p><p>将 AI 服务集成到前端工作流中时要遵循的关键步骤</p><p>如何确保您构建的 AI 应用程序具有最佳性能和安全性。</p><p>最后,我们将结合 1-3 中的技巧来构建一个 AI 网站评论家,它可以使用 React 和 OpenAI 的 GPT4-Vision 模型烘焙您的网站和投资组合应用程序。</p><p>先决条件</p><p>HTML知识</p><p>对 React hooks 的基本了解</p><p>本地计算机上安装的 Node 和 npm。</p><p>前端开发人员在打造 AI 驱动体验中的作用</p><p>前端开发人员利用他们在用户界面设计、数据可视化和技术实施方面的专业知识,在打造 AI 驱动的体验方面发挥着至关重要的作用。</p><p>他们负责创建用户界面、设计交互流程以及将 AI 功能无缝集成到应用程序中。</p><p>前端开发人员还与后端开发人员和数据科学家合作,以确保 AI 算法的高效和准确运行。</p><p>此外,前端开发人员在利用最新 AI 模型的 Web 应用程序的性能方面发挥着关键作用。他们负责优化应用程序的性能,确保跨平台兼容性,并实施适应不同设备和屏幕尺寸的响应式设计。</p><p>如何将 AI 服务集成到前端工作流中</p><p>若要将 AI 服务集成到前端工作流中,应遵循包括以下步骤的系统方法:</p><p>确定 AI 功能可以解决或增强的任务或问题。</p><p>研究和评估为所确定的任务或问题所需的特定 AI 功能提供 API 和节点 SDK 的 AI 公司。通过了解不同 AI 公司的产品,您可以选择最合适的 AI 服务来集成到您的应用程序中。</p><p>让我们来看看一些流行的 AI 模型及其核心任务:</p><p>AI模型 任务</p><p>GPT-4的 多模态模型(能够处理文本、图像等)</p><p>稳定扩散 文本到图像生成式 AI 模型</p><p>米斯特拉尔 7B 多模态模型(能够处理文本、图像等)</p><p>语音盒 语音生成式 AI 模型</p><p>达尔·E 3 文本到图像生成式 AI 模型</p><p>您可以在“复制探索”和“拥抱脸”探索模型页面上探索更多此类模型。</p><p>利用提供的 API 和节点 SDK,将选定的 AI 服务集成到您的前端应用程序中。这涉及了解 AI 公司提供的文档和指南,以确保无缝集成和正确利用 AI 功能。</p><p>测试和验证前端应用程序中的集成 AI 服务,以确保准确高效的功能。此步骤对于识别和解决技术问题或优化要求至关重要。</p><p>通过提供清晰的解释和可视化,让用户对 AI 生成的输出有一种控制感和所有权,以同理心进行设计也很重要。</p><p>应用实例</p><p>让我们看一个例子。假设你想制作一个自定义的模因生成器。在这种情况下,您应该搜索专门训练用于处理图像的 AI 模型,例如 Stability 的 Stable Diffusion 和 OpenAI 的 DALL·E 3.</p><p>之后,您可以探索可用于利用这些 AI 模型并创建基本示例的最佳 API 和 SDK。</p><p>为了说明这一点,让我们使用 Replicate Node SDK,它提供了一种方便的方法来与 Stable Diffusion AI 模型进行交互,并设置一个基本的 Node.js 程序,我们以后可以将其集成到我们的 React 应用程序中。</p><p>步骤 1。从 https://replicate.com/account 获取令牌</p><p>第 2 步:使用 npm 命令安装 Node SDK:Step 2: Install the Node SDK with the npm command: 步骤 3:</p><p>通过复制 SDK 查询 Stable Diffusion AI 模型。npm install replicate</p><p>const <span style="color: #569cd6;">Replicate</span> = require(<span style="color: #ce9178;">"replicate"</span>)<span style="color: #6a9955;">;</span></p><p>const <span style="color: #569cd6;">replicate</span> = new Replicate({</p><p> auth: <span style="color: #ce9178;">""</span>, // defaults to process.env.REPLICATE_API_TOKEN</p><p>})<span style="color: #6a9955;">;</span></p><p>async function iLoveCats(){</p><p> const <span style="color: #569cd6;">model</span> = <span style="color: #ce9178;">"stability-ai/stable-diffusion:27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478"</span><span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">input</span> = {</p><p> prompt: <span style="color: #ce9178;">"a cat wearing a suit"</span>,</p><p> }<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">output</span> = await replicate.run(model, { input })<span style="color: #6a9955;">;</span></p><p> console.log(output[0])<span style="color: #6a9955;">;</span></p><p>}</p><p>iLoveCats()</p><p>当您记录输出时,您会获得一个图像 URL,您可以轻松地在前端应用程序中显示该 URL。https://replicate.delivery/pbxt/ng6Tb0HNdzYwFZXMNv3qmIBxc2GIwU4t7edephtDvuWZ5wNSA/out-0.png</p><p>一只穿西装的猫一只穿西装的猫。</p><p>如何优化 AI 驱动的前端应用程序的性能和安全性</p><p>优化 AI 驱动的前端应用程序的性能和安全性对于创建流畅的用户体验和数据保护至关重要。</p><p>值得庆幸的是,下面列出的技术类似于传统前端开发中的标准做法。这种重叠意味着熟悉传统前端优化和安全实践的开发人员可以更轻松地适应和应用这些技能来满足 AI 驱动应用程序的独特需求:</p><p>采用延迟加载和代码拆分技术来减少初始加载时间并提高性能。</p><p>利用缓存和资源优化技术来最大限度地减少不必要的 API 调用并提高数据检索速度。</p><p>实施安全的 API 端点和身份验证机制,以确保仅授权访问 AI 服务和数据。</p><p>如何使用 React 和 OpenAI 的 GPT4-Vision 模型构建 AI 网站评论家</p><p>在本节中,我们将构建一个 React 应用程序,该应用程序利用 Vision 模型来分析网站图像并提供反馈。为此,我们将遵循前面描述的 4 步工作流程,将 AI 服务集成到前端应用程序中。</p><p>由于我们需要一个可以分析图像的视觉模型,我们应该看看市场上的可用选项,你可以在这里和这里找到。在检查了可用视觉模型的性能基准后,我们将使用 OpenAI 的 GPT-4 视觉模型。</p><p>OpenAI 的 GPT-4 视觉模型是 2023 年底发布的最先进的 AI 模型。它可以接受图像作为输入,对其进行分析,并根据提示提供详细的反馈。</p><p>除了性能原因外,我们还将把它用于我们的网站评论应用程序,因为它提供比其他视觉模型相对便宜的价格,并且有一个易于使用的 API 端点,与流行的 OpenAI 开发人员界面捆绑在一起。</p><p>现在是时候将它集成到我们的 React 应用程序中了。</p><p>第 1 步:安装 React + Vite</p><p>您可以使用以下命令执行此操作:</p><p>npm create vite@latest my-website-critic -- --template react</p><p>第 2 步:安装 OpenAI Node 包</p><p>在您喜欢的 IDE 中打开生成的项目文件夹并安装 OpenAI Node 包,您将使用它与 GPT4 Vision 模型进行交互。</p><p>安装方法如下:</p><p>cd my-website-critic</p><p>npm install openai</p><p>第 3 步:安装 React Markdown 包</p><p>这将帮助您以可读的格式格式化模型的文本响应。</p><p>npm install react-markdown</p><p>第 4 步:运行 npm install</p><p>现在运行:npm install</p><p> npm install</p><p> npm run dev</p><p>第 5 步:在 React 中管理状态</p><p>在此步骤中,您将使用 React 的 useState 和 useEffect 钩子来管理状态并处理对 OpenAI API 的异步请求。src/App.jsx</p><p>freeCodeCamp 英雄部分freeCodeCamp 英雄部分</p><p>对于我们的图像输入,我们将使用上传到 IMGBB 等图像存储平台的 freeCodeCamp 主页英雄部分的屏幕截图。随意使用您想要的任何图像 URL。</p><p>这是代码 - 我将在下面解释它:</p><p>import { useState, useEffect } from <span style="color: #ce9178;">'react'</span><span style="color: #6a9955;">;import OpenAI from 'openai';import ReactMarkdown from 'react-markdown';const App = () => {</span></p><p> const [response, setResponse] = useState(null)<span style="color: #6a9955;">;</span></p><p> const [isLoading, setIsLoading] = useState(false)<span style="color: #6a9955;">;</span></p><p> useEffect(() => {</p><p> const <span style="color: #569cd6;">openai</span> = new OpenAI({</p><p> apiKey: <span style="color: #ce9178;">"YOUR_OPENAI_API_KEY"</span>,</p><p> dangerouslyAllowBrowser: true,</p><p> })<span style="color: #6a9955;">;</span></p><p> const <span style="color: #569cd6;">fetchUICriticResponse</span> = async () => {</p><p> setIsLoading(true)<span style="color: #6a9955;">;</span></p><p> try {</p><p> const <span style="color: #569cd6;">result</span> = await openai.chat.completions.create({</p><p> model: <span style="color: #ce9178;">"gpt-4-vision-preview"</span>,</p><p> messages: [</p><p> {</p><p> role: <span style="color: #ce9178;">"user"</span>,</p><p> content: [</p><p> { type: <span style="color: #ce9178;">"text"</span>, text: <span style="color: #ce9178;">"You're an expert UI critic. What can I improve in this website?"</span> },</p><p> {</p><p> type: <span style="color: #ce9178;">"image_url"</span>,</p><p> image_url: {</p><p> <span style="color: #ce9178;">"url"</span>: <span style="color: #ce9178;">"https://i.ibb.co/sWM573X/Screenshot-2024-01-18-at-10-34-28-AM.png"</span>,</p><p> },</p><p> },</p><p> ],</p><p> },</p><p> ],</p><p> <span style="color: #ce9178;">"max_tokens"</span>: 1500</p><p> })<span style="color: #6a9955;">;</span></p><p> if (result && result.choices && result.choices.length > 0 && result.choices[0].message) {</p><p> console.log(1, result)<span style="color: #6a9955;">;</span></p><p> setResponse(result.choices[0].message.content)<span style="color: #6a9955;">;</span></p><p> }</p><p> } catch (error) {</p><p> console.error(<span style="color: #ce9178;">"Error fetching AI response:"</span>, error)<span style="color: #6a9955;">;</span></p><p> } finally {</p><p> setIsLoading(false)<span style="color: #6a9955;">;</span></p><p> }</p><p> }<span style="color: #6a9955;">;</span></p><p> fetchUICriticResponse()<span style="color: #6a9955;">;</span></p><p> }, [])<span style="color: #6a9955;">;</span></p><p> return (</p><p> <div></p><p> <h3>Hi! UI Expert Here</h3></p><p> {isLoading ? (</p><p> <p>Loading...</p></p><p> ) : response ? (</p><p> <div></p><p> <h3>My Feedback:</h3></p><p> <ReactMarkdown>{response}</ReactMarkdown></p><p> </div></p><p> ) : (</p><p> <p>No response received.</p></p><p> )}</p><p> </div></p><p> )<span style="color: #6a9955;">;};export default App;</span></p><p>在上面的组件中:</p><p>useEffect 挂钩在组件挂载时运行该函数。fetchUICriticResponse</p><p>useState 钩子管理 AI 响应 (response) 和加载状态 (isLoading)。</p><p>fetchUICriticResponse是一个使用 OpenAI API 获取响应的异步函数。</p><p>该组件在获取响应时呈现加载消息。获取完成后,它会使用我们之前安装的 React Markdown 包显示响应或回退消息。</p><p>您应该得到类似于下图的结果,其中包含对所提供图像和给定提示的 GPT4 Vision 模型分析结果。</p><p>GPT4 Vision 模型分析结果GPT4 Vision 模型分析的结果。</p><p>正如你所看到的,分析遍历了页面上的每个元素,并提供了关于导航清晰度、空格使用、搜索功能等方面的反馈——既有积极的,也有更具建设性的。</p><p>注意:出于安全考虑,不建议直接在前端处理 API 密钥。这个例子只是为了学习。在生产环境中,创建一个文件并放入其中。.envYOUR_OPENAI_API_KEY</p><p>下一步是什么?</p><p>您可以通过创建一个简单的输入字段供用户输入其图像链接来增强这些代码示例。您还可以设置图像上传器,以允许用户从其本地设备上传图像。</p><p>有关如何实现此目的的说明,请参阅官方文档。</p><p>在决定开发哪些 AI 应用程序时,考虑预期影响、用户需求和可用资源至关重要。</p><p>其他一些潜在的人工智能应用想法包括语言翻译应用程序和虚拟个人助理。</p><p>结论</p><p>如果您有兴趣将 AI 整合到前端应用中,请从探索开源和闭源 AI 模型开始。您还需要了解如何使用 API 和外部库。</p><p>您还应该专注于熟悉处理 AI 模型响应和交互性。</p><p>有了这些知识,您就可以为即将涌现的几项面向消费者的 AI 创新做好准备,这些创新需要熟练构建 AI 驱动的应用程序的前端开发人员的服务。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>