Repository: ten-ltw/JavaScript-The-Definitive-Guide-7th-zh
Branch: master
Commit: 02dd0ecfbb7c
Files: 28
Total size: 1.7 MB
Directory structure:
gitextract_0ubatihb/
├── .github/
│ └── workflows/
│ └── gh-pages.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── archetypes/
│ └── default.md
├── config.toml
├── content/
│ └── posts/
│ ├── ch1.md
│ ├── ch10.md
│ ├── ch11.md
│ ├── ch12.md
│ ├── ch13.md
│ ├── ch14.md
│ ├── ch15.md
│ ├── ch16.md
│ ├── ch17.md
│ ├── ch2.md
│ ├── ch3.md
│ ├── ch4.md
│ ├── ch5.md
│ ├── ch6.md
│ ├── ch7.md
│ ├── ch8.md
│ └── ch9.md
├── layouts/
│ └── partials/
│ └── head/
│ └── seo.html
└── static/
├── CNAME
├── browserconfig.xml
└── site.webmanifest
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/gh-pages.yml
================================================
name: Js
on:
push:
branches:
- master # Set a branch to deploy
pull_request:
jobs:
deploy:
runs-on: ubuntu-20.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
with:
submodules: true # Fetch Hugo themes (true OR recursive)
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.91.2'
extended: true
- name: Build
run: hugo -D
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
external_repository: ten-ltw/JavaScript-The-Definitive-Guide-7th-zh
personal_token: ${{ secrets.JS_GITHUB_TOKEN }}
publish_dir: ./public
publish_branch: page
- name: Algolia Docsearch Uploader
uses: guzhongren/algolia-docsearch-upload-action@v1.0.0
env:
FILE_PATH: "./public/index.json"
APPLICATION_ID: ${{secrets.ALGOLIA_APPLICATION_ID}}
ADMIN_API_KEY: ${{secrets.ALGOLIA_API_KEY}}
INDEX_NAME: "JS"
================================================
FILE: .gitignore
================================================
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,hugo
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,hugo
### Hugo ###
# Generated files by hugo
/public/
/resources/_gen/
/assets/jsconfig.json
hugo_stats.json
# Executable may be added to repository
hugo.exe
hugo.darwin
hugo.linux
# Temporary lock file while building
/.hugo_build.lock
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
# Ignore code-workspaces
*.code-workspace
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,hugo
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
================================================
FILE: .gitmodules
================================================
[submodule "themes/LoveIt"]
path = themes/LoveIt
url = https://github.com/dillonzq/LoveIt.git
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Mr.Ten
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# JavaScript-The-Definitive-Guide-7th-zh
《JavaScript 权威指南第七版》中英对照
在线阅读:[https://js.okten.cn/](https://js.okten.cn/)
## 目录
- [第 1 章 JavaScript 概述](content/posts/ch1.md)
- [第 2 章 词法结构](content/posts/ch2.md)
- [第 3 章 类型、值和变量](content/posts/ch3.md)
- [第 4 章 表达式和运算符](content/posts/ch4.md)
- [第 5 章 语句](content/posts/ch5.md)
- [第 6 章 对象](content/posts/ch6.md)
- [第 7 章 数组](content/posts/ch7.md)
- [第 8 章 函数](content/posts/ch8.md)
- [第 9 章 类](content/posts/ch9.md)
- [第 10 章 模块](content/posts/ch10.md)
- [第 11 章 JavaScript 标准库](content/posts/ch11.md)
- [第 12 章 迭代器和生成器](content/posts/ch12.md)
- [第 13 章 异步 JavaScript](content/posts/ch13.md)
- [第 14 章 元编程](content/posts/ch14.md)
- [第 15 章 Web 浏览器中的 JavaScript](content/posts/ch15.md)
- [第 16 章 服务器端 JavaScript](content/posts/ch16.md)
- [第 17 章 JavaScript 工具和扩展](content/posts/ch17.md)
模块、标准库选择性阅读
Node 相关先放一放
## License
[MIT](./LICENSE)
================================================
FILE: archetypes/default.md
================================================
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
================================================
FILE: config.toml
================================================
# for build
baseURL = 'https://blog.okten.cn/'
theme = "LoveIt"
minify = true
html = "keep"
Whitespace = false
title = "《JavaScript 权威指南第七版》中英对照"
# 网站语言, 仅在这里 CN 大写 ["en", "zh-CN", "fr", "pl", ...]
languageCode = "zh-CN"
# 语言名称 ["English", "简体中文", "Français", "Polski", ...]
languageName = "简体中文"
# 是否包括中日韩文字
hasCJKLanguage = true
# 作者配置
[author]
name = "Ten Li"
email = "li.tw.ten@gmail.com"
link = "https://blog.okten.cn/"
# 菜单配置
[menu]
[[menu.main]]
weight = 1
identifier = "posts"
# 你可以在名称 (允许 HTML 格式) 之前添加其他信息, 例如图标
pre = ""
# 你可以在名称 (允许 HTML 格式) 之后添加其他信息, 例如图标
post = ""
name = "所有章节"
url = "/posts/"
# 当你将鼠标悬停在此菜单链接上时, 将显示的标题
title = ""
[markup]
[markup.highlight]
noClasses = false
[module]
[module.hugoVersion]
extended = true
min = "0.62.0"
[params]
description = "This is my blog"
# date format
dateFormat = "2006-01-02"
# website description for RSS, SEO, Open Graph and Twitter Cards
# 网站描述, 用于 RSS, SEO, Open Graph 和 Twitter Cards
# website images for Open Graph and Twitter Cards
# 网站图片, 用于 Open Graph 和 Twitter Cards
images = []
[params.header]
desktopMode = "fixed"
mobileMode = "auto"
[params.header.title]
# URL of the LOGO
# LOGO 的 URL
logo = ""
name = "《JavaScript 权威指南第七版》中英对照"
pre = ""
post = ""
# Footer config
# 页面底部信息配置
[params.footer]
enable = true
custom = ""
hugo = false
copyright = true
author = true
since = 2020
# ICP info only in China (HTML format is supported)
# ICP 备案信息,仅在中国使用 (支持 HTML 格式)
icp = ""
# license info (HTML format is supported)
# 许可协议信息 (支持 HTML 格式)
license= "CC BY-NC 4.0"
# Section (all posts) page config
[params.section]
paginate = 20
dateFormat = "01-02"
# amount of RSS pages
# RSS 文章数目
rss = 10
# List (category or tag) page config
# List (目录或标签) 页面配置
[params.list]
# special amount of posts in each list page
# list 页面每页显示文章数量
paginate = 20
# date format (month and day)
# 日期格式 (月和日)
dateFormat = "01-02"
# amount of RSS pages
# RSS 文章数目
rss = 10
# App icon config
# 应用图标配置
[params.app]
# optional site title override for the app when added to an iOS home screen or Android launcher
# 当添加到 iOS 主屏幕或者 Android 启动器时的标题, 覆盖默认标题
title = "《JavaScript 权威指南第七版》中英对照"
# whether to omit favicon resource links
# 是否隐藏网站图标资源链接
noFavicon = false
# modern SVG favicon to use in place of older style .png and .ico files
# 更现代的 SVG 网站图标, 可替代旧的 .png 和 .ico 文件
svgFavicon = ""
# Android browser theme color
# Android 浏览器主题色
themeColor = "#ffffff"
# Safari mask icon color
# Safari 图标颜色
iconColor = "#5bbad5"
# Windows v8-11 tile color
# Windows v8-11 磁贴颜色
tileColor = "#da532c"
# Search config
# 搜索配置
[params.search]
enable = true
# type of search engine ["lunr", "algolia"]
# 搜索引擎的类型 ["lunr", "algolia"]
type = "algolia"
# max index length of the chunked content
# 文章内容最长索引长度
contentLength = 4000
placeholder = "搜索文章标题或内容..."
# max number of results length
# 最大结果数目
maxResultLength = 10
# snippet length of the result
# 结果内容片段长度
snippetLength = 30
# HTML tag name of the highlight part in results
# 搜索结果中高亮部分的 HTML 标签
highlightTag = "em"
# whether to use the absolute URL based on the baseURL in search index
# 是否在搜索索引中使用基于 baseURL 的绝对路径
absoluteURL = false
[params.search.algolia]
index = "JS"
appID = "I74G1T3YFH"
searchKey = "9f39718c1951c948495770664edec6b8"
# Home page config
# 主页信息设置
[params.home]
# amount of RSS pages
# RSS 文章数目
rss = 10
# Home page profile
# 主页个人信息
[params.home.profile]
enable = true
# Gravatar Email for preferred avatar in home page
# Gravatar 邮箱,用于优先在主页显示的头像
gravatarEmail = ""
# URL of avatar shown in home page
# 主页显示头像的 URL
avatarURL = "./posts/cover.jpg"
# title shown in home page (HTML format is supported)
# 主页显示的网站标题 (支持 HTML 格式)
# title = "
"
# subtitle shown in home page (HTML format is supported)
# 主页显示的网站副标题 (允许 HTML 格式)
subtitle = "《JavaScript 权威指南第七版》中英对照"
# whether to use typeit animation for subtitle
# 是否为副标题显示打字机动画
typeit = true
# whether to show social links
# 是否显示社交账号
social = true
# disclaimer (HTML format is supported)
# 免责声明 (支持 HTML 格式)
disclaimer = ""
# Home page posts
# 主页文章列表
[params.home.posts]
enable = true
# special amount of posts in each home posts page
# 主页每页显示文章数量
paginate = 6
# Social config in home page
# 主页的社交信息设置
[params.social]
GitHub = "ten-ltw"
Linkedin = ""
Twitter = ""
Instagram = "ten_is_studing"
Facebook = ""
Telegram = ""
Medium = ""
Gitlab = ""
Youtubelegacy = ""
Youtubecustom = ""
Youtubechannel = ""
Tumblr = ""
Quora = ""
Keybase = ""
Pinterest = ""
Reddit = ""
Codepen = ""
FreeCodeCamp = ""
Bitbucket = ""
Stackoverflow = ""
Weibo = ""
Odnoklassniki = ""
VK = ""
Flickr = ""
Xing = ""
Snapchat = ""
Soundcloud = ""
Spotify = ""
Bandcamp = ""
Paypal = ""
Fivehundredpx = ""
Mix = ""
Goodreads = ""
Lastfm = ""
Foursquare = ""
Hackernews = ""
Kickstarter = ""
Patreon = ""
Steam = ""
Twitch = ""
Strava = ""
Skype = ""
Whatsapp = ""
Zhihu = "dan-ke-58-70"
Douban = ""
Angellist = ""
Slidershare = ""
Jsfiddle = ""
Deviantart = ""
Behance = ""
Dribbble = ""
Wordpress = ""
Vine = ""
Googlescholar = ""
Researchgate = ""
Mastodon = ""
Thingiverse = ""
Devto = ""
Gitea = ""
XMPP = ""
Matrix = ""
Bilibili = ""
Discord = ""
DiscordInvite = ""
Lichess = ""
ORCID = ""
Pleroma = ""
Kaggle = ""
Email = "li.tw.ten@gmail.com"
Phone = ""
RSS = ""
# Page global config
# 文章页面全局配置
[params.page]
# whether to hide a page from home page
# 是否在主页隐藏一篇文章
hiddenFromHomePage = false
# whether to hide a page from search results
# 是否在搜索结果中隐藏一篇文章
hiddenFromSearch = false
# whether to enable twemoji
# 是否使用 twemoji
twemoji = false
# whether to enable lightgallery
# 是否使用 lightgallery
lightgallery = false
# whether to enable the ruby extended syntax
# 是否使用 ruby 扩展语法
ruby = true
# whether to enable the fraction extended syntax
# 是否使用 fraction 扩展语法
fraction = true
# whether to enable the fontawesome extended syntax
# 是否使用 fontawesome 扩展语法
fontawesome = true
# whether to show link to Raw Markdown content of the content
# 是否显示原始 Markdown 文档内容的链接
linkToMarkdown = true
# whether to show the full text content in RSS
# 是否在 RSS 中显示全文内容
rssFullText = false
# Table of the contents config
# 目录配置
[params.page.toc]
# whether to enable the table of the contents
# 是否使用目录
enable = true
# whether to keep the static table of the contents in front of the post
# 是否保持使用文章前面的静态目录
keepStatic = false
# whether to make the table of the contents in the sidebar automatically collapsed
# 是否使侧边目录自动折叠展开
auto = true
# Code config
# 代码配置
[params.page.code]
# whether to show the copy button of the code block
# 是否显示代码块的复制按钮
copy = true
# the maximum number of lines of displayed code by default
# 默认展开显示的代码行数
maxShownLines = 50
# KaTeX mathematical formulas config (KaTeX https://katex.org/)
# KaTeX 数学公式配置 (KaTeX https://katex.org/)
[params.page.math]
enable = false
# default inline delimiter is $ ... $ and \( ... \)
# 默认行内定界符是 $ ... $ 和 \( ... \)
inlineLeftDelimiter = ""
inlineRightDelimiter = ""
# default block delimiter is $$ ... $$, \[ ... \], \begin{equation} ... \end{equation} and some other functions
# 默认块定界符是 $$ ... $$, \[ ... \], \begin{equation} ... \end{equation} 和一些其它的函数
blockLeftDelimiter = ""
blockRightDelimiter = ""
# KaTeX extension copy_tex
# KaTeX 插件 copy_tex
copyTex = true
# KaTeX extension mhchem
# KaTeX 插件 mhchem
mhchem = true
# Mapbox GL JS config (Mapbox GL JS https://docs.mapbox.com/mapbox-gl-js)
# Mapbox GL JS 配置 (Mapbox GL JS https://docs.mapbox.com/mapbox-gl-js)
[params.page.mapbox]
# access token of Mapbox GL JS
# Mapbox GL JS 的 access token
accessToken = ""
# style for the light theme
# 浅色主题的地图样式
lightStyle = "mapbox://styles/mapbox/light-v10?optimize=true"
# style for the dark theme
# 深色主题的地图样式
darkStyle = "mapbox://styles/mapbox/dark-v10?optimize=true"
# whether to add NavigationControl (https://docs.mapbox.com/mapbox-gl-js/api/#navigationcontrol)
# 是否添加 NavigationControl (https://docs.mapbox.com/mapbox-gl-js/api/#navigationcontrol)
navigation = true
# whether to add GeolocateControl (https://docs.mapbox.com/mapbox-gl-js/api/#geolocatecontrol)
# 是否添加 GeolocateControl (https://docs.mapbox.com/mapbox-gl-js/api/#geolocatecontrol)
geolocate = true
# whether to add ScaleControl (https://docs.mapbox.com/mapbox-gl-js/api/#scalecontrol)
# 是否添加 ScaleControl (https://docs.mapbox.com/mapbox-gl-js/api/#scalecontrol)
scale = true
# whether to add FullscreenControl (https://docs.mapbox.com/mapbox-gl-js/api/#fullscreencontrol)
# 是否添加 FullscreenControl (https://docs.mapbox.com/mapbox-gl-js/api/#fullscreencontrol)
fullscreen = true
# Social share links in post page
# 文章页面的分享信息设置
[params.page.share]
enable = true
Twitter = true
Facebook = true
Linkedin = false
Whatsapp = false
Pinterest = false
Tumblr = false
HackerNews = true
Reddit = false
VK = false
Buffer = false
Xing = false
Line = true
Instapaper = false
Pocket = false
Flipboard = false
Weibo = true
Blogger = false
Baidu = false
Odnoklassniki = false
Evernote = false
Skype = false
Trello = false
Mix = false
# Comment config
# 评论系统设置
[params.page.comment]
enable = false
# Disqus comment config (https://disqus.com/)
# Disqus 评论系统设置 (https://disqus.com/)
[params.page.comment.disqus]
enable = false
# Disqus shortname to use Disqus in posts
# Disqus 的 shortname,用来在文章中启用 Disqus 评论系统
shortname = ""
# Gitalk comment config (https://github.com/gitalk/gitalk)
# Gitalk 评论系统设置 (https://github.com/gitalk/gitalk)
[params.page.comment.gitalk]
enable = false
owner = ""
repo = ""
clientId = ""
clientSecret = ""
# Valine comment config (https://github.com/xCss/Valine)
# Valine 评论系统设置 (https://github.com/xCss/Valine)
[params.page.comment.valine]
enable = false
appId = ""
appKey = ""
placeholder = ""
avatar = "mp"
meta= ""
pageSize = 10
# automatically adapt the current theme i18n configuration when empty
# 为空时自动适配当前主题 i18n 配置
lang = ""
visitor = true
recordIP = true
highlight = true
enableQQ = false
serverURLs = ""
# emoji data file name, default is "google.yml"
# ["apple.yml", "google.yml", "facebook.yml", "twitter.yml"]
# located in "themes/LoveIt/assets/lib/valine/emoji/" directory
# you can store your own data files in the same path under your project:
# "assets/lib/valine/emoji/"
# emoji 数据文件名称, 默认是 "google.yml"
# ["apple.yml", "google.yml", "facebook.yml", "twitter.yml"]
# 位于 "themes/LoveIt/assets/lib/valine/emoji/" 目录
# 可以在你的项目下相同路径存放你自己的数据文件:
# "assets/lib/valine/emoji/"
emoji = ""
# Facebook comment config (https://developers.facebook.com/docs/plugins/comments)
# Facebook 评论系统设置 (https://developers.facebook.com/docs/plugins/comments)
[params.page.comment.facebook]
enable = false
width = "100%"
numPosts = 10
appId = ""
# automatically adapt the current theme i18n configuration when empty
# 为空时自动适配当前主题 i18n 配置
languageCode = ""
# Telegram comments config (https://comments.app/)
# Telegram comments 评论系统设置 (https://comments.app/)
[params.page.comment.telegram]
enable = false
siteID = ""
limit = 5
height = ""
color = ""
colorful = true
dislikes = false
outlined = false
# Commento comment config (https://commento.io/)
# Commento comment 评论系统设置 (https://commento.io/)
[params.page.comment.commento]
enable = false
# utterances comment config (https://utteranc.es/)
# utterances comment 评论系统设置 (https://utteranc.es/)
[params.page.comment.utterances]
enable = false
# owner/repo
repo = ""
issueTerm = "pathname"
label = ""
lightTheme = "github-light"
darkTheme = "github-dark"
# giscus comment config (https://giscus.app/)
# giscus comment 评论系统设置 (https://giscus.app/zh-CN)
[params.page.comment.giscus]
# You can refer to the official documentation of giscus to use the following configuration.
# 你可以参考官方文档来使用下列配置
enable = false
repo = ""
repoId = ""
category = "Announcements"
categoryId = ""
# automatically adapt the current theme i18n configuration when empty
# 为空时自动适配当前主题 i18n 配置
lang = ""
mapping = "pathname"
reactionsEnabled = "1"
emitMetadata = "0"
inputPosition = "bottom"
lazyLoading = false
lightTheme = "light"
darkTheme = "dark"
# Third-party library config
# 第三方库配置
[params.page.library]
[params.page.library.css]
# someCSS = "some.css"
# located in "assets/" 位于 "assets/"
# Or 或者
# someCSS = "https://cdn.example.com/some.css"
[params.page.library.js]
# someJavascript = "some.js"
# located in "assets/" 位于 "assets/"
# Or 或者
# someJavascript = "https://cdn.example.com/some.js"
# Page SEO config
# 页面 SEO 配置
[params.page.seo]
# image URL
# 图片 URL
images = []
# Publisher info
# 出版者信息
[params.page.seo.publisher]
name = ""
logoUrl = ""
# TypeIt config
# TypeIt 配置
[params.typeit]
# typing speed between each step (measured in milliseconds)
# 每一步的打字速度 (单位是毫秒)
speed = 100
# blinking speed of the cursor (measured in milliseconds)
# 光标的闪烁速度 (单位是毫秒)
cursorSpeed = 1000
# character used for the cursor (HTML format is supported)
# 光标的字符 (支持 HTML 格式)
cursorChar = "|"
# cursor duration after typing finishing (measured in milliseconds, "-1" means unlimited)
# 打字结束之后光标的持续时间 (单位是毫秒, "-1" 代表无限大)
duration = -1
# Site verification code for Google/Bing/Yandex/Pinterest/Baidu
# 网站验证代码,用于 Google/Bing/Yandex/Pinterest/Baidu
[params.verification]
google = ""
bing = ""
yandex = ""
pinterest = ""
baidu = ""
# Site SEO config
# 网站 SEO 配置
[params.seo]
# image URL
# 图片 URL
image = ""
# thumbnail URL
# 缩略图 URL
thumbnailUrl = ""
# Analytics config
# 网站分析配置
[params.analytics]
enable = true
# Google Analytics
[params.analytics.google]
id = "G-BK52F3N7KL"
# whether to anonymize IP
# 是否匿名化用户 IP
anonymizeIP = true
# Fathom Analytics
[params.analytics.fathom]
id = ""
# server url for your tracker if you're self hosting
# 自行托管追踪器时的主机路径
server = ""
# Plausible Analytics
[params.analytics.plausible]
dataDomain = ""
# Yandex Metrica
[params.analytics.yandexMetrica]
id = ""
# Cookie consent config
# Cookie 许可配置
[params.cookieconsent]
enable = false
# text strings used for Cookie consent banner
# 用于 Cookie 许可横幅的文本字符串
[params.cookieconsent.content]
message = ""
dismiss = ""
link = ""
# CDN config for third-party library files
# 第三方库文件的 CDN 设置
[params.cdn]
# CDN data file name, disabled by default
# ["jsdelivr.yml"]
# located in "themes/LoveIt/assets/data/cdn/" directory
# you can store your own data files in the same path under your project:
# "assets/data/cdn/"
# CDN 数据文件名称, 默认不启用
# ["jsdelivr.yml"]
# 位于 "themes/LoveIt/assets/data/cdn/" 目录
# 可以在你的项目下相同路径存放你自己的数据文件:
# "assets/data/cdn/"
data = "jsdelivr.yml"
# Compatibility config
# 兼容性设置
[params.compatibility]
# whether to use Polyfill.io to be compatible with older browsers
# 是否使用 Polyfill.io 来兼容旧式浏览器
polyfill = false
# whether to use object-fit-images to be compatible with older browsers
# 是否使用 object-fit-images 来兼容旧式浏览器
objectFit = false
[outputs]
home = ["HTML", "RSS", "JSON"]
================================================
FILE: content/posts/ch1.md
================================================
---
title: "第 1 章 JavaScript 概述"
date: 2020-11-02T22:18:42+08:00
---
JavaScript is the programming language of the web. The overwhelming majority of websites use JavaScript, and all modern web browsers—on desktops, tablets, and phones—include JavaScript interpreters, making JavaScript the most-deployed programming language in history. Over the last decade, Node.js has enabled JavaScript programming outside of web browsers, and the dramatic success of Node means that JavaScript is now also the most-used programming language among software developers. Whether you’re starting from scratch or are already using JavaScript professionally, this book will help you master the language.
> JavaScript 是 web 的编程语言。绝大多数的网站都使用 JavaScript,所有的现代网络浏览器——台式机、平板电脑和手机——都包括 JavaScript 解释器,这使得 JavaScript 成为历史上部署最多的编程语言。在过去的十年中,Node.js 使得 JavaScript 编程可以在 web 浏览器之外进行,Node 的巨大成功意味着 JavaScript 现在也是软件开发人员最常用的编程语言。无论你是从零开始还是已经开始专业地使用 JavaScript,这本书都会帮助你掌握这门语言。
If you are already familiar with other programming languages, it may help you to know that JavaScript is a high-level, dynamic, interpreted programming language that is well-suited to object-oriented and functional programming styles. JavaScript’s variables are untyped. Its syntax is loosely based on Java, but the languages are otherwise unrelated. JavaScript derives its first-class functions from Scheme and its prototype-based inheritance from the little-known language Self. But you do not need to know any of those languages, or be familiar with those terms, to use this book and learn JavaScript.
> 如果您已经熟悉了其他编程语言,那么了解 JavaScript 是一种高级的、动态的、解释的编程语言可能会对您有所帮助,它非常适合面向对象和函数式编程风格。JavaScript 的变量是无类型的。它的语法不严格地讲基于 Java,但是这两种语言在其他方面是无关的。JavaScript 的 first-class 类型函数衍生于 Scheme,从鲜为人知的 Self 继承基于原型的函数。但您不需要了解任何这些语言,或熟悉这些术语,以使用这本书和学习 JavaScript。
The name “JavaScript” is quite misleading. Except for a superficial syntactic resemblance, JavaScript is completely different from the Java programming language. And JavaScript has long since outgrown its scripting-language roots to become a robust and efficient general-purpose language suitable for serious software engineering and projects with huge codebases.
> “JavaScript”这个名称很容易引起误解。除了表面上的语法相似之外,JavaScript 与 Java 编程语言完全不同。而且 JavaScript 早已超越了它的脚本语言根基,成为一种健壮、高效的通用语言,适合于具有巨大代码库的严肃软件工程和项目。
#### JAVASCRIPT: NAMES, VERSIONS, AND MODES
JavaScript was created at Netscape in the early days of the web, and technically, “JavaScript” is a trademark licensed from Sun Microsystems (now Oracle) used to describe Netscape’s (now Mozilla’s) implementation of the language. Netscape submitted the language for standardization to ECMA—the European Computer Manufacturer’s Association—and because of trademark issues, the standardized version of the language was stuck with the awkward name “ECMAScript.” In practice, everyone just calls the language JavaScript. This book uses the name “ECMAScript” and the abbreviation “ES” to refer to the language standard and to versions of that standard.
> JavaScript 是在网络早期由网景公司创建的,从技术上讲,“JavaScript”是 Sun Microsystems(现在的 Oracle)授权的商标,用来描述 Netscape 公司(现在的Mozilla 公司)对该语言的实现。Netscape 公司将这种语言提交给欧洲计算机制造商协会(ecma)进行标准化,但由于商标问题,这种语言的标准化版本只能使用一个尴尬的名字“ECMAScript”。实际上,每个人都称这种语言为 JavaScript。本书使用名称“ECMAScript”和缩写“ES”来表示该语言标准和该标准的版本。
For most of the 2010s, version 5 of the ECMAScript standard has been supported by all web browsers. This book treats ES5 as the compatibility baseline and no longer discusses earlier versions of the language. ES6 was released in 2015 and added major new features—including class and module syntax—that changed JavaScript from a scripting language into a serious, general-purpose language suitable for large-scale software engineering. Since ES6, the ECMAScript specification has moved to a yearly release cadence, and versions of the language—ES2016, ES2017, ES2018, ES2019, and ES2020—are now identified by year of release.
> 对于2010年代的大多数版本,所有 web 浏览器都支持 ECMAScript 标准的第5版。本书将 ES5 作为兼容性基线,不再讨论该语言的早期版本。ES6 于2015年发布,增加了主要的新特性(包括类和模块语法),使 JavaScript 从一种脚本语言变成了一种严肃的、适用于大规模软件工程的通用语言。自 ES6 以来,ECMAScript 规范已经以每年发布一次为基调,该语言的版本——es2016、ES2017、ES2018、ES2019和es2020——现在以发布年份来确定。
As JavaScript evolved, the language designers attempted to correct flaws in the early (pre-ES5) versions. In order to maintain backward compatibility, it is not possible to remove legacy features, no matter how flawed. But in ES5 and later, programs can opt in to JavaScript’s strict mode in which a number of early language mistakes have been corrected. The mechanism for opting in is the “use strict” directive described in §5.6.3. That section also summarizes the differences between legacy JavaScript and strict JavaScript. In ES6 and later, the use of new language features often implicitly invokes strict mode. For example, if you use the ES6 class keyword or create an ES6 module, then all the code within the class or module is automatically strict, and the old, flawed features are not available in those contexts. This book will cover the legacy features of JavaScript but is careful to point out that they are not available in strict mode.
> 随着 JavaScript 的发展,语言设计者试图纠正早期版本(es5 之前)的缺陷。为了保持向后兼容性,不可能删除遗留特性,无论其缺陷有多大。但在 ES5 及以后版本中,程序可以选择使用 JavaScript 的严格模式,在这种模式中,早期的一些语言错误已经得到了纠正。选择加入的机制是 §5.6.3 中描述的“严格使用”指令。这一节还总结了传统 JavaScript 和严格 JavaScript 之间的区别。在 ES6 及以后版本中,使用新的语言特性通常会隐式地调用 strict 模式。例如,如果您使用 ES6 类关键字或创建 ES6 模块,那么类或模块中的所有代码将自动严格,并且在这些上下文中不能使用旧的、有缺陷的特性。这本书将涵盖 JavaScript 的遗留特性,但小心地指出,它们在严格模式下是不可用的。
To be useful, every language must have a platform, or standard library, for performing things like basic input and output. The core JavaScript language defines a minimal API for working with numbers, text, arrays, sets, maps, and so on, but does not include any input or output functionality. Input and output (as well as more sophisticated features, such as networking, storage, and graphics) are the responsibility of the “host environment” within which JavaScript is embedded.
> 每种语言都必须有一个平台或标准库来执行基本输入和输出之类的操作。核心 JavaScript 语言定义了一个极小的 API 处理数字、文本、数组、集合、映射等,但不包括任何输入或输出功能。输入和输出(以及更复杂的特性,如网络、存储和图形)由嵌入 JavaScript 的“宿主”负责。
The original host environment for JavaScript was a web browser, and this is still the most common execution environment for JavaScript code. The web browser environment allows JavaScript code to obtain input from the user’s mouse and keyboard and by making HTTP requests. And it allows JavaScript code to display output to the user with HTML and CSS.
> JavaScript 的原始宿主环境是一个 web 浏览器,这仍然是 JavaScript 代码最常见的执行环境。web 浏览器环境允许 JavaScript 代码通过发送 HTTP 请求从用户的鼠标和键盘获取输入。它允许 JavaScript 代码用 HTML 和 CSS 向用户显示输出。
Since 2010, another host environment has been available for JavaScript code. Instead of constraining JavaScript to work with the APIs provided by a web browser, Node gives JavaScript access to the entire operating system, allowing JavaScript programs to read and write files, send and receive data over the network, and make and serve HTTP requests. Node is a popular choice for implementing web servers and also a convenient tool for writing simple utility scripts as an alternative to shell scripts.
> 从2010年开始,另一个宿主已经可以用于 JavaScript 代码。Node 没有限制 JavaScript 使用 web 浏览器提供的 api,而是允许 JavaScript 访问整个操作系统,允许 JavaScript 程序读和写文件,通过网络发送和接收数据,以及发出和服务 HTTP 请求。Node 是实现 web 服务器的常用选择,也是编写简单实用程序脚本的方便工具,可以作为 shell 脚本的替代。
Most of this book is focused on the JavaScript language itself. Chapter 11 documents the JavaScript standard library, Chapter 15 introduces the web browser host environment, and Chapter 16 introduces the Node host environment.
> 这本书的大部分内容都集中在 JavaScript 语言本身。第 11 章介绍了 JavaScript 标准库,第 15 章介绍了 web 浏览器宿主,第 16 章介绍了 Node 宿主。
This book covers low-level fundamentals first, and then builds on those to more advanced and higher-level abstractions. The chapters are intended to be read more or less in order. But learning a new programming language is never a linear process, and describing a language is not linear either: each language feature is related to other features, and this book is full of cross-references—sometimes backward and sometimes forward—to related material. This introductory chapter makes a quick first pass through the language, introducing key features that will make it easier to understand the in-depth treatment in the chapters that follow. If you are already a practicing JavaScript programmer, you can probably skip this chapter. (Although you might enjoy reading Example 1-1 at the end of the chapter before you move on.)
> 这本书首先介绍了底层基础知识,然后在这些基础上构建更高级和更高级别的抽象。这些章节的目的是让读者或多或少地按顺序阅读。但是学习一种新的编程语言从来都不是一个线性的过程,描述一种语言也不是线性的:每一种语言的特性都与其他特性相关,这本书充满了交叉引用——有时向后,有时向前的相关材料。这一介绍性章节对该语言进行了一次快速的介绍,并介绍了一些关键特性,这些特性将使后续章节的深入处理更容易理解。如果你已经是一个实践 JavaScript 程序员,你可以跳过这一章。(尽管你可能会喜欢阅读本章末尾的示例 1-1,然后再继续阅读。)
## 1.1 Exploring JavaScript
When learning a new programming language, it’s important to try the examples in the book, then modify them and try them again to test your understanding of the language. To do that, you need a JavaScript interpreter.
> 在学习一门新的编程语言时,试一试书中的示例是很重要的,然后修改它们,再试一次来测试你对这门语言的理解。为此,需要一个 JavaScript 解释器。
The easiest way to try out a few lines of JavaScript is to open up the web developer tools in your web browser (with F12, Ctrl-Shift-I, or Command-Option-I) and select the Console tab. You can then type code at the prompt and see the results as you type. Browser developer tools often appear as panes at the bottom or right of the browser window, but you can usually detach them as separate windows (as pictured in Figure 1-1), which is often quite convenient.
> 尝试几行 JavaScript 的最简单方法是在web浏览器中打开 web developer 工具(使用 F12、Ctrl-Shift-I 或 Command-Option-I)并选择 Console 选项卡。然后可以在提示符处键入代码,并在键入时查看结果。浏览器开发人员工具通常以窗格的形式出现在浏览器窗口的底部或右侧,但是您通常可以将它们分离为单独的窗口(如图1-1所示),这通常非常方便。
The JavaScript console in Firefox’s Developer Tools
Another way to try out JavaScript code is to download and install Node from https://nodejs.org. Once Node is installed on your system, you can simply open a Terminal window and type node to begin an interactive JavaScript session like this one:
> 另一种尝试 JavaScript 代码的方法是从[https://nodejs.org](https://nodejs.org)下载并安装 Node。一旦在你的系统上安装了 Node,你可以简单地打开一个终端窗口,输入 Node 来开始一个交互式的 JavaScript 会话,就像这样:
```sh
$ node
Welcome to Node.js v12.13.0.
Type ".help" for more information.
> .help
.break Sometimes you get stuck, this gets you out
.clear Alias for .break
.editor Enter editor mode
.exit Exit the repl
.help Print this help message
.load Load JS from a file into the REPL session
.save Save all evaluated commands in this REPL session to a file
Press ^C to abort current expression, ^D to exit the repl
> let x = 2, y = 3;
undefined
> x + y
5
> (x === 2) && (y === 3)
true
> (x > 3) || (y < 3)
false
```
## 1.2 Hello World
When you are ready to start experimenting with longer chunks of code, these line-by-line interactive environments may no longer be suitable, and you will probably prefer to write your code in a text editor. From there, you can copy and paste to the JavaScript console or into a Node session. Or you can save your code to a file (the traditional filename extension for JavaScript code is .js) and then run that file of JavaScript code with Node:
> 当您准备开始尝试更长的代码块时,这些逐行交互环境可能不再适合,您可能更喜欢在文本编辑器中编写代码。从那里,您可以复制并粘贴到JavaScript控制台或节点会话中。或者你可以将你的代码保存到一个文件中(传统的 JavaScript 代码的文件名扩展名是 .js),然后用 Node 运行该 JavaScript 代码文件:
```sh
$ node snippet.js
```
If you use Node in a noninteractive manner like this, it won’t automatically print out the value of all the code you run, so you’ll have to do that yourself. You can use the function console.log() to display text and other JavaScript values in your terminal window or in a browser’s developer tools console. So, for example, if you create a hello.js file containing this line of code:
> 如果像这样以非交互的方式使用 Node,它不会自动打印出您运行的所有代码的值,因此您必须自己执行。可以使用 console.log() 函数在终端窗口或浏览器的 developer tools 控制台中显示文本和其他 JavaScript 值。因此,例如,如果你创建一个 hello.js 文件,其中包含这行代码:
```js
console.log("Hello World!");
```
and execute the file with node hello.js, you’ll see the message “Hello World!” printed out.
> 并执行 `node hello.js` ,你会看到消息“Hello World!”打印出来。
If you want to see that same message printed out in the JavaScript console of a web browser, create a new file named hello.html, and put this text in it:
> 如果您想在 web 浏览器的 JavaScript 控制台中看到同样的消息打印出来,那么创建一个名为 hello.html 的文件,并把这段文字放进去:
```js
```
Then load hello.html into your web browser using a `file://` URL like this one:
> 然后使用 `file://` URL将 hello.html 加载到浏览器中,如下图所示:
```
file:///Users/username/javascript/hello.html
```
Open the developer tools window to see the greeting in the console.
> 打开 developer tools 窗口,在控制台中查看问候语。
## 1.3 A Tour of JavaScript
This section presents a quick introduction, through code examples, to the JavaScript language. After this introductory chapter, we dive into JavaScript at the lowest level: Chapter 2 explains things like JavaScript comments, semicolons, and the Unicode character set. Chapter 3 starts to get more interesting: it explains JavaScript variables and the values you can assign to those variables.
> 本节通过代码示例快速介绍 JavaScript 语言。在这一介绍性章节之后,我们将深入到 JavaScript 的底层:第 2 章说明了 JavaScript 注释、分号和 Unicode 字符集等内容。第 3 章开始变得更有趣:它说明了 JavaScript 变量和你可以为这些变量赋值的值。
Here’s some sample code to illustrate the highlights of those two chapters:
> 下面是一些示例代码,演示这两章的重点内容:
```js
// Anything following double slashes is an English-language comment.
// Read the comments carefully: they explain the JavaScript code.
// A variable is a symbolic name for a value.
// Variables are declared with the let keyword:
let x; // Declare a variable named x.
// Values can be assigned to variables with an = sign
x = 0; // Now the variable x has the value 0
x // => 0: A variable evaluates to its value.
// JavaScript supports several types of values
x = 1; // Numbers.
x = 0.01; // Numbers can be integers or reals.
x = "hello world"; // Strings of text in quotation marks.
x = 'JavaScript'; // Single quote marks also delimit strings.
x = true; // A Boolean value.
x = false; // The other Boolean value.
x = null; // Null is a special value that means "no value."
x = undefined; // Undefined is another special value like null.
```
Two other very important types that JavaScript programs can manipulate are objects and arrays. These are the subjects of Chapters 6 and 7, but they are so important that you’ll see them many times before you reach those chapters:
> JavaScript 程序可以操作的另外两种非常重要的类型是对象和数组。这些是第 6 章和第 7 章的主题,但它们非常重要,在你读到这些章节之前,你会多次看到它们:
```js
// JavaScript's most important datatype is the object.
// An object is a collection of name/value pairs, or a string to value map.
let book = { // Objects are enclosed in curly braces.
topic: "JavaScript", // The property "topic" has value "JavaScript."
edition: 7 // The property "edition" has value 7
}; // The curly brace marks the end of the object.
// Access the properties of an object with . or []:
book.topic // => "JavaScript"
book["edition"] // => 7: another way to access property values.
book.author = "Flanagan"; // Create new properties by assignment.
book.contents = {}; // {} is an empty object with no properties.
// Conditionally access properties with ?. (ES2020):
book.contents?.ch01?.sect1 // => undefined: book.contents has no ch01 property.
// JavaScript also supports arrays (numerically indexed lists) of values:
let primes = [2, 3, 5, 7]; // An array of 4 values, delimited with [ and ].
primes[0] // => 2: the first element (index 0) of the array.
primes.length // => 4: how many elements in the array.
primes[primes.length-1] // => 7: the last element of the array.
primes[4] = 9; // Add a new element by assignment.
primes[4] = 11; // Or alter an existing element by assignment.
let empty = []; // [] is an empty array with no elements.
empty.length // => 0
// Arrays and objects can hold other arrays and objects:
let points = [ // An array with 2 elements.
{x: 0, y: 0}, // Each element is an object.
{x: 1, y: 1}
];
let data = { // An object with 2 properties
trial1: [[1,2], [3,4]], // The value of each property is an array.
trial2: [[2,3], [4,5]] // The elements of the arrays are arrays.
};
```
#### COMMENT SYNTAX IN CODE EXAMPLES
You may have noticed in the preceding code that some of the comments begin with an arrow (=>). These show the value produced by the code before the comment and are my attempt to emulate an interactive JavaScript environment like a web browser console in a printed book.
> 您可能已经注意到,在前面的代码中,一些注释以箭头开头(=>)。这些代码显示了注释之前代码产生的值,我试图模拟交互式 JavaScript 环境,就像印刷书籍中的 web 浏览器控制台一样。
Those // => comments also serve as an assertion, and I’ve written a tool that tests the code and verifies that it produces the value specified in the comment. This should help, I hope, to reduce errors in the book.
> 那些 // => 注释也用作断言,我编写了一个工具来测试代码并验证它是否生成注释中指定的值。我希望这有助于减少书中的错误。
There are two related styles of comment/assertion. If you see a comment of the form // a == 42, it means that after the code before the comment runs, the variable a will have the value 42. If you see a comment of the form // !, it means that the code on the line before the comment throws an exception (and the rest of the comment after the exclamation mark usually explains what kind of exception is thrown).
> 注释和断言有两种相关的风格。如果您看到 `// a == 42` 形式的注释,这意味着在注释运行之前的代码之后,变量a的值将是42。如果您看到 `// !` 形式的注释,这意味着注释前一行的代码抛出一个异常(感叹号之后的注释的其余部分通常解释抛出的是哪种异常)。
You’ll see these comments used throughout the book.
> 您将在整本书中看到这些注释。
The syntax illustrated here for listing array elements within square braces or mapping object property names to property values inside curly braces is known as an initializer expression, and it is just one of the topics of Chapter 4. An expression is a phrase of JavaScript that can be evaluated to produce a value. For example, the use of . and [] to refer to the value of an object property or array element is an expression.
> 这里演示的在方括号内列出数组元素或在花括号内将对象属性名映射到属性值的语法称为初始化表达式,它只是第 4 章的主题之一。表达式是 JavaScript 的一个短语,可以计算它来产生一个值。例如,的使用。和 [] 引用对象属性或数组元素的值是一个表达式。
One of the most common ways to form expressions in JavaScript is to use operators:
> 在 JavaScript 中形成表达式最常见的方法之一是使用运算符:
```js
// Operators act on values (the operands) to produce a new value.
// Arithmetic operators are some of the simplest:
3 + 2 // => 5: addition
3 - 2 // => 1: subtraction
3 * 2 // => 6: multiplication
3 / 2 // => 1.5: division
points[1].x - points[0].x // => 1: more complicated operands also work
"3" + "2" // => "32": + adds numbers, concatenates strings
// JavaScript defines some shorthand arithmetic operators
let count = 0; // Define a variable
count++; // Increment the variable
count--; // Decrement the variable
count += 2; // Add 2: same as count = count + 2;
count *= 3; // Multiply by 3: same as count = count * 3;
count // => 6: variable names are expressions, too.
// Equality and relational operators test whether two values are equal,
// unequal, less than, greater than, and so on. They evaluate to true or false.
let x = 2, y = 3; // These = signs are assignment, not equality tests
x === y // => false: equality
x !== y // => true: inequality
x < y // => true: less-than
x <= y // => true: less-than or equal
x > y // => false: greater-than
x >= y // => false: greater-than or equal
"two" === "three" // => false: the two strings are different
"two" > "three" // => true: "tw" is alphabetically greater than "th"
false === (x > y) // => true: false is equal to false
// Logical operators combine or invert boolean values
(x === 2) && (y === 3) // => true: both comparisons are true. && is AND
(x > 3) || (y < 3) // => false: neither comparison is true. || is OR
!(x === y) // => true: ! inverts a boolean value
```
If JavaScript expressions are like phrases, then JavaScript statements are like full sentences. Statements are the topic of Chapter 5. Roughly, an expression is something that computes a value but doesn’t do anything: it doesn’t alter the program state in any way. Statements, on the other hand, don’t have a value, but they do alter the state. You’ve seen variable declarations and assignment statements above. The other broad category of statement is control structures, such as conditionals and loops. You’ll see examples below, after we cover functions.
> 如果 JavaScript 表达式像短语,那么 JavaScript 语句就像完整的句子。这部分是第 5 章的主题。粗略地说,表达式不做任何事情只计算一个值:它不以任何方式改变程序状态。另一方面,语句没有值,但是它们可以改变状态。您已经在上面看到了变量声明和赋值语句。语句的另一大类是控制结构,比如条件语句和循环。在介绍函数之后,您将看到下面的示例。
A function is a named and parameterized block of JavaScript code that you define once, and can then invoke over and over again. Functions aren’t covered formally until Chapter 8, but like objects and arrays, you’ll see them many times before you get to that chapter. Here are some simple examples:
> 函数是一个已命名和参数化的 JavaScript 代码块,您只定义一次,然后可以反复调用它。函数直到第 8 章才正式介绍,但就像对象和数组一样,在进入这一章之前,您将多次看到它们。下面是一些简单的例子:
```js
// Functions are parameterized blocks of JavaScript code that we can invoke.
function plus1(x) { // Define a function named "plus1" with parameter "x"
return x + 1; // Return a value one larger than the value passed in
} // Functions are enclosed in curly braces
plus1(y) // => 4: y is 3, so this invocation returns 3+1
let square = function(x) { // Functions are values and can be assigned to vars
return x * x; // Compute the function's value
}; // Semicolon marks the end of the assignment.
square(plus1(y)) // => 16: invoke two functions in one expression
```
In ES6 and later, there is a shorthand syntax for defining functions. This concise syntax uses => to separate the argument list from the function body, so functions defined this way are known as arrow functions. Arrow functions are most commonly used when you want to pass an unnamed function as an argument to another function. The preceding code looks like this when rewritten to use arrow functions:
> 在 ES6 及以后版本中,有一种用于定义函数的快捷语法。这种简洁的语法使用 => 将参数列表与函数体分开,因此以这种方式定义的函数称为箭头函数。当您希望将一个未命名的函数作为参数传递给另一个函数时,最常用的是箭头函数。前面的代码看起来像这样,当重写使用箭头函数:
```js
const plus1 = x => x + 1; // The input x maps to the output x + 1
const square = x => x * x; // The input x maps to the output x * x
plus1(y) // => 4: function invocation is the same
square(plus1(y)) // => 16
```
When we use functions with objects, we get methods:
> 当我们使用函数和对象时,我们得到方法:
```js
// When functions are assigned to the properties of an object, we call
// them "methods." All JavaScript objects (including arrays) have methods:
let a = []; // Create an empty array
a.push(1,2,3); // The push() method adds elements to an array
a.reverse(); // Another method: reverse the order of elements
// We can define our own methods, too. The "this" keyword refers to the object
// on which the method is defined: in this case, the points array from earlier.
points.dist = function() { // Define a method to compute distance between points
let p1 = this[0]; // First element of array we're invoked on
let p2 = this[1]; // Second element of the "this" object
let a = p2.x-p1.x; // Difference in x coordinates
let b = p2.y-p1.y; // Difference in y coordinates
return Math.sqrt(a*a + // The Pythagorean theorem
b*b); // Math.sqrt() computes the square root
};
points.dist() // => Math.sqrt(2): distance between our 2 points
```
Now, as promised, here are some functions whose bodies demonstrate common JavaScript control structure statements:
> 现在,如前所述,下面是一些函数,它们的主体演示了常见的 JavaScript 控制结构语句:
```js
// JavaScript statements include conditionals and loops using the syntax
// of C, C++, Java, and other languages.
function abs(x) { // A function to compute the absolute value.
if (x >= 0) { // The if statement...
return x; // executes this code if the comparison is true.
} // This is the end of the if clause.
else { // The optional else clause executes its code if
return -x; // the comparison is false.
} // Curly braces optional when 1 statement per clause.
} // Note return statements nested inside if/else.
abs(-10) === abs(10) // => true
function sum(array) { // Compute the sum of the elements of an array
let sum = 0; // Start with an initial sum of 0.
for(let x of array) { // Loop over array, assigning each element to x.
sum += x; // Add the element value to the sum.
} // This is the end of the loop.
return sum; // Return the sum.
}
sum(primes) // => 28: sum of the first 5 primes 2+3+5+7+11
function factorial(n) { // A function to compute factorials
let product = 1; // Start with a product of 1
while(n > 1) { // Repeat statements in {} while expr in () is true
product *= n; // Shortcut for product = product * n;
n--; // Shortcut for n = n - 1
} // End of loop
return product; // Return the product
}
factorial(4) // => 24: 1*4*3*2
function factorial2(n) { // Another version using a different loop
let i, product = 1; // Start with 1
for(i=2; i <= n; i++) // Automatically increment i from 2 up to n
product *= i; // Do this each time. {} not needed for 1-line loops
return product; // Return the factorial
}
factorial2(5) // => 120: 1*2*3*4*5
```
JavaScript supports an object-oriented programming style, but it is significantly different than “classical” object-oriented programming languages. Chapter 9 covers object-oriented programming in JavaScript in detail, with lots of examples. Here is a very simple example that demonstrates how to define a JavaScript class to represent 2D geometric points. Objects that are instances of this class have a single method, named distance(), that computes the distance of the point from the origin:
> JavaScript 支持面向对象的编程风格,但它与“经典的”面向对象编程语言有显著的不同。第 9 章详细介绍了 JavaScript 的面向对象编程,并提供了很多示例。下面是一个非常简单的示例,演示了如何定义一个 JavaScript 类来表示 2D 几何点。作为这个类的实例的对象有一个名为 distance() 的方法,它计算点到原点的距离:
```js
class Point { // By convention, class names are capitalized.
constructor(x, y) { // Constructor function to initialize new instances.
this.x = x; // This keyword is the new object being initialized.
this.y = y; // Store function arguments as object properties.
} // No return is necessary in constructor functions.
distance() { // Method to compute distance from origin to point.
return Math.sqrt( // Return the square root of x² + y².
this.x * this.x + // this refers to the Point object on which
this.y * this.y // the distance method is invoked.
);
}
}
// Use the Point() constructor function with "new" to create Point objects
let p = new Point(1, 1); // The geometric point (1,1).
// Now use a method of the Point object p
p.distance() // => Math.SQRT2
```
This introductory tour of JavaScript’s fundamental syntax and capabilities ends here, but the book continues with self-contained chapters that cover additional features of the language:
> 关于 JavaScript 基本语法和能力的介绍到此结束,但这本书继续以自成体系的章节介绍该语言的其他特性:
Chapter 10, Modules
Shows how JavaScript code in one file or script can use JavaScript functions and classes defined in other files or scripts.
> 演示一个文件或脚本中的 JavaScript 代码如何使用在其他文件或脚本中定义的 JavaScript 函数和类。
Chapter 11, The JavaScript Standard Library
Covers the built-in functions and classes that are available to all JavaScript programs. This includes important data stuctures like maps and sets, a regular expression class for textual pattern matching, functions for serializing JavaScript data structures, and much more.
> 介绍所有 JavaScript 程序可用的内置函数和类。这包括重要的数据结构,如映射和集合、用于文本模式匹配的正则表达式类、用于序列化 JavaScript 数据结构的函数等等。
Chapter 12, Iterators and Generators
Explains how the for/of loop works and how you can make your own classes iterable with for/of. It also covers generator functions and the yield statement.
> 解释 for/of 循环是如何工作的,以及如何使用 for/of 使您自己的类可迭代。它还包括生成器函数和 yield 语句。
Chapter 13, Asynchronous JavaScript
This chapter is an in-depth exploration of asynchronous programming in JavaScript, covering callbacks and events, Promise-based APIs, and the async and await keywords. Although the core JavaScript language is not asynchronous, asynchronous APIs are the default in both web browsers and Node, and this chapter explains the techniques for working with those APIs.
> 本章对 JavaScript 中的异步编程进行了深入的探索,涵盖了回调和事件、基于承诺的 api 以及异步和等待关键字。尽管核心 JavaScript 语言不是异步的,异步 api 在 web 浏览器和节点中都是默认的,本章解释了使用这些 api 的技术。
Chapter 14, Metaprogramming
Introduces a number of advanced features of JavaScript that may be of interest to programmers writing libraries of code for other JavaScript programmers to use.
> 介绍了 JavaScript 的许多高级特性,编写代码库供其他 JavaScript 程序员使用的程序员可能会对这些特性感兴趣。
Chapter 15, JavaScript in Web Browsers
Introduces the web browser host environment, explains how web browsers execute JavaScript code, and covers the most important of the many APIs defined by web browsers. This is by far the longest chapter in the book.
> 介绍 web 浏览器宿主,解释 web 浏览器如何执行 JavaScript 代码,并涵盖 web 浏览器定义的许多 api 中最重要的一个。这是书中最长的一章。
Chapter 16, Server-Side JavaScript with Node
Introduces the Node host environment, covering the fundamental programming model and the data structures and APIs that are most important to understand.
> 介绍 Node 宿主,涵盖基本编程模型以及需要理解的最重要的数据结构和 api。
Chapter 17, JavaScript Tools and Extensions
Covers tools and language extensions that are worth knowing about because they are widely used and may make you a more productive programmer.
> 涵盖了值得了解的工具和语言扩展,因为它们被广泛使用,可能使您成为更有生产力的程序员。
## 1.4 Example: Character Frequency Histograms
This chapter concludes with a short but nontrivial JavaScript program. Example 1-1 is a Node program that reads text from standard input, computes a character frequency histogram from that text, and then prints out the histogram. You could invoke the program like this to analyze the character frequency of its own source code:
> 本章以一个简短但不平凡的 JavaScript 程序结束。示例 1-1 是一个节点程序,它从标准输入中读取文本,根据文本计算字符频率直方图,然后打印该直方图。你可以调用这样的程序来分析字符频率自己的源代码:
```sh
$ node charfreq.js < charfreq.js
T: ########### 11.22%
E: ########## 10.15%
R: ####### 6.68%
S: ###### 6.44%
A: ###### 6.16%
N: ###### 5.81%
O: ##### 5.45%
I: ##### 4.54%
H: #### 4.07%
C: ### 3.36%
L: ### 3.20%
U: ### 3.08%
/: ### 2.88%
```
This example uses a number of advanced JavaScript features and is intended to demonstrate what real-world JavaScript programs can look like. You should not expect to understand all of the code yet, but be assured that all of it will be explained in the chapters that follow.
> 这个示例使用了许多高级 JavaScript 特性,旨在演示真实的 JavaScript 程序是什么样的。你不应该期望理解所有的代码,但是要确保所有的代码将在下面的章节中被解释。
Example 1-1. Computing character frequency histograms with JavaScript
```js
/**
* This Node program reads text from standard input, computes the frequency
* of each letter in that text, and displays a histogram of the most
* frequently used characters. It requires Node 12 or higher to run.
*
* In a Unix-type environment you can invoke the program like this:
* node charfreq.js < corpus.txt
*/
// This class extends Map so that the get() method returns the specified
// value instead of null when the key is not in the map
class DefaultMap extends Map {
constructor(defaultValue) {
super(); // Invoke superclass constructor
this.defaultValue = defaultValue; // Remember the default value
}
get(key) {
if (this.has(key)) { // If the key is already in the map
return super.get(key); // return its value from superclass.
}
else {
return this.defaultValue; // Otherwise return the default value
}
}
}
// This class computes and displays letter frequency histograms
class Histogram {
constructor() {
this.letterCounts = new DefaultMap(0); // Map from letters to counts
this.totalLetters = 0; // How many letters in all
}
// This function updates the histogram with the letters of text.
add(text) {
// Remove whitespace from the text, and convert to upper case
text = text.replace(/\s/g, "").toUpperCase();
// Now loop through the characters of the text
for(let character of text) {
let count = this.letterCounts.get(character); // Get old count
this.letterCounts.set(character, count+1); // Increment it
this.totalLetters++;
}
}
// Convert the histogram to a string that displays an ASCII graphic
toString() {
// Convert the Map to an array of [key,value] arrays
let entries = [...this.letterCounts];
// Sort the array by count, then alphabetically
entries.sort((a,b) => { // A function to define sort order.
if (a[1] === b[1]) { // If the counts are the same
return a[0] < b[0] ? -1 : 1; // sort alphabetically.
} else { // If the counts differ
return b[1] - a[1]; // sort by largest count.
}
});
// Convert the counts to percentages
for(let entry of entries) {
entry[1] = entry[1] / this.totalLetters*100;
}
// Drop any entries less than 1%
entries = entries.filter(entry => entry[1] >= 1);
// Now convert each entry to a line of text
let lines = entries.map(
([l,n]) => `${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%`
);
// And return the concatenated lines, separated by newline characters.
return lines.join("\n");
}
}
// This async (Promise-returning) function creates a Histogram object,
// asynchronously reads chunks of text from standard input, and adds those chunks to
// the histogram. When it reaches the end of the stream, it returns this histogram
async function histogramFromStdin() {
process.stdin.setEncoding("utf-8"); // Read Unicode strings, not bytes
let histogram = new Histogram();
for await (let chunk of process.stdin) {
histogram.add(chunk);
}
return histogram;
}
// This one final line of code is the main body of the program.
// It makes a Histogram object from standard input, then prints the histogram.
histogramFromStdin().then(histogram => { console.log(histogram.toString()); });
```
## 1.5 Summary
This book explains JavaScript from the bottom up. This means that we start with low-level details like comments, identifiers, variables, and types; then build to expressions, statements, objects, and functions; and then cover high-level language abstractions like classes and modules. I take the word definitive in the title of this book seriously, and the coming chapters explain the language at a level of detail that may feel off-putting at first. True mastery of JavaScript requires an understanding of the details, however, and I hope that you will make time to read this book cover to cover. But please don’t feel that you need to do that on your first reading. If you find yourself feeling bogged down in a section, simply skip to the next. You can come back and master the details once you have a working knowledge of the language as a whole.
> 这本书从下至上地说明了 JavaScript。这意味着我们从底层细节开始,比如注释、标识符、变量和类型;然后构建表达式、语句、对象和函数;然后介绍高级语言抽象,比如类和模块。我在这本书的标题中认真地使用了“权威”这个词,接下来的章节会详细地解释这种语言,一开始可能会让人感到不快。然而,真正掌握 JavaScript 需要了解细节,我希望您能抽出时间从头到尾阅读这本书。但请不要觉得在第一次阅读时就需要这样做。如果你发现自己在某个章节陷入困境,直接跳到下一个章节。一旦你对语言有了整体的应用知识,你可以回过头来掌握细节。
================================================
FILE: content/posts/ch10.md
================================================
---
title: "第 10 章 模块"
date: 2020-11-02T22:18:33+08:00
---
The goal of modular programming is to allow large programs to be assembled using modules of code from disparate authors and sources and for all of that code to run correctly even in the presence of code that the various module authors did not anticipate. As a practical matter, modularity is mostly about encapsulating or hiding private implementation details and keeping the global namespace tidy so that modules cannot accidentally modify the variables, functions, and classes defined by other modules.
> 模块化编程的目标是允许使用来自不同作者和源的代码模块来组装大型程序,并且即使出现了不同模块作者没有预料到的代码,所有这些代码也能正确运行。作为一个实际问题,模块化主要是关于封装或隐藏私有实现细节和保持全局名称空间整洁,以便模块不会意外地修改其他模块定义的变量、函数和类。
Until recently, JavaScript had no built-in support for modules, and programmers working on large code bases did their best to use the weak modularity available through classes, objects, and closures. Closure-based modularity, with support from code-bundling tools, led to a practical form of modularity based on a require() function, which was adopted by Node. require()-based modules are a fundamental part of the Node programming environment but were never adopted as an official part of the JavaScript language. Instead, ES6 defines modules using import and export keywords. Although import and export have been part of the language for years, they were only implemented by web browsers and Node relatively recently. And, as a practical matter, JavaScript modularity still depends on code-bundling tools.
> 直到最近,JavaScript 还没有对模块的内置支持,在大型代码库上工作的程序员尽力使用类、对象和闭包的弱模块性。基于闭包的模块化在代码捆绑工具的支持下,实际使用中形成了一种基于 require() 函数的模块化形式,Node 采用了这种形式。基于 require() 的模块是 Node 编程环境的基本部分,但从未被作为 JavaScript 语言的正式部分采用。相反,ES6 使用 import 和 import 关键字定义模块。虽然 import 和 export 已经成为语言的一部分很多年了,但是它们只是最近才被 web 浏览器和 Node 实现。而且,作为一个实际问题,JavaScript 模块化仍然依赖于代码捆绑工具。
The sections that follow cover:
> 以下各节包括:
- Do-it-yourself modules with classes, objects, and closures
- Node modules using require()
- ES6 modules using export, import, and import()
---
> - 使用类、对象和闭包自己做模块
> - 使用 require() 的 Node 模块
> - 使用 export、import 和 import() 的ES6模块
## 10.1 Modules with Classes, Objects, and Closures
Though it may be obvious, it is worth pointing out that one of the important features of classes is that they act as modules for their methods. Think back to Example 9-8. That example defined a number of different classes, all of which had a method named has(). But you would have no problem writing a program that used multiple set classes from that example: there is no danger that the implementation of has() from SingletonSet will overwrite the has() method of BitSet, for example.
> 尽管这可能很明显,但值得指出的是,类的重要特性之一是它们充当其方法的模块。回想一下示例 9-8。该示例定义了许多不同的类,所有这些类都有一个名为 has() 的方法。但是,在编写使用该示例中的多个 set 类的程序时没有问题:例如,SingletonSet 的 has() 实现不会覆盖 BitSet 的 has() 方法。
The reason that the methods of one class are independent of the methods of other, unrelated classes is that the methods of each class are defined as properties of independent prototype objects. The reason that classes are modular is that objects are modular: defining a property in a JavaScript object is a lot like declaring a variable, but adding properties to objects does not affect the global namespace of a program, nor does it affect the properties of other objects. JavaScript defines quite a few mathematical functions and constants, but instead of defining them all globally, they are grouped as properties of a single global Math object. This same technique could have been used in Example 9-8. Instead of defining global classes with names like SingletonSet and BitSet, that example could have been written to define only a single global Sets object, with properties referencing the various classes. Users of this Sets library could then refer to the classes with names like Sets.Singleton and Sets.Bit.
> 一个类的方法独立于其他不相关类的方法的原因是,每个类的方法都被定义为独立原型对象的属性。类是模块化的原因是对象是模块化的:在 JavaScript 对象中定义属性非常类似于声明变量,但是向对象添加属性不会影响程序的全局命名空间,也不会影响其他对象的属性。JavaScript 定义了很多数学函数和常量,但它们不是全局定义的,而是分组为 Math 全局对象的单个属性。同样的技术也可以用在示例 9-8 中。不使用 SingletonSet 和 BitSet 这样的名称定义全局类,这个示例可以编写为只有一个 Sets 全局对象,Sets 的属性引用各种类。然后,用户可以使用这个 Sets 库通过 Sets.Singleton 和 Sets.Bit 的名称来获取类的引用。
Using classes and objects for modularity is a common and useful technique in JavaScript programming, but it doesn’t go far enough. In particular, it doesn’t offer us any way to hide internal implementation details inside the module. Consider Example 9-8 again. If we were writing that example as a module, maybe we would have wanted to keep the various abstract classes internal to the module, only making the concrete subclasses available to users of the module. Similarly, in the BitSet class, the _valid() and _has() methods are internal utilities that should not really be exposed to users of the class. And BitSet.bits and BitSet.masks are implementation details that would be better off hidden.
> 使用类和对象实现模块化是 JavaScript 编程中常见而有用的技术,但这还不够。特别是,它没有提供任何方法来隐藏模块内部的实现细节。再次考虑示例 9-8。如果我们将该示例作为一个模块来编写,也许我们会希望将各种抽象类保留在模块内部,只让具体的子类对模块的用户可用。同样,在 BitSet 类中,_valid() 和 _has() 方法是内部实用程序,不应该向类的用户公开它们。BitSet.bits 和 BitSet.masks 是实现细节,最好隐藏起来。
As we saw in §8.6, local variables and nested functions declared within a function are private to that function. This means that we can use immediately invoked function expressions to achieve a kind of modularity by leaving the implementation details and utility functions hidden within the enclosing function but making the public API of the module the return value of the function. In the case of the BitSet class, we might structure the module like this:
> 正如我们在 §8.6 中看到的,在函数中声明的局部变量和嵌套函数是该函数私有的。这意味着我们可以使用立即调用函数表达式来实现一种模块化,方法是将实现细节和实用函数隐藏在封装的函数中,而将模块的公共 API 作为函数的返回值。在 BitSet 类的情况下,我们可以像这样构造模块:
```js
const BitSet = (function() { // Set BitSet to the return value of this function
// Private implementation details here
function isValid(set, n) { ... }
function has(set, byte, bit) { ... }
const BITS = new Uint8Array([1, 2, 4, 8, 16, 32, 64, 128]);
const MASKS = new Uint8Array([~1, ~2, ~4, ~8, ~16, ~32, ~64, ~128]);
// The public API of the module is just the BitSet class, which we define
// and return here. The class can use the private functions and constants
// defined above, but they will be hidden from users of the class
return class BitSet extends AbstractWritableSet {
// ... implementation omitted ...
};
}());
```
This approach to modularity becomes a little more interesting when the module has more than one item in it. The following code, for example, defines a mini statistics module that exports mean() and stddev() functions while leaving the implementation details hidden:
> 当模块中有多个条目时,这种模块化方法就变得更有趣了。例如,下面的代码定义了一个迷你统计模块,它导出 mean() 和 stddev() 函数,同时隐藏实现细节:
```js
// This is how we could define a stats module
const stats = (function() {
// Utility functions private to the module
const sum = (x, y) => x + y;
const square = x => x * x;
// A public function that will be exported
function mean(data) {
return data.reduce(sum)/data.length;
}
// A public function that we will export
function stddev(data) {
let m = mean(data);
return Math.sqrt(
data.map(x => x - m).map(square).reduce(sum)/(data.length-1)
);
}
// We export the public function as properties of an object
return { mean, stddev };
}());
// And here is how we might use the module
stats.mean([1, 3, 5, 7, 9]) // => 5
stats.stddev([1, 3, 5, 7, 9]) // => Math.sqrt(10)
```
### 10.1.1 Automating Closure-Based Modularity
Note that it is a fairly mechanical process to transform a file of JavaScript code into this kind of module by inserting some text at the beginning and end of the file. All that is needed is some convention for the file of JavaScript code to indicate which values are to be exported and which are not.
> 请注意,通过在文件的开头和结尾插入一些文本来将 JavaScript 代码文件转换为这种模块是相当机械的过程。所需要做的只是为 JavaScript 代码文件提供一些约定,以指示要导出的值和不导出的值。
Imagine a tool that takes a set of files, wraps the content of each of those files within an immediately invoked function expression, keeps track of the return value of each function, and concatenates everything into one big file. The result might look something like this:
> 想象一下一个工具,它需要一组文件,将每个文件的内容包装在立即调用的函数表达式中,跟踪每个函数的返回值,并将所有内容连接到一个大文件中。结果可能看起来像这样:
```js
const modules = {};
function require(moduleName) { return modules[moduleName]; }
modules["sets.js"] = (function() {
const exports = {};
// The contents of the sets.js file go here:
exports.BitSet = class BitSet { ... };
return exports;
}());
modules["stats.js"] = (function() {
const exports = {};
// The contents of the stats.js file go here:
const sum = (x, y) => x + y;
const square = x = > x * x;
exports.mean = function(data) { ... };
exports.stddev = function(data) { ... };
return exports;
}());
```
With modules bundled up into a single file like the one shown in the preceding example, you can imagine writing code like the following to make use of those modules:
> 如上一个示例所示,将模块捆绑到单个文件中,可以想象编写如下代码来利用这些模块:
```js
// Get references to the modules (or the module content) that we need
const stats = require("stats.js");
const BitSet = require("sets.js").BitSet;
// Now write code using those modules
let s = new BitSet(100);
s.insert(10);
s.insert(20);
s.insert(30);
let average = stats.mean([...s]); // average is 20
```
This code is a rough sketch of how code-bundling tools (such as webpack and Parcel) for web browsers work, and it’s also a simple introduction to the require() function like the one used in Node programs.
> 这段代码概述了用于网络浏览器的代码捆绑工具(例如 webpack 和 Parcel)的工作方式,并且是对 require() 函数(如 Node 程序中使用的函数)的简单介绍。
## 10.2 Modules in Node
In Node programming, it is normal to split programs into as many files as seems natural. These files of JavaScript code are assumed to all live on a fast filesystem. Unlike web browsers, which have to read files of JavaScript over a relatively slow network connection, there is no need or benefit to bundling a Node program into a single JavaScript file.
In Node, each file is an independent module with a private namespace. Constants, variables, functions, and classes defined in one file are private to that file unless the file exports them. And values exported by one module are only visible in another module if that module explicitly imports them.
Node modules import other modules with the require() function and export their public API by setting properties of the Exports object or by replacing the module.exportsobject entirely.
### 10.2.1 Node Exports
Node defines a global exports object that is always defined. If you are writing a Node module that exports multiple values, you can simply assign them to the properties of this object:
```js
const sum = (x, y) => x + y;
const square = x => x * x;
exports.mean = data => data.reduce(sum)/data.length;
exports.stddev = function(d) {
let m = exports.mean(d);
return Math.sqrt(d.map(x => x - m).map(square).reduce(sum)/(d.length-1));
};
```
Often, however, you want to define a module that exports only a single function or class rather than an object full of functions or classes. To do this, you simply assign the single value you want to export to module.exports:
```js
module.exports = class BitSet extends AbstractWritableSet {
// implementation omitted
};
```
The default value of module.exports is the same object that exports refers to. In the previous stats module, we could have assigned the mean function to module.exports.mean instead of exports.mean. Another approach with modules like the stats module is to export a single object at the end of the module rather than exporting functions one by one as you go:
```js
// Define all the functions, public and private
const sum = (x, y) => x + y;
const square = x => x * x;
const mean = data => data.reduce(sum)/data.length;
const stddev = d => {
let m = mean(d);
return Math.sqrt(d.map(x => x - m).map(square).reduce(sum)/(d.length-1));
};
// Now export only the public ones
module.exports = { mean, stddev };
```
### 10.2.2 Node Imports
A Node module imports another module by calling the require() function. The argument to this function is the name of the module to be imported, and the return value is whatever value (typically a function, class, or object) that module exports.
If you want to import a system module built in to Node or a module that you have installed on your system via a package manager, then you simply use the unqualified name of the module, without any “/” characters that would turn it into a filesystem path:
```js
// These modules are built in to Node
const fs = require("fs"); // The built-in filesystem module
const http = require("http"); // The built-in HTTP module
// The Express HTTP server framework is a third-party module.
// It is not part of Node but has been installed locally
const express = require("express");
```
When you want to import a module of your own code, the module name should be the path to the file that contains that code, relative to the current module’s file. It is legal to use absolute paths that begin with a / character, but typically, when importing modules that are part of your own program, the module names will begin with ./ or sometimes ../ to indicate that they are relative to the current directory or the parent directory. For example:
```js
const stats = require('./stats.js');
const BitSet = require('./utils/bitset.js');
```
(You can also omit the .js suffix on the files you’re importing and Node will still find the files, but it is common to see these file extensions explicitly included.)
When a module exports just a single function or class, all you have to do is require it. When a module exports an object with multiple properties, you have a choice: you can import the entire object, or just import the specific properties (using destructuring assignment) of the object that you plan to use. Compare these two approaches:
```js
// Import the entire stats object, with all of its functions
const stats = require('./stats.js');
// We've got more functions than we need, but they're neatly
// organized into a convenient "stats" namespace.
let average = stats.mean(data);
// Alternatively, we can use idiomatic destructuring assignment to import
// exactly the functions we want directly into the local namespace:
const { stddev } = require('./stats.js');
// This is nice and succinct, though we lose a bit of context
// without the 'stats' prefix as a namspace for the stddev() function.
let sd = stddev(data);
```
### 10.2.3 Node-Style Modules on the Web
Modules with an Exports object and a require() function are built in to Node. But if you’re willing to process your code with a bundling tool like webpack, then it is also possible to use this style of modules for code that is intended to run in web browsers. Until recently, this was a very common thing to do, and you may see lots of web-based code that still does it.
> Node 中内置了带有 Exports 对象和 require() 函数的模块。 但是,如果要使用诸如 webpack 之类的捆绑工具来处理代码,则也可以将这种样式的模块用于要在网络浏览器中运行的代码。直到最近,这还是一种非常常用的做法,可能会看到很多基于 Web 的代码仍然这样做。
Now that JavaScript has its own standard module syntax, however, developers who use bundlers are more likely to use the official JavaScript modules with import and export statements.
> 现在,JavaScript 具有自己的标准模块语法,但是使用捆绑程序的开发人员更喜欢将正式的 JavaScript 模块与 import 和 export 语句一起使用。
## 10.3 Modules in ES6
ES6 adds import and export keywords to JavaScript and finally supports real modularity as a core language feature. ES6 modularity is conceptually the same as Node modularity: each file is its own module, and constants, variables, functions, and classes defined within a file are private to that module unless they are explicitly exported. Values that are exported from one module are available for use in modules that explicitly import them. ES6 modules differ from Node modules in the syntax used for exporting and importing and also in the way that modules are defined in web browsers. The sections that follow explain these things in detail.
> ES6 给 JavaScript 添加了 import 和 export 关键字,并且最终支持真正的模块化,将其作为核心语言特性。ES6 模块化概念上和 Node 的模块化相同:每个文件是它们自己的模块,定义在文件中的常量、变量、函数和类是模块私有成员,除非它们是被显示导出。
First, though, note that ES6 modules are also different from regular JavaScript “scripts” in some important ways. The most obvious difference is the modularity itself: in regular scripts, top-level declarations of variables, functions, and classes go into a single global context shared by all scripts. With modules, each file has its own private context and can use the import and export statements, which is the whole point, after all. But there are other differences between modules and scripts as well. Code inside an ES6 module (like code inside any ES6 class definition) is automatically in strict mode (see §5.6.3). This means that, when you start using ES6 modules, you’ll never have to write "use strict" again. And it means that code in modules cannot use the with statement or the arguments object or undeclared variables. ES6 modules are even slightly stricter than strict mode: in strict mode, in functions invoked as functions, this is undefined. In modules, this is undefined even in top-level code. (By contrast, scripts in web browsers and Node set this to the global object.)
> 首先,请注意,ES6 模块在某些重要方面也与常规 JavaScript “脚本”不同。最明显的区别是模块化本身:在常规脚本中,变量,函数和类的顶级声明在所有脚本共享的一个全局上下文中。模块每个文件都有其自己的专用上下文,并且可以使用 import 和 export 语句。但是模块和脚本之间也存在其他差异。ES6 模块内的代码(类似 ES6 类内定义的代码)将自动进入严格模式(请参见 §5.6.3)。这意味着,当使用 ES6 模块时,无需再写“use strict”。这意味着模块中的代码不能使用 with 语句或 arguments 对象或未声明的变量。ES6 模块甚至比严格模式稍微严格:在严格模式下,在作为函数调用的函数中,this 是 undefined。在模块中,this 在顶层代码中也是 undefined。(相比之下,Web 浏览器和 Node 中的脚本将 this 设置为全局对象。)
#### ES6 MODULES ON THE WEB AND IN NODE
ES6 modules have been in use on the web for years with the help of code bundlers like webpack, which combine independent modules of JavaScript code into large, non-modular bundles suitable for inclusion into web pages. At the time of this writing, however, ES6 modules are finally supported natively by all web browsers other than Internet Explorer. When used natively, ES6 modules are added into HTML pages with a special `
```
Code inside an inline `` tags. Here, for example, is an HTML file that includes a script tag with JavaScript code that dynamically updates one element of the document to make it behave like a digital clock:
```html
Digital Clock
Digital Clock
```
Although JavaScript code can be embedded directly within a `
```
A JavaScript file contains pure JavaScript, without `` tags. Note that the closing `` tag is required in HTML documents even when the src attribute is specified: HTML does not support a `` tag.
There are a number of advantages to using the src attribute:
- It simplifies your HTML files by allowing you to remove large blocks of JavaScript code from them—that is, it helps keep content and behavior separate.
- When multiple web pages share the same JavaScript code, using the src attribute allows you to maintain only a single copy of that code, rather than having to edit each HTML file when the code changes.
- If a file of JavaScript code is shared by more than one page, it only needs to be downloaded once, by the first page that uses it—subsequent pages can retrieve it from the browser cache.
- Because the src attribute takes an arbitrary URL as its value, a JavaScript program or web page from one web server can employ code exported by other web servers. Much internet advertising relies on this fact.
MODULES
§10.3 documents JavaScript modules and covers their import and export directives. If you have written your JavaScript program using modules (and have not used a code-bundling tool to combine all your modules into a single nonmodular file of JavaScript), then you must load the top-level module of your program with a `
```
Both the defer and async attributes are ways of telling the browser that the linked script does not use document.write() to generate HTML output, and that the browser, therefore, can continue to parse and render the document while downloading the script. The defer attribute causes the browser to defer execution of the script until after the document has been fully loaded and parsed and is ready to be manipulated. The async attribute causes the browser to run the script as soon as possible but does not block document parsing while the script is being downloaded. If a `
```
This two-line script extracts input from the “name” query parameter of the document URL. It then uses the DOM API to inject an HTML string into the first `
` tag in the document. This page is intended to be invoked with a URL like this:
```
http://www.example.com/greet.html?name=David
```
When used like this, it displays the text “Hello David.” But consider what happens when it is invoked with this query parameter:
```
name=%3Cimg%20src=%22x.png%22%20onload=%22alert(%27hacked%27)%22/%3E
```
When the URL-escaped parameters are decoded, this URL causes the following HTML to be injected into the document:
```
Hello
```
After the image loads, the string of JavaScript in the onload attribute is executed. The global alert() function displays a modal dialogue box. A single dialogue box is relatively benign but demonstrates that arbitrary code execution is possible on this site because it displays unsanitized HTML.
Cross-site scripting attacks are so called because more than one site is involved. Site B includes a specially crafted link (like the one in the previous example) to site A. If site B can convince users to click the link, they will be taken to site A, but that site will now be running code from site B. That code might deface the page or cause it to malfunction. More dangerously, the malicious code could read cookies stored by site A (perhaps account numbers or other personally identifying information) and send that data back to site B. The injected code could even track the user’s keystrokes and send that data back to site B.
In general, the way to prevent XSS attacks is to remove HTML tags from any untrusted data before using it to create dynamic document content. You can fix the greet.html file shown earlier by replacing special HTML characters in the untrusted input string with their equivalent HTML entities:
```js
name = name
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/\//g, "/")
```
Another approach to the problem of XSS is to structure your web applications so that untrusted content is always displayed in an `