
嗨,habrozhiteli! 本书将使您深入探讨该主题,学习如何编写美观而有效的代码。 您将学习语法,箭头和异步函数,迭代器,模式字符串和块作用域。
Marein Haverbeke-医生。 通过练习和培训项目中的大量示例获得经验并学习语言。 首先,您将熟悉JavaScript语言的结构,管理结构,功能和数据结构,然后研究错误处理和错误修复,模块化和异步编程,然后继续进行浏览器编程。
复习这本书
本书分为三大部分。 前12章讨论JavaScript语言。 接下来的七章是关于浏览器以及如何使用JavaScript对其进行编程的。 最后,两章专门介绍另一个JavaScript编程环境Node.js。
在本书中,您将遇到五个章节的项目,它们描述了较大的程序示例,因此您可以体会到真正的编程的味道。 按照它们的出现顺序,我们将致力于创建交付机器人,编程语言,游戏平台,光栅图形编辑器和动态站点。
本书的语言部分从四章开始,向您介绍JavaScript语言的基本结构。 您将学习控制结构(例如,在简介中已经看到的while关键字),函数(编写自己的构建块)和数据结构。 之后,您可以编写最简单的程序。 此外,第5章和第6章描述了如何使用函数和对象来编写更多抽象代码并控制其复杂性。
在第一个项目的章节之后,本书的语言部分将继续进行-接下来的章节将专门介绍检测和纠正错误,正则表达式(一种用于处理文本的重要工具),模块化(另一种防止复杂性的方法)和异步编程(用于处理某些事件的持续时间)。时间)。 本书的第一部分在第二稿的章节中完成。
第二部分,第13至19章,介绍了启用JavaScript的浏览器可以访问的工具。 您将学习如何在屏幕上显示元素(第14和17章),响应用户输入(第15章)以及如何通过网络共享它们(第18章)。 这部分还包含项目的两章。
之后,在第20章中描述Node.js,并在第21章中使用指定的工具创建一个小型站点。
摘录。 减少总和
数组经常做的另一件事是根据数组计算单个值。 这种情况的一个特例是我们已经使用过的一组数字求和的示例。 另一个示例是查找包含最多字符的字体。
实现此模式的高阶操作称为简写(有时也称为卷积)。 此操作通过重复从数组中获取一个元素并将其与当前值组合来构建值。 在对数字求和时,我们从零开始,然后将每个后续元素加到总和上。
除了数组之外,reduce函数的参数是组合函数和初始值。 此函数比filter和map复杂一点,因此请仔细看一下:
function reduce(array, combine, start) { let current = start; for (let element of array) { current = combine(current, element); } return current; } console.log(reduce([1, 2, 3, 4], (a, b) => a + b, 0));
当然,与该函数相对应的用于化简数组的标准方法具有更多的便利。 如果数组包含至少一个元素,则可以省略start参数。 该方法选择数组的第一个元素作为初始值,并从第二个元素开始减少。
console.log([1, 2, 3, 4].reduce((a, b) => a + b));
要使用reduce(两次)来查找字符数最多的字体,我们可以编写如下内容:
function characterCount(script) { return script.ranges.reduce((count, [from, to]) => { return count + (to — from); }, 0); } console.log(SCRIPTS.reduce((a, b) => { return characterCount(a) < characterCount(b) ? b : a; }));
characterCount函数通过计算字体大小的总和来减小分配给该字体的范围。 在归约函数的参数列表中注意使用解构。 然后第二个reduce调用使用先前的结果来找到最大的字体,反复比较两种字体并返回较大的字体。
Han字体在Unicode标准中分配了超过89,000个字符,使其成为我们数据集中最大的书写系统。 Han是有时用于中文,日文和韩文文本的字体。 他们的语言具有许多共同的特征,尽管它们的书写方式不同。 Unicode联盟(位于美国)决定将此类字符视为一个记录系统,以保存字符代码。 这叫做汉统一,对某些人来说仍然很烦人。
可组合性
让我们想想:如何在没有高阶函数的情况下重写前面的示例(找到最大的字体)? 以下代码并不差很多。
let biggest = null; for (let script of SCRIPTS) { if (biggest == null || characterCount(biggest) < characterCount(script)) { biggest = script; } } console.log(biggest);
出现了几个附加的绑定,程序长了四行。 但是这段代码仍然很清楚。
当您需要编写操作时,高阶函数开始变得非常有用。 作为示例,我们将编写一个代码,计算在数据集中创建活泼和死语字体的平均时间。
function average(array) { return array.reduce((a, b) => a + b) / array.length; } console.log(Math.round(average( SCRIPTS.filter(s => s.living).map(s => s.year))));
因此,Unicode中的无效语言脚本通常比活动语言的脚本要旧。
这些不是特别重要或令人惊讶的统计数据。 但您希望同意,用于计算它的代码易于阅读。 可以将其想象为传送带:我们首先分析所有字体,过滤掉活的字体(或死字体),使用创建的年份,计算平均值并四舍五入。
该计算也可以表示为一个大周期。
let total = 0, count = 0; for (let script of SCRIPTS) { if (script.living) { total += script.year; count += 1; } } console.log(Math.round(total / count));
但是在这段代码中,要理解什么以及如何计算更加困难。 而且,由于中间结果未显示为一致的值,因此需要做更多的工作才能将平均值等分离为单独的函数。
就计算机实际执行的功能而言,这两种方法也有根本不同。 第一个在运行filter和map时创建新的数组,第二个仅计算一些数字,减少了工作量。 通常,您可以提供一个更具可读性的选项,但是如果您必须处理非常大的数组并执行多次,那么抽象度较低的样式可以为您带来额外的速度提升。
字符串和字符代码
数据集的一种用途是确定给定文本键入的字体。 让我们看一个执行此操作的程序。
回想一下,每种字体都有一系列字符代码范围。 因此,了解字符代码后,我们可以使用以下函数来找到相应的字体(如果有):
function characterScript(code) { for (let script of SCRIPTS) { if (script.ranges.some(([from, to]) => { return code >= from && code < to; })) { return script; } } return null; } console.log(characterScript(121));
some方法是另一个高阶函数。 它接受一个测试函数,并报告该数组的任何元素是否返回true。
但是我们如何获得字符串形式的字符代码呢?
在第1章中,我提到在JavaScript中,字符串表示为16位数字的序列。 这些就是所谓的代码单元。 最初,假定在Unicode中将字符代码放置在这样的块中(该块提供了超过65,000个字符)。 当显然这还不够时,许多人开始反对需要使用更多的内存来存储一个字符。 为了解决这个问题,发明了在JavaScript字符串中使用的UTF-16格式。 在其中,最常见的字符占据一个16位代码单元,其余的占两个代码单元。
今天,人们普遍认为UTF-16是一个坏主意。 它似乎是为了产生错误而创建的。 您可以轻松地编写一个程序,其代码单位和字符是相同的。 并且,如果您的母语不使用占用两个代码单元的字符,则此程序可以正常运行。 但是,一旦有人尝试将这种程序用于不太常见的字母(例如汉字),它将立即中断。 幸运的是,在表情符号出现之后,两个代码单元开始在各处用于字符编码,解决此类问题的负担也更加公平地分配了。
不幸的是,使用JavaScript字符串进行的明显操作(例如通过length属性获取其长度并使用方括号访问其内容)仅处理代码单元。

JavaScript charCodeAt方法不返回完整的字符代码,而是一个代码单元。 稍后出现的codePointAt方法将返回完整的Unicode字符。 因此我们可以使用它从字符串中获取字符。 但是传递给codePointAt的参数仍然是一系列代码单元中的索引。 因此,为了遍历字符串中的所有字符,我们仍然需要解决一个或两个代码单元占用一个字符的问题。
在上一章中,我提到过for / of循环也可以用于字符串。 与codePointAt一样,这种循环出现在程序员清楚地意识到UTF-16问题的时候。 当您将此循环应用于字符串时,它将给出实字符,而不是代码单位。

如果您有一个字符(一个或两个代码单元的字符串),则为了获取其代码,可以使用codePointAt(0)。
文字识别
我们有一个characterScript函数和一种在循环中正确枚举字符的方法。 下一步是计算属于每种字体的字符数。 这里我们需要一个计数抽象:
function countBy(items, groupName) { let counts = []; for (let item of items) { let name = groupName(item); let known = counts.findIndex(c => c.name == name); if (known == -1) { counts.push({name, count: 1}); } else { counts[known].count++; } } return counts; } console.log(countBy([1, 2, 3, 4, 5], n => n > 2));
countBy函数接受一个集合(所有可以在for / of循环中排序的东西)和一个计算给定元素的组名的函数。 countBy函数返回一个对象数组,每个对象包含组的名称和为其找到的元素数。
该函数使用另一种处理数组的方法-findIndex。 此方法有点类似于indexOf,但是它不查找特定值,而是查找给定函数为其返回true的第一个值。 如果找不到该项目,则findIndex与indexOf一样,返回–1。
使用countBy,我们可以编写一个函数,告诉该文本中使用了哪些字体。

该函数首先按字体名称对字符计数,使用characterScript为它们命名,然后为不属于任何字体的字符返回字符串“ none”。 调用filter会从结果数组中删除“ none”条目,因为我们对这些字符不感兴趣。
为了能够计算百分比,我们首先需要获取可以使用reduce方法计算的属于字体的字符总数。 如果找不到此类字符,则该函数返回特定的字符串。 否则,它将使用map将计数结果转换为可读的字符串,然后使用join组合它们。
总结
将功能值传递给其他功能的能力是JavaScript的一个非常有用的方面。 这使您可以创建模拟带有空格的计算的函数。 随后,在代码中调用此类函数时,这些“间隙”将填充有函数值。
对于数组,有许多有用的高阶方法。 forEach方法可用于遍历数组的元素。 filter方法返回一个新数组,其中仅包含满足谓词函数条件的元素。 通过使用map完成每个元素的函数来进行数组转换。 要将数组的所有元素组合为一个值,可以使用reduce。 some方法检查是否有任何元素与给定的谓词功能匹配。 最后,findIndex方法查找与谓词匹配的第一个元素的位置。
»这本书的更多信息可以
在出版商的网站上找到»
目录»
摘录小贩优惠券可享受25%的折扣-JavaScript
支付纸质版本的书后,就会通过电子邮件发送电子书。