├── 事件 ├── 第六章.md ├── DOM事件.md ├── 定时器.md ├── assets │ ├── old-radio.jpg │ ├── 1558824824647.png │ ├── 1562599371222.png │ ├── 1562626507612.png │ ├── 1562998447733.png │ ├── 1562999615730.png │ ├── 1563063890497.png │ ├── 1563326586026.png │ ├── 1563326700807.png │ ├── 1563326712428.png │ ├── 1563327353017.png │ ├── 1563327355516.png │ ├── 1563327994789.png │ ├── 1565500624871.png │ ├── 1565500672733.png │ ├── 1565500784247.png │ ├── 1565501845034.png │ ├── 1565503235616.png │ ├── 1565505025525.png │ ├── 1565506008086.png │ ├── 1565562799087.png │ ├── 1565563216094.png │ ├── 1565584162296.png │ ├── 1565584238135.png │ ├── 1565586248914.png │ ├── 1565590070635.png │ ├── 1565590445363.png │ ├── 1565600046914.png │ ├── 1565679212423.png │ ├── 1565682021275.png │ ├── 1565767500359.png │ ├── 1565771987739.png │ ├── 1565772422179.png │ ├── 1565853058826.png │ ├── 1565854628479.png │ ├── 1565854636619.png │ ├── 1566463506773.png │ └── javascript_sensors_yaw.jpg ├── 事件的细节.md ├── 移动设备事件.md ├── 事件初探.md └── HTML控件.md ├── 信息处理 ├── 二进制数据.md ├── 反应式编程.md ├── 正则表达式.md ├── 案例研究:编程语言.md ├── 算术表达式解析.md └── 模板.md ├── 软件开发 ├── 兼容性.md ├── 测试.md ├── 使用JavaScript库.md ├── 性能.md ├── reference.md ├── 模块化.md └── 国际化.md ├── 魔法世界 ├── 多线程.md ├── 音频处理.md ├── WebRTC.md ├── Web幻灯片.md ├── 再探HTML5.md ├── 图像处理.md └── 数据可视化.md ├── 新的征途 ├── Chrome 扩展.md ├── Electron.md ├── Node.js.md ├── 案例研究:聊天室.md ├── 案例研究:音乐播放器.md └── 自动化工作流.md ├── 附录 ├── Unicode指南.md ├── JavaScript语言参考.md └── 键码映射表.md ├── 分布式计算 ├── AJAX.md ├── 安全性.md ├── 互联网与信息传输.md ├── 客户端存储技术.md ├── 分布式应用程序.md ├── 数据交换格式.md └── 异步操作.md ├── 图形与动画 ├── Canvas.md ├── WebGL.md ├── 可伸缩矢量图形.md ├── 案例研究:画图工具.md ├── 级联样式表.md ├── 计算机图形.md └── 案例研究·波浪进度球.md ├── 设计原理 ├── 代理对象.md ├── Symbol和迭代器.assets │ └── 0054F331.png ├── assets │ └── freezeSealAndPreventExtensions.png ├── 装饰器.md ├── JavaScript标准对象.md ├── 类和原型.md ├── 求值策略.md └── Symbol和迭代器.md ├── 导出 ├── 第五章.pdf ├── 第四章.pdf ├── BOOK.docx ├── BOOK.pdf ├── 第三章.docx ├── 第五章.docx ├── 第四章.docx ├── JavaScript 艺术之旅.docx ├── ~$第五章.docx └── ~$第四章.docx ├── 函数 ├── assets │ ├── th.jpg │ ├── 1555713818684.png │ ├── 1555713844215.png │ ├── 1555713869213.png │ ├── 1556862479426.png │ └── th-1555712687236.jpg ├── 生成器函数.md ├── 第五章练习.md ├── 方法.md └── 函数和算法.md ├── BOOK.assets ├── 640.webp ├── 1800-census.jpg ├── 1552904604507.png ├── 1552905378968.png ├── 1552912887244.png ├── 1552999312562.png ├── 1552999360878.png ├── 1552999390567.png ├── 1553079227178.png ├── 1556836336765.png ├── 1558824325517.png ├── 1563330252149.png ├── 1563331271632.png ├── 1565929449193.png ├── 1565930786117.png ├── 1565932209076.png ├── 1565932212738.png ├── numbers-table.png ├── swimming-timetable.png ├── 2237281220-5898949183cc3_articlex.png └── F9B33FF24D7418356F52703587ED9922.jpg ├── BOOK └── image_165.png ├── 语句 ├── assets │ ├── 640.webp │ └── 1556836336765.png ├── 第四章练习.md ├── 异常处理.md ├── while和do-while语句.md ├── switch语句.md ├── if语句.md ├── for-in和for-of语句.md └── for语句.md ├── 数据 ├── assets │ ├── ieee754.jpg │ ├── 1565929449193.png │ ├── 1565930786117.png │ ├── 1565932209076.png │ ├── 1565932212738.png │ ├── bg2014121121-1.png │ └── 2237281220-5898949183cc3_articlex.png ├── 第三章练习.md ├── 数据类型.md ├── 解构赋值.md ├── 对象.md └── 逻辑.md ├── README.assets └── image_165.png ├── 启程 ├── assets │ ├── 1552904604507.png │ ├── 1552905378968.png │ ├── 1552912887244.png │ ├── 1552999312562.png │ ├── 1552999360878.png │ ├── 1552999390567.png │ ├── 1553079227178.png │ ├── 1553079359387.png │ └── 1558824325517.png ├── 第二章.assets │ ├── 1552904604507.png │ ├── 1552905378968.png │ ├── 1552912887244.png │ ├── 1552999312562.png │ ├── 1552999360878.png │ ├── 1552999390567.png │ ├── 1553079227178.png │ ├── 1558824325517.png │ ├── 1563330252149.png │ └── 1563331271632.png ├── 表达式与值.md ├── 更进一步.md ├── 命名的值.md ├── Hello-world.md └── HTML.md ├── 练习答案 └── 第四章.md ├── REFERENCE.md ├── SCRATCH.md ├── TODO.md ├── MOTTO.md ├── README.md └── 绪论 └── 绪论.md /事件/第六章.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /信息处理/二进制数据.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /信息处理/反应式编程.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /信息处理/正则表达式.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /软件开发/兼容性.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /软件开发/测试.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /魔法世界/多线程.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /魔法世界/音频处理.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /信息处理/案例研究:编程语言.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/Chrome 扩展.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/Electron.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/Node.js.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/案例研究:聊天室.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/案例研究:音乐播放器.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新的征途/自动化工作流.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /附录/Unicode指南.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /魔法世界/WebRTC.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /魔法世界/Web幻灯片.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /软件开发/使用JavaScript库.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /附录/JavaScript语言参考.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /信息处理/算术表达式解析.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /事件/DOM事件.md: -------------------------------------------------------------------------------- 1 | ## DOM 事件 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /软件开发/性能.md: -------------------------------------------------------------------------------- 1 | ## 似水流年·性能 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /分布式计算/AJAX.md: -------------------------------------------------------------------------------- 1 | ## 世界灯火·AJAX 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /分布式计算/安全性.md: -------------------------------------------------------------------------------- 1 | ## 避风港·安全策略 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /事件/定时器.md: -------------------------------------------------------------------------------- 1 | ## 定时器 2 | 3 | --- 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /图形与动画/Canvas.md: -------------------------------------------------------------------------------- 1 | ## 案例研究:小黄人动画 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/WebGL.md: -------------------------------------------------------------------------------- 1 | ## 俯仰自如·WebGL 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/可伸缩矢量图形.md: -------------------------------------------------------------------------------- 1 | ## 游刃有余·可伸缩矢量图形 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/案例研究:画图工具.md: -------------------------------------------------------------------------------- 1 | ## 案例研究:画图工具 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/级联样式表.md: -------------------------------------------------------------------------------- 1 | ## 绝世伴侣·级联样式表 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/计算机图形.md: -------------------------------------------------------------------------------- 1 | ## 眼见为实·计算机图形 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /分布式计算/互联网与信息传输.md: -------------------------------------------------------------------------------- 1 | # 让世界相连·互联网和信息传输 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /分布式计算/客户端存储技术.md: -------------------------------------------------------------------------------- 1 | ## 百代之过客·客户端存储技术 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /图形与动画/案例研究·波浪进度球.md: -------------------------------------------------------------------------------- 1 | ## 案例研究:波浪进度球 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /设计原理/代理对象.md: -------------------------------------------------------------------------------- 1 | ## 代理对象 2 | 3 | --- 4 | 5 | 什么是*代理对象*? 6 | 7 | -------------------------------------------------------------------------------- /导出/第五章.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/第五章.pdf -------------------------------------------------------------------------------- /导出/第四章.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/第四章.pdf -------------------------------------------------------------------------------- /导出/BOOK.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/BOOK.docx -------------------------------------------------------------------------------- /导出/BOOK.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/BOOK.pdf -------------------------------------------------------------------------------- /导出/第三章.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/第三章.docx -------------------------------------------------------------------------------- /导出/第五章.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/第五章.docx -------------------------------------------------------------------------------- /导出/第四章.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/第四章.docx -------------------------------------------------------------------------------- /函数/assets/th.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/th.jpg -------------------------------------------------------------------------------- /BOOK.assets/640.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/640.webp -------------------------------------------------------------------------------- /BOOK/image_165.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK/image_165.png -------------------------------------------------------------------------------- /语句/assets/640.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/语句/assets/640.webp -------------------------------------------------------------------------------- /数据/assets/ieee754.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/ieee754.jpg -------------------------------------------------------------------------------- /事件/assets/old-radio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/old-radio.jpg -------------------------------------------------------------------------------- /导出/JavaScript 艺术之旅.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/导出/JavaScript 艺术之旅.docx -------------------------------------------------------------------------------- /BOOK.assets/1800-census.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1800-census.jpg -------------------------------------------------------------------------------- /README.assets/image_165.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/README.assets/image_165.png -------------------------------------------------------------------------------- /事件/assets/1558824824647.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1558824824647.png -------------------------------------------------------------------------------- /事件/assets/1562599371222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1562599371222.png -------------------------------------------------------------------------------- /事件/assets/1562626507612.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1562626507612.png -------------------------------------------------------------------------------- /事件/assets/1562998447733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1562998447733.png -------------------------------------------------------------------------------- /事件/assets/1562999615730.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1562999615730.png -------------------------------------------------------------------------------- /事件/assets/1563063890497.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563063890497.png -------------------------------------------------------------------------------- /事件/assets/1563326586026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563326586026.png -------------------------------------------------------------------------------- /事件/assets/1563326700807.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563326700807.png -------------------------------------------------------------------------------- /事件/assets/1563326712428.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563326712428.png -------------------------------------------------------------------------------- /事件/assets/1563327353017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563327353017.png -------------------------------------------------------------------------------- /事件/assets/1563327355516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563327355516.png -------------------------------------------------------------------------------- /事件/assets/1563327994789.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1563327994789.png -------------------------------------------------------------------------------- /事件/assets/1565500624871.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565500624871.png -------------------------------------------------------------------------------- /事件/assets/1565500672733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565500672733.png -------------------------------------------------------------------------------- /事件/assets/1565500784247.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565500784247.png -------------------------------------------------------------------------------- /事件/assets/1565501845034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565501845034.png -------------------------------------------------------------------------------- /事件/assets/1565503235616.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565503235616.png -------------------------------------------------------------------------------- /事件/assets/1565505025525.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565505025525.png -------------------------------------------------------------------------------- /事件/assets/1565506008086.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565506008086.png -------------------------------------------------------------------------------- /事件/assets/1565562799087.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565562799087.png -------------------------------------------------------------------------------- /事件/assets/1565563216094.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565563216094.png -------------------------------------------------------------------------------- /事件/assets/1565584162296.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565584162296.png -------------------------------------------------------------------------------- /事件/assets/1565584238135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565584238135.png -------------------------------------------------------------------------------- /事件/assets/1565586248914.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565586248914.png -------------------------------------------------------------------------------- /事件/assets/1565590070635.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565590070635.png -------------------------------------------------------------------------------- /事件/assets/1565590445363.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565590445363.png -------------------------------------------------------------------------------- /事件/assets/1565600046914.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565600046914.png -------------------------------------------------------------------------------- /事件/assets/1565679212423.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565679212423.png -------------------------------------------------------------------------------- /事件/assets/1565682021275.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565682021275.png -------------------------------------------------------------------------------- /事件/assets/1565767500359.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565767500359.png -------------------------------------------------------------------------------- /事件/assets/1565771987739.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565771987739.png -------------------------------------------------------------------------------- /事件/assets/1565772422179.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565772422179.png -------------------------------------------------------------------------------- /事件/assets/1565853058826.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565853058826.png -------------------------------------------------------------------------------- /事件/assets/1565854628479.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565854628479.png -------------------------------------------------------------------------------- /事件/assets/1565854636619.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1565854636619.png -------------------------------------------------------------------------------- /事件/assets/1566463506773.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/1566463506773.png -------------------------------------------------------------------------------- /函数/assets/1555713818684.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/1555713818684.png -------------------------------------------------------------------------------- /函数/assets/1555713844215.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/1555713844215.png -------------------------------------------------------------------------------- /函数/assets/1555713869213.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/1555713869213.png -------------------------------------------------------------------------------- /函数/assets/1556862479426.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/1556862479426.png -------------------------------------------------------------------------------- /启程/assets/1552904604507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552904604507.png -------------------------------------------------------------------------------- /启程/assets/1552905378968.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552905378968.png -------------------------------------------------------------------------------- /启程/assets/1552912887244.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552912887244.png -------------------------------------------------------------------------------- /启程/assets/1552999312562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552999312562.png -------------------------------------------------------------------------------- /启程/assets/1552999360878.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552999360878.png -------------------------------------------------------------------------------- /启程/assets/1552999390567.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1552999390567.png -------------------------------------------------------------------------------- /启程/assets/1553079227178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1553079227178.png -------------------------------------------------------------------------------- /启程/assets/1553079359387.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1553079359387.png -------------------------------------------------------------------------------- /启程/assets/1558824325517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/assets/1558824325517.png -------------------------------------------------------------------------------- /数据/assets/1565929449193.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/1565929449193.png -------------------------------------------------------------------------------- /数据/assets/1565930786117.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/1565930786117.png -------------------------------------------------------------------------------- /数据/assets/1565932209076.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/1565932209076.png -------------------------------------------------------------------------------- /数据/assets/1565932212738.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/1565932212738.png -------------------------------------------------------------------------------- /语句/assets/1556836336765.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/语句/assets/1556836336765.png -------------------------------------------------------------------------------- /BOOK.assets/1552904604507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552904604507.png -------------------------------------------------------------------------------- /BOOK.assets/1552905378968.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552905378968.png -------------------------------------------------------------------------------- /BOOK.assets/1552912887244.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552912887244.png -------------------------------------------------------------------------------- /BOOK.assets/1552999312562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552999312562.png -------------------------------------------------------------------------------- /BOOK.assets/1552999360878.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552999360878.png -------------------------------------------------------------------------------- /BOOK.assets/1552999390567.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1552999390567.png -------------------------------------------------------------------------------- /BOOK.assets/1553079227178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1553079227178.png -------------------------------------------------------------------------------- /BOOK.assets/1556836336765.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1556836336765.png -------------------------------------------------------------------------------- /BOOK.assets/1558824325517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1558824325517.png -------------------------------------------------------------------------------- /BOOK.assets/1563330252149.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1563330252149.png -------------------------------------------------------------------------------- /BOOK.assets/1563331271632.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1563331271632.png -------------------------------------------------------------------------------- /BOOK.assets/1565929449193.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1565929449193.png -------------------------------------------------------------------------------- /BOOK.assets/1565930786117.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1565930786117.png -------------------------------------------------------------------------------- /BOOK.assets/1565932209076.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1565932209076.png -------------------------------------------------------------------------------- /BOOK.assets/1565932212738.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/1565932212738.png -------------------------------------------------------------------------------- /BOOK.assets/numbers-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/numbers-table.png -------------------------------------------------------------------------------- /函数/assets/th-1555712687236.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/函数/assets/th-1555712687236.jpg -------------------------------------------------------------------------------- /数据/assets/bg2014121121-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/bg2014121121-1.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552904604507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552904604507.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552905378968.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552905378968.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552912887244.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552912887244.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552999312562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552999312562.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552999360878.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552999360878.png -------------------------------------------------------------------------------- /启程/第二章.assets/1552999390567.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1552999390567.png -------------------------------------------------------------------------------- /启程/第二章.assets/1553079227178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1553079227178.png -------------------------------------------------------------------------------- /启程/第二章.assets/1558824325517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1558824325517.png -------------------------------------------------------------------------------- /启程/第二章.assets/1563330252149.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1563330252149.png -------------------------------------------------------------------------------- /启程/第二章.assets/1563331271632.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/启程/第二章.assets/1563331271632.png -------------------------------------------------------------------------------- /BOOK.assets/swimming-timetable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/swimming-timetable.png -------------------------------------------------------------------------------- /设计原理/Symbol和迭代器.assets/0054F331.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/设计原理/Symbol和迭代器.assets/0054F331.png -------------------------------------------------------------------------------- /事件/assets/javascript_sensors_yaw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/事件/assets/javascript_sensors_yaw.jpg -------------------------------------------------------------------------------- /数据/assets/2237281220-5898949183cc3_articlex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/数据/assets/2237281220-5898949183cc3_articlex.png -------------------------------------------------------------------------------- /设计原理/assets/freezeSealAndPreventExtensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/设计原理/assets/freezeSealAndPreventExtensions.png -------------------------------------------------------------------------------- /BOOK.assets/2237281220-5898949183cc3_articlex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/2237281220-5898949183cc3_articlex.png -------------------------------------------------------------------------------- /BOOK.assets/F9B33FF24D7418356F52703587ED9922.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanpero/JavaScript-Art-Tour/HEAD/BOOK.assets/F9B33FF24D7418356F52703587ED9922.jpg -------------------------------------------------------------------------------- /导出/~$第五章.docx: -------------------------------------------------------------------------------- 1 | alphaxuan a l p h a x u a n -------------------------------------------------------------------------------- /导出/~$第四章.docx: -------------------------------------------------------------------------------- 1 | alphaxuan a l p h a x u a n -------------------------------------------------------------------------------- /信息处理/模板.md: -------------------------------------------------------------------------------- 1 | ## 模板 2 | 3 | --- 4 | 5 | ### 模板引擎的概念 6 | 7 | 8 | 9 | 10 | 11 | ### Handlebars.js 模板引擎 12 | 13 | 14 | 15 | 16 | 17 | ### Dust.js 模板引擎 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /分布式计算/分布式应用程序.md: -------------------------------------------------------------------------------- 1 | ## 光阴逆旅·分布式应用程序 2 | 3 | --- 4 | 5 | ### 统一资源标识符 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### 表征状态传输 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### GraphQL 22 | 23 | -------------------------------------------------------------------------------- /事件/事件的细节.md: -------------------------------------------------------------------------------- 1 | ## 芥子纳须弥·事件的细节 2 | 3 | --- 4 | 5 | ### 事件捕获与冒泡 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### 默认操作 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### 事件队列 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /分布式计算/数据交换格式.md: -------------------------------------------------------------------------------- 1 | ## 殊途同归·数据交换格式 2 | 3 | --- 4 | 5 | ### 纯文本 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### XML 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### JSON 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### YAML 30 | 31 | -------------------------------------------------------------------------------- /分布式计算/异步操作.md: -------------------------------------------------------------------------------- 1 | ## 鱼跃龙门·异步操作 2 | 3 | --- 4 | 5 | ### 初探 Promise 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### 深入 Promise 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### async 和 await 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### 使用异步操作的 API -------------------------------------------------------------------------------- /魔法世界/再探HTML5.md: -------------------------------------------------------------------------------- 1 | ## 互通有无·再探 HTML5 2 | 3 | --- 4 | 5 | ### 多媒体 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### 地理定位 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### 多线程和消息传递 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### 离线缓存 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ### 一些有用的技术 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /软件开发/reference.md: -------------------------------------------------------------------------------- 1 | ## 参考文献 2 | 3 | --- 4 | 5 | 1. *Internationalization and localization*, https://en.wikipedia.org/wiki/Internationalization_and_localization 6 | 2. *Hanunuo Script*, https://en.wikipedia.org/wiki/Hanunuo_script 7 | 3. *IETF BCP 47*, https://tools.ietf.org/pdf/bcp47.pdf 8 | 4. *Intl.PluralRules Spec Proposal*, https://rawgit.com/caridy/intl-plural-rules-spec/master/index.html -------------------------------------------------------------------------------- /数据/第三章练习.md: -------------------------------------------------------------------------------- 1 | ## 练习题 2 | 3 | --- 4 | 5 | 1. 世界范围内人们使用两种温度计量方式,一种是摄氏度($$^{\circ}C$$),它的意义是:在标准大气压下,将水结冰的温度记为 0 ℃,而水沸腾的温度则为 100 ℃。另一种是华氏度(℉),其意义是:以水银为测温介质,将氯化铵和冰水的混合物的开始结冰的温度作为 0 ℉,人体温度为 100 ℉。 6 | 7 | 设摄氏度为 $$C$$,华氏度为 $$F$$,则它们的相互转换公式如下: 8 | 9 | $$ F = C \times1.8 +32 $$ 10 | 11 | $$ C=(F-32) \div 1.8 $$ 12 | 13 | 写一个程序,提示用户输入温度值,并将其进行转换。 14 | 15 | 16 | 17 | 2. 18 | 19 | 20 | -------------------------------------------------------------------------------- /魔法世界/图像处理.md: -------------------------------------------------------------------------------- 1 | ## 鹰瞵鹗视·图像处理 2 | 3 | --- 4 | 5 | ### 格式与原理 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ### 裁剪与拉伸 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### 调整颜色 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### 简单视觉效果 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ### 元信息 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ### 复杂处理 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /练习答案/第四章.md: -------------------------------------------------------------------------------- 1 | 5. ```javascript 2 | let n = parseInt(prompt("请输入一个正整数:")); 3 | let info = "你输入的数是:" + n + "\n"; 4 | while (n !== 1) { 5 | if (n % 2 === 0) { 6 | info += n + " 是一个偶数,将它除以 2 得到 "; 7 | n /= 2; 8 | info += n + "\n"; 9 | } else { 10 | info += n + " 是一个奇数,将它乘以 3 再加 1 得到 "; 11 | n *= 3; 12 | n += 1; 13 | info += n + "\n"; 14 | } 15 | } 16 | alert(info); 17 | ``` 18 | 19 | 6. -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | - .Jeremy Keith, Jeffrey Sambells. *DOM Scripting: Web Design with JavaScript and the Document Object Model, Second Edition*. Berkeley. Apress L.P.. 2010. 2 | - John Resig, Bear Bibeault, Josip Maras. *JavaScript Ninja, Second Edition*. Greenwich. Manning Publications Co. .2016. 3 | - Eric S. Roberts. *Programming Abstractions in C++*. Standford. Pearson Education, Inc.. 2014. 4 | - Steve Fulton, Jeff Fulton. *HTML5 Canvas, Second Edition*, 8bitrocket Studios. O`Reilly. 2013 5 | - Mark E. Daggett. *Expert JavaScript*. Apress Media. 2013. 6 | - Den Odell. *Pro JavaScript Development: Coding, Capabilities, and Tooling*. Berkeley. Apress L.P.. 2014. 7 | - Lü Zhihua. *Pro D3.js: High-level programming of interactive Data visualization*. Beijing. Electronic Industry Press. 2015. 8 | 9 | -------------------------------------------------------------------------------- /SCRATCH.md: -------------------------------------------------------------------------------- 1 | # Scratch 2 | 3 | --- 4 | 5 | 记录一些想法。 6 | 7 | 8 | 9 | 绪论会从互联网的诞生开始,经历洪荒时代、JavaScript 的诞生、浏览器大战、W3C 标准、ECMAScript 标准的发展、一直到当下最前沿的 JavaScript 周边技术,包括 WebGL、React Native、WebAssembly 等都会浮光掠影一番。 10 | 11 | 全书零散添加一些历史小故事。 12 | 13 | - HTML 的发展历程。 14 | - JavaScript 服务端的历史和 Node.js 的成功故事。 15 | - JavaScript Linter 的演变。 16 | - 前端库和框架的演变。 17 | - JavaScript 引擎的进化。 18 | 19 | 20 | 21 | 附录里添加一篇编辑器和开发环境选择指南。 22 | 23 | - Visual Studio Code 24 | - Atom 25 | - Bracket 26 | - WebStorm 27 | - Sublime Text 28 | - Notepad++ 29 | - EditPlus 30 | - Vim 31 | - Emacs 32 | - Nano 33 | 34 | 35 | 36 | 第九章 37 | 38 | - 介绍了客户端与服务器的概念后,快速搭建一个简易服务器以进行后续示例。 39 | 40 | 41 | 42 | 第十四章 43 | 44 | - Node.js:编写一个聊天应用。 45 | - Electron:编写一个音乐播放器。 46 | - Ionic:编写一个天气应用。 47 | -------------------------------------------------------------------------------- /函数/生成器函数.md: -------------------------------------------------------------------------------- 1 | ## 生成器函数 2 | 3 | --- 4 | 5 | 请想象一台机器,一台只存在于我们深邃思想之中的机器。你问它一个问题,它就会悄悄运作一番,给我们一个答案,然后就在静默中无声地等待着,直到我们再一次唤醒它,向它提问。和其他机器不同,每次向它提问时,它都留存着上一次思索的记忆。每一个回答都可能独一无二,每一个回答也一定有一个内在的秩序,这秩序以精妙的设计存在于机器的思想中,只有它和创造它的我们知晓。 6 | 7 | 这台机器已经在 JavaScript 世界中被制造出来了,它的名字叫*生成器函数*(Generator Function),这个名字使人想起工厂里流水化的生产线,批量地制造新产品。而生成器函数的确就像流水线上的机器,每次运作,都生成一个值,然后这个值被送到我们面前,然后经过一些时刻生成下一个值。生成器函数在本质上,是一种调用一次而多次返回一个值的函数,而普通函数调用一次只能返回一次。 8 | 9 | 因此,生成器函数是一种特殊类型的函数。当我们从头到尾运行标准函数时,我们最多只会得到一次值,这个值保存了函数在这次运行中所留给我们的所有东西。然而生成器函数不同的地方在于,它是可以在运行过程中暂停的,每次暂停都可以返回一个值。生成器函数能生成一组值的序列,当我们“要求”它生成一个值的时候,它就生成一个值,然后在运行过程中暂停在所处的位置。如果它不再打算生成新的值,就会告诉我们它的运行周期已经结束了。 10 | 11 | 12 | 13 | --- 14 | 15 | Note: 16 | 17 | 生成器函数是 JavaScript 中一个相对较新的概念和特性,其实它已经在 Python、PHP 和 C# 等编程语言中存在很长时间了,它常常被用来实现一种称为*协程*的语言机制。生成器函数的本质是*状态机*。 18 | 19 | --- 20 | 21 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # TODO 4 | 5 | --- 6 | 7 | 暂时保留的待办事项列表。 8 | 9 | 10 | 11 | --- 12 | 13 | - 全局 14 | 15 | - [ ] 为每一章添加课后练习 16 | 17 | - [ ] 为每一章添加参考文献 18 | 19 | - [ ] 为每一节添加小结 20 | 21 | - 第二章 22 | 23 | - [ ] 更新第二章的运行器截图 24 | 25 | - [ ] 在第二章的 表达式 一节中加入关于十六进制和二进制的概念 26 | 27 | - [ ] 完成第二章的 HTML 一节相关内容 28 | 29 | 简要介绍 HTML 和在 HTML 中使用 JavaScript 的方式 30 | 31 | - 第三章 32 | 33 | - [x] 完成第三章的 数值 一节剩余内容 34 | - [x] 完成第三章的 模式匹配 一节 35 | - [x] 完成第三章的 字符串 一节中关于字符串操作的剩余内容 36 | - [x] 完成第三章的 数组 一节中关于数组操作的剩余内容 37 | - [x] 添加标签模板字符串相关内容(新的函数调用形式) 38 | - [x] 添加第三章中 对象 一节中有关 `this` 的说明 39 | - [ ] 添加 ECMAScript 6 的设置对象字面量中属性名的新语法 40 | 41 | - 第四章 42 | 43 | - [x] 在第四章的 for语句 一节中,增加数组遍历相关内容 44 | - [ ] 在第四章中添加有关 块级作用域 的内容 45 | 46 | - 第五章 47 | - [ ] 完成 生成器函数 一节 48 | - [ ] 完成 高级主题:函数式编程 一节 49 | - [ ] 完成 递归 一节剩余内容 50 | - [ ] 完成 高阶函数 一节中关于数组方法 `reduce`、`filter` 的解释 51 | - [x] 完成 高阶函数 一节中关于闭包的阐述 52 | 53 | - 第七章 54 | 55 | - [ ] 将 迭代协议 一节中有关迭代器的内容移到可迭代对象之前 56 | -------------------------------------------------------------------------------- /软件开发/模块化.md: -------------------------------------------------------------------------------- 1 | ## 山中无岁月·模块化 2 | 3 | --- 4 | 5 | ### 为何使用模块 6 | 7 | > 一次又一次的事实证明,小的、组织良好的代码远比庞大的代码更容易理解、更易于维护。因此,很自然,优化程序的结构和组织的方式,就是把它们分成小的、耦合相对松散的片段,这些片段称为模板。 8 | > 9 | > ——《JavaScript Ninja》 10 | 11 | 好的作者把他们的书组织成逻辑紧密的章节,好的程序员把代码分为一些模块。章节是一些句子聚合在一起,组成一个“主题”。模块就是把一些代码聚合在一起,组成一个“功能”。模块的意图有点像类,但模块的层次比类更高,模块中代码的关系比类要松散。类可能是现实世界的事物的逻辑表示,而一个模块就是有相互关联的“一些事物”的集合,按需取用。如果说一个函数(方法)是一个零件,那么包含了一系列方法的类就是一台机器,而一个模块就是工厂里的一套车间,本身能够独立完成整个加工流程,组合而成就成了庞大的工厂。 12 | 13 | 一个好的模块应该是*独立的*,它可以被随时加入或者移除,而不会损害整个系统或应用程序。模块拥有的特点包括: 14 | 15 | - 可维护性。因为模块是独立的,一个设计良好的模块会让外面的代码对自己的依赖越少越好,这样模块的更新和改进就更加灵活,外部代码需要关注的细节也就越少,同时减少了“这些功能”对“那些功能”的关联造成的影响。 16 | - 提供命名空间。在 JavaScript 里面,如果一个标识符在最顶级的函数之外声明,它就直接变成全局可用,当应用程序越来越大,容易出现命名冲突的情况,产生难以排查的问题。使用模块化开发来封装独立的标识符,可以避免污染全局环境。 17 | - 重用代码。我们有时候会为了方便,从先前的代码中拷贝一些到新的项目,这没有问题,但是更好的方法是,通过将代码封装成可重复使用的模块,来避免机械的复制粘贴,同时保持代码的简洁和关注点的单一性。 18 | 19 | 20 | 21 | ### 模块模式 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### AMD 和 CommonJS 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ### ECMAScript 6 的模块 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ### 在浏览器中使用现代模块 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /设计原理/装饰器.md: -------------------------------------------------------------------------------- 1 | ## 白马非马·装饰器 2 | 3 | --- 4 | 5 | > 这是某种令人惊骇而不知名的杰作,在不可名状的晨曦中依稀可见,宛如在欧洲文明的地平线上瞥见的亚洲文明的剪影。 6 | > 7 | > ——维克多·雨果《就英法联军远征中国致巴特勒上尉的信》 8 | 9 | JavaScript 世界新开张了一家蛋糕房。大厨拿出一块蛋糕胚,抹上糖霜,涂上果酱,放上鲜果,撒上可可粉或咖啡粉,摆上黑色和白色的巧克力,再用奶油沿着边缘雕刻几朵花,一个蛋糕就大致做好了。所有的蛋糕胚都相差无几,有了蛋糕胚,我们就能随心所欲地装饰它,赋予它特别的风味。蛋糕房里,这个裱花袋装着奶油,那个大概装着蓝莓酱或草莓酱。我们只需要按照自己的想法,借助它们来装饰蛋糕。在 JavaScript 中,我们也可以像装饰蛋糕一样装饰类或方法,*装饰器*就是我们手中的裱花袋。 10 | 11 | 装饰器是一个美妙的特性,人们说它来自另一种叫 Python 的以优雅著称的语言。装饰器在 2016 年时被加入 JavaScript,它在本质上是高阶函数的一种应用。当我们定义一个装饰器时,我们只需要写一个函数,这个函数至少要接受一个参数,这个参数代表将要被装饰的类或方法。然后就可以在需要的地方使用它,用一个 `@` 字符,其后紧接装饰器的名字,接着像通常那样写出类或方法的定义。 12 | 13 | 现在我们有一个蛋糕类,它只是一个胚,没有光鲜亮丽的色彩和令人垂涎欲滴的滋味。 14 | 15 | ```javascript 16 | class Cake { 17 | constructor() { 18 | this.flavor = "original"; 19 | } 20 | }; 21 | ``` 22 | 23 | 我们没有裱花袋,让我们来制作一个裱花袋。它装着草莓果酱。 24 | 25 | ```javascript 26 | const strawberry = (cake) => { 27 | cake.prototype.flavor = "strawberry"; 28 | } 29 | ``` 30 | 31 | 现在给蛋糕挤上草莓果酱。 32 | 33 | ```javascript 34 | @strawberry 35 | class Cake { 36 | constructor() { 37 | this.flavor = "original"; 38 | } 39 | }; 40 | ``` 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /MOTTO.md: -------------------------------------------------------------------------------- 1 | # Motto 2 | 3 | --- 4 | 5 | 一些会在书中引用到以抒发思想感情的诗句、格言和梦话。 6 | 7 | 8 | 9 | 路漫漫其修远兮,吾将上下而求索。 10 | 11 | ——屈原《离骚》 12 | 13 | 14 | 15 | 新的转机和闪闪星斗,正在缀满无遮拦的天空。那是五千年的象形文字,那是未来人们凝视的眼睛。 16 | 17 | ——北岛《回答》 18 | 19 | 20 | 21 | 黑夜给了我黑色的眼睛,我却用它来寻找光明。 22 | 23 | ——顾城《一代人》 24 | 25 | 26 | 27 | 老玉米,金黄黄,养活了一国的小儿郎。我捧着玉米回头望,地里站着的是我的娘。 28 | 29 | ——《中国妈妈》 30 | 31 | 32 | 33 | 此后如竟没有炬火,我便是那唯一的光。 34 | 35 | ——鲁迅 36 | 37 | 38 | 39 | 魂兮归来!北方不可以止些。增冰峨峨,飞雪千里些。 40 | 41 | ——《招魂》 42 | 43 | 44 | 45 | 走过的人说树枝低了,走过的人说树枝在长。 46 | 47 | ——顾城《墓床》 48 | 49 | 50 | 51 | 原野上有一股好闻的淡淡焦味,太阳把一切成熟的东西焙得更成熟,黄透的枫叶杂着赭尽的橡叶,一路艳烧到天边。 52 | 53 | ——余光中 54 | 55 | 56 | 57 | 外面下着雨,已经下了许多天,点点滴滴,歪歪斜斜,像我的抄不完的草稿。 58 | 59 | ——张爱玲 60 | 61 | 62 | 63 | 城市是一粒粒精致的银扣,缀在旷野的黑绿色大氅上,不分昼夜地熠熠闪光。 64 | 65 | ——毕淑敏 66 | 67 | 68 | 69 | 我不知道,天为什么无端落起雨来了。薄薄的水雾把山和树隔到更远的地方去,我的窗外遂只剩下一片辽阔的空茫了。 70 | 71 | ——张晓风 72 | 73 | 74 | 75 | 寒不累时,则霜不降;温不兼日,则冰不释。 76 | 77 | ——王充 78 | 79 | 80 | 81 | 一条路是桃花,一条路是雪。开满了桃花的路上,云蒸霞蔚,前程似锦,不由得你不想往前走。 82 | 83 | ——季羡林 84 | 85 | 86 | 87 | 午夜醒来,后庭的月光正在涨潮,满园的林木都淹没在发亮的波澜里。 88 | 89 | ——张晓风 90 | 91 | 92 | 93 | 除非通过黑暗之径,人们不能抵达黎明。 94 | 95 | ——纪伯伦 96 | 97 | -------------------------------------------------------------------------------- /语句/第四章练习.md: -------------------------------------------------------------------------------- 1 | ## 练习题 2 | 3 | --- 4 | 5 | 1. 编写一个程序,读取正整数 `n`,计算前 `n` 个奇数之和。例如, `n` 是 `4`,那么这个程序会计算 `1 + 3 + 5 + 7`,并显示结果 `16`。 6 | 7 | 2. 编写一个程序,不断让用户输入一个数,当输入 `0` 时停止,并显示得到的数据的最大值。 8 | 9 | 3. 编写一个程序,在练习 2 的基础上显示次大和最小值。 10 | 11 | 4. 每个大于 `1` 的正整数可以表示成几个质数的乘积,这类因式分解是唯一的,被称为**质因数**。例如,数字 `60` 可以被分解成 2 × 2 × 3 × 5,每个因数都是质数。注意:在因式分解中,同样的质数可以出现多次。 12 | 13 | 编写一个程序,要求用户输入一个整数 `n`,并对它进行质因数分解。 14 | 15 | 5. 1979 年,道格拉斯·霍夫斯塔勒教授写了《哥德尔、艾舍尔、巴赫》一书,它获得了普利策文学奖,是计算机科学的经典著作之一。书中提出了一个问题:对一个特定的正整数 n 重复执行以下规则,便可形成一系列数: 16 | 17 | - 如果 n 等于 1,那么已经到达这个序列数的终点,可以停止。 18 | - 如果 n 是偶数,将它除以 2。 19 | - 如果 n 是奇数,将它乘以 3 再加 1。 20 | 21 | 这个序列有许多名称,一般称为**冰雹序列**,因为这些值忽上忽下,如冰雹在云中的形成。 22 | 23 | 编写一个程序,让用户输入一个正整数,然后从这个数产生冰雹序列,如下所示: 24 | 25 |  26 | 27 | 这个程序记录了序列的每一步所进行的操作,你可能要思考一下如何在一个对话框里放入所有信息。 28 | 29 | 冰雹序列最迷人之处是直到目前还没有人证明它最终能停止。冰雹序列的计算过程可以有很多步,但不知何故,它总能跳回到 1。 30 | 31 | 6. 德国数学家莱布尼兹(1646~1716)发现了一个事实:圆周率 π 可以用下面的公式计算: 32 | $$ 33 | \frac{\pi}{4} \cong 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - \frac{1}{11} + ... 34 | $$ 35 | 这个等式的右边是一个无穷级数,每个分数是级数中的一项。所有奇数从 1 开始,减去三分之一,加上五分之一,以此类推按照上述公式一直做下去,所得到的值就会越来越接近于 $ \pi $/4。 36 | 37 | 编写一个程序,计算包含莱布尼兹级数的前 10 000 项的 π 的近似值。 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /事件/移动设备事件.md: -------------------------------------------------------------------------------- 1 | ## 移动设备事件 2 | 3 | --- 4 | 5 | ### 触摸和手势事件 6 | 7 | “移动设备”这个词的历史比我们所想象的还要悠久,它最初始于移动的车辆之间的通信实验,那个时候,更确切的叫法是“移动电话”。1926 年,在柏林和汉堡之间的路线上,德国国家铁路上的头等舱乘客获得了首个成功的移动电话服务。1973 年,摩托罗拉的 Martin Cooper 博士在重量为 1.1kg 的设备上进行了首次公开移动电话通话。它是世界上第一部真正意义上的“移动设备”,是我们口中的“手机”的先驱。其后的三十年里,人类在移动设备的洪荒中开不断开辟着将为后世带来深远影响的新技术,包括短信、铃声下载、表情符号等。2003 年,3G 标准开始在全球范围内采用,“移动互联网”这个词诞生了。移动设备的前置技术,逐渐在数十年的静默发展中积蓄了足够的力量。 8 | 9 | 在本章中,我们所说的移动设备,都是指从 2007 年开始所有继承了远古时代第一台 iPhone 的产品,这些产品更广为人知的名字叫**智能手机**。多年以后,我们仍然会记得,2007 年的 Apple 发布会上,iPhone 首次亮相的那一天。在乔布斯先生的手上,我们看到了一个崭新的时代。智能手机成为了移动设备真正的发展方向, 10 | 11 | 在移动设备上,浏览器会我们提供一类全新的事件,用以发挥出移动设备自身的强大特性。移动设备所拥有的触摸传感器可以让用户以一种简单、自然的方式来操控移动设备的界面。安装在屏幕底下的触摸传感器可以检测一只或一只以上的手指对屏幕的触碰,当检测到手指与屏幕发生触摸、移动或离开动作时,就会触发*触摸事件*(touch event)。触摸事件主要分为以下三种类型: 12 | 13 | - `touchstart` 事件:当手指接触屏幕时触发,相当于桌面设备上的 `mousedown`。 14 | - `touchmove` 事件:当手指在屏幕上开始移动时触发,相当于桌面设备上的 `mousemove`。 15 | - `touchend` 事件:当手指从屏幕上移走的时候触发,相当于桌面设备上的 `mouseup`。 16 | 17 | 触摸事件的处理函数可以接受一个事件对象,它包含许多有用的信息,包括: 18 | 19 | - 触摸点在屏幕上的位置; 20 | - 页面上被触摸的元素; 21 | - 以*接触对象数组*形式提供的当前屏幕上所有其他手指的触摸情况(`touches`); 22 | - 特定事件目标元素内的接触情况(`targetTouches`); 23 | - 上次触摸事件发生以来出现改变的接触(`changeTouches`)。 24 | 25 | 26 | 27 | 28 | 29 | ### 姿态和方向事件 30 | 31 | 移动设备朝向的改变可以被*姿态传感器*捕捉到,进而触发*姿态事件*。通过姿态传感器提供的信息,我们可以知道设备的哪一面朝上摆放。姿态传感器还可以检测出设备相对于三条坐标轴的旋转情况,就如同一个陀螺仪一样。一些设备,如 Apple iPhone 和 iPad,还配置了*磁力传感器*,它可以提供设备摆放的精确方向。围绕着 $$x$$轴、$$y$$轴和$$z$$轴的旋转,可以分别表示移动设备的前后倾斜角度(beta)、左右旋转角度(gamma)和平面朝向(alpha)。 32 | 33 | > 图片来源:Hillcrest Labs 34 | 35 |  36 | 37 | 38 | 39 | 40 | 41 | ### 运动事件 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ### 网络状态事件 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /魔法世界/数据可视化.md: -------------------------------------------------------------------------------- 1 | ## 数据可视化 2 | 3 | --- 4 | 5 | ### D3.js 6 | 7 | 我们每个人都会对“大数据”的概念不陌生。我们生活的信息时代由海量数据支撑,有一种说法,“最近十年内互联网上产生的信息超过了过去五千年的总和”。大数据及其相关技术蓬勃发展的今天,数据处理在我们的生活和工作中的影响越来越大,也越来越复杂。每天都有惊人的数据产生,怎么提取并显示有用的信息,变得越来越重要。有用的信息以数据作为载体,而*数据可视化*,就是将数据变为人能轻松理解的信息的重要途径。 8 | 9 | 这几年来,数据可视化越来越流行,无论是与时俱进的报刊杂志,还是不断翻新的 Web 门户网站、新闻媒体,都大量使用可视化技术,使得复杂的数据和文字变得十分容易理解。“一图胜千言”的道理越来越能体现出来。在信息爆炸式增长的今天,我们的时间有限,希望一眼就能找到自己需要的信息。图片和图标不仅容易理解,而且方便记忆,能在脑海中留下深刻印象。本节讨论的主题便是在 Web 上进行可视化的方方面面。 10 | 11 | 绚丽多彩的图表,令人陶醉的可交互特性,都可以利用 JavaScript 基于 Canvas 抑或是 SVG 实现,还能设计出流畅简洁、赏心悦目的动画效果。不过,Canvas 和 SVG 本身的 API 关注的是绘制过程的细节,而我们关注的抽象的数据,为了避免在底层浪费精力,我们可以使用 D3.js。它是一个 JavaScript 可视化库。 12 | 13 | D3 的全称是 Data-Driven Documents,也就是“数据驱动的文档”。D3.js 封装了基础的 DOM 操作和图形绘制细节,为我们提供了大量开箱即用的方法。我们只需要提供我们关心的数据,D3.js 就可以据此绘制出图表,并能根据我们的喜好与需求灵活改变呈现效果。 14 | 15 | --- 16 | 17 | Story: 18 | 19 | 数据可视化(Data Visualization)起源于 18 世纪。William Playfair 出版的书籍《The Commercial and Policital Atlas》中第一次使用了*柱形图*和*折线图*。 20 | 21 | 22 | 23 | --- 24 | 25 | 26 | 27 | 28 | 29 | ### 数据集 30 | 31 | D3.js 封装了一些基础的 DOM 操作。`select` 方法返回匹配选择器的第一个元素,而 `selectAll` 方法返回匹配选择器的所有元素。它们的用法分别与 `document.querySelector` 和 `document.querySelectorAll` 相同。它们返回一个 `D3` 的实例对象,如果是已经用原生 DOM 方法获取的元素,也需要用 D3 的这两个方法进行包装,获得的对象称为*选择集*。选择集对象具有如下三个基本方法: 32 | 33 | - `empty`判断选择集是否为空。 34 | - `node` 返回第一个非空元素。如果选择集为空,返回 `null`。 35 | - `size` 返回选择集中的元素个数。 36 | 37 | 选择集对象的 `attr` 方法与 DOM 的 `setAttribute` 类似,用于设置属性,但是获取属性必须用 `property` 方法。而 `classed` 方法决定某个选择集中的元素是否开启某个类名,`style` 方法则用于设置元素的样式。其余的一些 DOM 封装方法,我们将会在后面的示例中详细了解。 38 | 39 | 40 | 41 | 42 | 43 | ### 比例尺和坐标轴 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ### 布局 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ### 交互 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | ### 案例研究:思维导图 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ### 地图 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | ### 复杂的图 -------------------------------------------------------------------------------- /函数/第五章练习.md: -------------------------------------------------------------------------------- 1 | ## 练习题 2 | 3 | --- 4 | 5 | 1. 编写一个函数,用于将浮点数取整为与其最接近的整数,类似于 `Math.round`。例如,假设我们有一个浮点数变量 `x`,我们可以通过将变量加上 0.5 并舍去小数部分来得到其最接近的整数。因为数值四舍五入取整时会朝着数轴上 0 的方向,所以负数取整时需要将其数值减去 0.5,而不是加上 0.5。 6 | 7 | 2. 我们已经知道 JavaScript 可以使用二进制、八进制、十进制和十六进制的数字形式,也可以自己动手,将数字转换为其它进制的字符串形式。假设要将数字 n 转换为以 b 为基数的数字,实现转换的算法如下。 8 | 1. 设置最高位为 n % b,存入一个数组。 9 | 2. 使用 n / b 代替 n。 10 | 3. 重复步骤 1 和 2,直到 n 为 0,且没有余数。 11 | 4. 将整个数组顺序逆转,连接成的字符串就是转换后的 b 进制数字字符串。 12 | 13 | 3. 如果你碰上寒冷、大风的天气,你对温度的感觉不仅取决于温度,还取决于风速。风速越高,越觉得寒冷。为了量化风速对于温度感觉的影响,美国国家气象局提供了风寒指数报告,其官网上的说明如下: 14 | 15 |  16 | 17 | 正如你在图片底部所看到的,气象局使用以下公式计算风寒指数: 18 | 19 | $$ 35.74 + 0.6215 t - 35.75 v ^ {0.16} + 0.4725t v ^ {0.16} $$ 20 | 21 | 其中,$$t$$是华氏温度,$$v$$是风速,单位是$$ 英里/小时 $$。 22 | 23 | 编写一个函数 `windChill`,参数为 t 和 v,返回风寒指数。为了达到这一目的,你的函数必须考虑以下情况: 24 | 25 | - 如果没有风,`windChill` 必须返回原始温度 t。 26 | - 如果温度高于 $$40 ℉ $$,风寒指数未定义,此时你应当考虑如何输出错误信息。 27 | 28 | 29 | 30 | 4. 世界上的大部分人们使用摄氏度而非华氏度,包括我们。因此为了适应我们的习惯,编写一个华氏度转到摄氏度的函数,并基于此来计算风寒指数。我们在第三章中了解过温度转换的方法,现在是发挥作用的时候。 31 | 32 | 5. 实现一个将英语基数词转换为序数词的函数。 33 | 34 | 我们小学时学过这样的规则口诀: 35 | 36 | > 基变序,有规律,词尾加上“th”; 37 | > 38 | > 一,二,三(first、second、third)特殊记; 39 | > 40 | > 从 4 开始上 th,5 变 ve 改f(fifth),8 去 t(eighth),9 减 e(ninth); 41 | > 42 | > 几十尾巴 ty 变 tie,后面跟上th(twentieth); 43 | > 44 | > 几十几,头不变,尾巴变,中间记得加个杠(twenty-fourth); 45 | > 46 | > 遇到特殊要除外(twenty-first)。 47 | 48 | 49 | 50 | 6. 实现一个将英语动词转换为现在分词形式的函数。 51 | 52 | 规则: 53 | 54 | 1. 一般情况下,直接在动词原形后面加 -ing。 55 | 2. 结尾是辅音+一个元音+一个辅音的,重复最后一个辅音字母,再加 -ing。 56 | 3. 以不发音的 -e 结尾的动词,去 -e ,再加 -ing。 57 | 58 | 7. 实现一个将阿拉伯数字转换为罗马数字的函数。 59 | 60 | 罗马数字共有 7 个,即 I(1)、V(5)、X(10)、L(50)、C(100)、D(500)和M(1000)。按照下述的规则可以表示任意正整数。 61 | 62 | - 一个罗马数字重复几次,就表示这个数的几倍。 63 | 64 | - 在较大的罗马数字的右边记上较小的罗马数字,表示大数字加小数字。 65 | 66 | - 在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字。 67 | - 左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV 68 | - 但是,左减时不可跨越一个位值。比如,99不可以用IC($100-1$)表示,而是用 XCIX($ [100-10]+[10-1] $)表示(等同于阿拉伯数字每位数字分别表示。) 69 | 70 | 8. 改进之前的罗马数字函数。 71 | 72 | 罗马数字具有以下限制: 73 | 74 | - 左减数字必须为一位,比如8写成VIII,而非IIX。 75 | - 右加数字不可连续超过三位,比如14写成XIV,而非XIIII。(见下方“数码限制”一项。) 76 | - 同一数码最多只能连续出现三次,如40不可表示为XXXX,而要表示为XL。 77 | -------------------------------------------------------------------------------- /附录/键码映射表.md: -------------------------------------------------------------------------------- 1 | ## 附录 C - 键码映射表 2 | 3 | --- 4 | 5 | 6 | 7 | ### 字母和数字键盘 8 | 9 | | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 10 | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 11 | | A | 65 | J | 74 | S | 83 | 1 | 49 | 12 | | B | 66 | K | 75 | T | 84 | 2 | 50 | 13 | | C | 67 | L | 76 | U | 85 | 3 | 51 | 14 | | D | 68 | M | 77 | V | 86 | 4 | 52 | 15 | | E | 69 | N | 78 | W | 87 | 5 | 53 | 16 | | F | 70 | O | 79 | X | 88 | 6 | 54 | 17 | | G | 71 | P | 80 | Y | 89 | 7 | 55 | 18 | | H | 72 | Q | 81 | Z | 90 | 8 | 56 | 19 | | I | 73 | R | 82 | 0 | 48 | 9 | 57 | 20 | 21 | 22 | 23 | 24 | 25 | ### 数字和功能键盘 26 | 27 | | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 28 | | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- | 29 | | 0 | 96 | 8 | 104 | F1 | 112 | F7 | 118 | 30 | | 1 | 97 | 9 | 105 | F2 | 113 | F8 | 119 | 31 | | 2 | 98 | * | 106 | F3 | 114 | F9 | 120 | 32 | | 3 | 99 | + | 107 | F4 | 115 | F10 | 121 | 33 | | 4 | 100 | Enter | 108 | F5 | 116 | F11 | 122 | 34 | | 5 | 101 | - | 109 | F6 | 117 | F12 | 123 | 35 | | 6 | 102 | . | 110 | | | | | 36 | | 7 | 103 | / | 111 | | | | | 37 | 38 | 39 | 40 | 41 | 42 | ### 控制键盘 43 | 44 | | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 45 | | --------- | ---- | ---------- | ---- | ----------- | ---- | ---- | ---- | 46 | | BackSpace | 8 | Esc | 27 | Right Arrow | 39 | -_ | 189 | 47 | | Tab | 9 | Spacebar | 32 | Dw Arrow | 40 | .> | 190 | 48 | | Clear | 12 | Page Up | 33 | Insert | 45 | /? | 191 | 49 | | Enter | 13 | Page Down | 34 | Delete | 46 | `~ | 192 | 50 | | Shift | 16 | End | 35 | Num Lock | 144 | [{ | 219 | 51 | | Control | 17 | Home | 36 | ;: | 186 | \| | 220 | 52 | | Alt | 18 | Left Arrow | 37 | =+ | 187 | ]} | 221 | 53 | | Cape Lock | 20 | Up Arrow | 38 | ,< | 188 | '" | 222 | 54 | 55 | 56 | 57 | 58 | 59 | ### 多媒体键盘 60 | 61 | | 按键 | 键码 | 62 | | ------ | ---- | 63 | | 音量加 | 175 | 64 | | 音量减 | 174 | 65 | | 停止 | 179 | 66 | | 静音 | 173 | 67 | | 浏览器 | 172 | 68 | | 邮件 | 180 | 69 | | 搜索 | 170 | 70 | | 收藏 | 171 | -------------------------------------------------------------------------------- /启程/表达式与值.md: -------------------------------------------------------------------------------- 1 | ## 辟自鸿蒙·表达式与值 2 | 3 | --- 4 | 5 | 从最初有理性的记忆里,我们便与表达式打交道。小时候我们在数学课上称为“算式”的东西,就是一种表达式。$$1 + 1 = 2$$ 这样的算式,与我们最初理解的现实世界的概念相伴而生,与物体的颜色、形状、名字一道,扎根在每个人最深层的理性思维中。有一个苹果,又得到了一个苹果,那么我们有两个苹果——这是我们对这种来自于现实而又超脱于一切现实事物的人类智慧的最初印象,从最简单的算术开始,一点一点窥见数学这一人类智慧的曙光。人们把这种纯粹、不掺杂一点杂念的智慧带进了计算机最根本的生命中。 6 | 7 | 人们问,$$1 + 1 = $$ ?,然后电子管和继电器所组成的巨大机器便开始轰鸣运作,渐渐就能解答人们越来越复杂的问题。人类有关数学的理想,在用晦涩的低级程序语言编写以前,是怎样表达的?是数学表达式。很多年以后,在 JavaScript 这样的高级编程语言中,人们可以直接写下数学表达式,刹那间便可以从计算机那里得到答案。 8 | 9 | ```javascript 10 | alert(1 + 1); 11 | ``` 12 | 13 | 我们知道了答案:$$2$$。不需要有任何等待,一切都在电光火石中进行着。 14 | 15 | 为了让计算机中所蕴含的人类智慧不被如此简单的问题小觑,我们可以来个更难的: 16 | 17 | $$(147 + 258) × 369 - (550 + 233) ÷ 29$$ 18 | 19 | 在 JavaScript 中,这个数学表达式将以略微不同的方式被写下,然后用 `alert` 输出答案。 20 | 21 | ```javascript 22 | alert((147 + 258) * 369 - (550 + 233) / 29); 23 | ``` 24 | 25 | 答案是 $$149418$$。计算机不会让我们失望。 26 | 27 | 这个表达式被包裹在 `alert` 函数和一对小括号中。加号 `+`,减号 `-`,小括号 `( )` 都是本来的意思。`*` 负责在 JavaScript 中进行乘法运算,`/` 负责除法。这些标点符号被称为**运算符(Operator)**,负责执行各类算术运算。 28 | 29 | ------ 30 | 31 | Note: 32 | 33 | 为什么 JavaScript 的乘号和除号,与它们在日常生活中所使用的的形式不同? 34 | 35 | 一个简单的答案是因为你的键盘上没有所谓的乘号($$\times$$)与除号($$\div$$),而键盘布局的历史需要读者自行查阅资料。 36 | 37 | 几十年最初使用键盘进行编程的程序员们脑洞大开,将星号(`*`)作为乘号使用。而使用斜杠作为除号的原因还有一个:在数学中,除法还可以用分数的形式表示,所以这个斜杠其实就是横着写的分数线——左侧的被除数相当于分子,右侧的除数也就相当于分母。 38 | 39 | ------ 40 | 41 | 常见的 JavaScript 数学运算符有以下几种。 42 | 43 | | 符号 | 运算 | 44 | | ----- | -------------- | 45 | | `+` | 加法 | 46 | | `-` | 减法或取相反数 | 47 | | `*` | 乘法 | 48 | | `/` | 除法 | 49 | | `%` | 求整除后的余数 | 50 | | `**` | 乘方 | 51 | | `( )` | 改变优先级 | 52 | 53 | 如果没有 `alert` 函数来输出,计算仍然会进行,会算出一个结果,然后这个结果就被丢弃到了虚空中。为了让我们的眼睛能看见,`alert` 函数就担负了输出信息的作用,虽然它更常见的用途是输出一段警告信息。 54 | 55 | 我们可以编写并运行以下程序,重温小学数学课上的感觉。 56 | 57 | ```javascript 58 | alert(18 + 14 * 5); 59 | alert(24 - 112); 60 | alert(1 / 3); 61 | alert(-10 * 15); 62 | alert(Math.PI); 63 | alert(0xf + 1); 64 | alert(20 % 8); 65 | alert(20 ** 3); 66 | ``` 67 | 68 | 其中,`Math.PI` 是一个预定义的值,它表示圆周率 $π$ 近似值;最后一行代码中的 `0xf` 是一个*十六进制数*,它的值就是 `16`,我们会在第三章讲到它。 69 | 70 | 人们说,计算机不但要拥有人类的理性,还要有人类的情感,于是人类文字就以某种精巧的方式就进入了计算机的生命。我们需要某种优雅的方式,向计算机吐露我们的心声,计算机的答案也要以更优雅、合乎我们思维的方式让我们知晓,于是一种叫**字符串**的东西诞生了,它是人类文字的载体,让人类以自己熟悉的方式写下话语并传达给计算机和未来的读者成为可能。 71 | 72 | 我们也可以用 `+` 符号来拼接两段文本,使它成为我们想要的形式。如: 73 | 74 | ```javascript 75 | alert("Hello " + "world"); 76 | alert("我今年" + 120 + "岁了!"); 77 | alert("十六进制数 0xefef 的值是" + 0xefef); 78 | ``` 79 | 80 | 另外,在 JavaScript 中,`alert(xxx)` 这样的*函数调用*也是表达式,像其它的一样,它也会得到一个值。`alert()` 得到的是 `undefined`,我们会在后面的章节中慢慢了解。 81 | 82 | 我们已经初步了解了 JavaScript 中的表达式,接下来的我们将学到给值命名的技巧,这样我们就可以把表达式的值存放起来,需要的时候再用。 83 | 84 | -------------------------------------------------------------------------------- /启程/更进一步.md: -------------------------------------------------------------------------------- 1 | ## 听风知雨·更进一步 2 | 3 | --- 4 | 5 | ### 输入与输出 6 | 7 | 提供输入与输出数据的功能,是任何一种编程语言的基本设施。试想一下,假如我们的程序无法使用输入输出的功能——确切地说,无法与外界进行数据交换,那么它能做什么呢?什么也做不了!它也许可以静静地计算一个表达式的值,可以执行一个循环与条件判断,但是我们将始终无从得知它的最终工作,这个程序也就不会有存在的意义。输入与输出非常重要,也充满灵活性。 8 | 9 | JavaScript 的语言标准(即 ECMAScript)并没有规定用于输入与输出的方式。浏览器为我们提供了两个简单的函数:`alert` 和 `prompt` ,以便进行基本的信息输出和输入。 10 | 11 | 12 | 13 | **`alert` 和 `prompt`** 14 | 15 | `alert` 我们已经见过很多次了。当我们简单地想要输出一条信息,比如显示一条表达式的计算结果,或者干其他的什么事情,我们可以使用它。在实际应用中我们有更复杂和标准的信息输出方式,但是现在我们使用 `alert` 就足以满足我们需要了。 16 | 17 | `prompt` 这个函数我们已经在前面的代码示例中见过了,它可以弹出一个对话框,要求用户输入一点内容,然后得到这个内容,它的使用形式如下: 18 | 19 | `let xxx = prompt();` 20 | 21 | 变量 `xxx` 中存放的就是我们获取到的内容。 22 | 23 | 但是它弹出的对话框什么提示也没有,只有一个简单的输入框。试想一下,假如别人使用你的程序,突然就看到这么一个框,什么也没有提示,会觉得丈二和尚摸不着头脑,对吧?更有可能,我们想要一个表示年龄的数字,用户却稀里糊涂地输入了一个手机号码。 24 | 25 | 我们可以给 `prompt` 的对话框加一条简单的提示语,来表明我们要干的事情,像这样: 26 | 27 | `let xxx = prompt("请输入你的年龄:");` 28 | 29 | 这是使用 `prompt` 函数的另一种形式,变量 `xxx` 即是我们获取到的内容。 30 | 31 |  32 | 33 | 34 | 35 | 我们可以用一些简单的示例来尝试我们刚刚了解到的东西: 36 | 37 | ```javascript 38 | alert("我们将收集您的身高数据以计算您的标准体重。"); 39 | let height = parseFloat(prompt("请输入您的身高(单位:厘米):")); 40 | let weight = (height - 100) * 0.9; 41 | alert("您的标准体重是:" + weight); 42 | ``` 43 | 44 | 其中 `parseFloat` 函数会从文本中获取一个数字,将在第三章讲到。 45 | 46 | 你可以自己试着测测你的标准体重哦! 47 | 48 | 49 | 50 | 这是另一个实用性的例子,更好地练习我们刚刚所学内容: 51 | 52 | ```javascript 53 | // 计算圆的面积与周长。 54 | let r = parseFloat(prompt("请输入圆的半径:")); 55 | alert("圆的面积是:" + r * r * Math.PI); 56 | alert("圆的周长是:" + r * 2 * Math.PI); 57 | ``` 58 | 59 | 60 | 61 | 62 | 63 | ### 注释 64 | 65 | 在编写 JavaScript 代码时,你可以在代码周围插入一些说明性的文字,它们被称为*注释*。 66 | 67 | 以下是一个在代码中应用注释的例子: 68 | 69 | ```javascript 70 | let a = +prompt(); // 获取第一个数字 71 | let b = +prompt(); // 获取第二个数字 72 | alert(a + b) // 计算并展示 a + b 的值 73 | ``` 74 | 75 | 在代码中, `//` 标记被用于说明一个*单行注释*的开始。它意味着之后的整一行代码都会被忽略掉,因此你可以在里面写上任何东西,当然更多情况下我们只是用于说明该行代码的功能。 76 | 77 | 假如我们需要写很多行东西来解释和说明我们的代码,或者是充当一个临时备忘录,我们可以相应地使用*多行注释*,如下所示: 78 | 79 | ```javascript 80 | /* 交换两个变量的值。 81 | 作者:杨雨露 82 | 日期:2019-3-19 83 | 备注:无 84 | */ 85 | let a = prompt(); 86 | let b = prompt(); 87 | let temp = a; 88 | a = b; 89 | b = temp; 90 | alert("a = " + a + ", b = " + b); 91 | ``` 92 | 93 | 在一对 `/*` 与 `*/` 之间的所有东西都会被忽略掉,同样,你可以在里面写上任何东西。从第一个 `/*` 开始,一旦遇到一个 `*/` ,就意味着注释内容已经结束了,其后如果再出现单独的 `*/` ,就会被认为是一个语法错误。 94 | 95 | 如下所示: 96 | 97 | ```javascript 98 | /* 第一行注释 99 | 第二行注释 100 | /* 第三行注释(这行开头的 /* 同样会被忽略) 101 | 第四行注释 102 | 现在多行注释结束了: */ 103 | 104 | */ // 嘿,多余的 */ 会被当成语法错误! 105 | ``` 106 | 107 | **` //` 注释用于一行里的注释,`/* */` 注释用于一段完整的注释。** -------------------------------------------------------------------------------- /数据/数据类型.md: -------------------------------------------------------------------------------- 1 | ## 数据类型 2 | 3 | --- 4 | 5 | ### JavaScript 中的数据类型 6 | 7 | JavaScript 所有的值(数据)都有着自己的**数据类型**。目前 JavaScript 中共有以下的数据类型: 8 | 9 | - `number`(数值) 10 | - `BigInt` (任意精度整数,2019年发布) 11 | - `string`(字符串) 12 | - `object`(对象) 13 | - `function`(函数) 14 | - `undefined` 15 | - `regexp`(正则表达式) 16 | - `symbol`(符号) 17 | 18 | 我们已经接触了 `number` 用于数值计算,`string` 用于处理文本内容,`object` 作为存放其他数据的结构,还有 `undefined`,它自身也是一种独立的数据类型。你可能会为看不见 `array` 而感到奇怪,事实上,数组是一种特殊的对象,它被精心设计以用于处理数据,但是我们仍需将它归类为 `object`。至于另外三种数据类型,我们会在后面逐渐接触到。 19 | 20 | JavaScript 提供了 `typeof` 操作符来确定一个值的数据类型,它得到类型的字符串名称,即以上七种之一。 21 | 22 | ```javascript 23 | alert(typeof 123); // "number" 24 | alert(typeof NaN); // "number 25 | alert(typeof Infinity); // "number" 26 | alert(typeof "Hello world"); // "string" 27 | alert(typeof {}); // "object" 28 | alert(typeof [1, 2, 3]); // "object" 29 | alert(typeof null); // "object" 30 | alert(typeof alert); // "function" 31 | alert(typeof undefined); // "undefined" 32 | ``` 33 | 34 | 35 | 36 | --- 37 | Note: 为什么 `typeof null === "object"` ? 38 | 39 | 在 JavaScript 第一个版本的实现中,每个值在内部存储时都会用一个标记来记录它的数据类型。由于 `object` 是 JavaScript 中的“第一等类型”,它的类型标记为 `0`,而 `null` 表示为 *`NULL` 指针*,在大多数平台上, `NULL` 指针的实际值是 `0x00`,那么 `null` 的数据类型标记实际上与 `object` 相同。因此 `typeof` 运算符在获取 `null` 的类型标记的时候,得到的是 `0` ,便会将它判断为 `"object"`。 40 | 41 | --- 42 | 43 | 44 | 45 | 46 | 47 | ### 判断数据类型的技巧 48 | 49 | `typeof` 的首要作用自然是判断数据类型,以便了解到的数据类型做出可能的操作。它具有明显的局限性:它对数据类型的判断仅限于以上七种;无法区分 `array` 和一般的 `object`;当我们明确地需要一个**对象**时它却会将 `null` 混为一谈。我们需要在 `typeof` 的判断的基础上使用一些辅助方法,以便在各类数据类型之间游刃有余。 50 | 51 | **区分数组与对象** 52 | 53 | `typeof` 会将数组判定为 `"object"`,没关系,JavaScript 提供了 `Array.isArray` 函数来判断一个值是不是数组。那么我们只需要: 54 | 55 | ```javascript 56 | alert(Array.isArray([1, 2, 3])); // true 57 | alert(Array.isArray([])); // true 58 | alert(Array.isArray(new Array())); // true 59 | alert(Array.isArray({})); // false 60 | ``` 61 | 62 | 63 | 64 | **精确地判断对象** 65 | 66 | 我们在第一节(逻辑)中了解过,`null` 会被当做一个假值,因此对它进行非运算会得到 `true`。 67 | 68 | 我们可以采取这样的策略: 69 | 70 | - 使用`typeof` 进行判断,如果它不是 `"object"`,得到 `false`。 71 | - 如果它是 `"object"`,判断它是否为数组,若是,得到 `false`。 72 | - 如果它是 `null`,得到 `false`,否则为 `true`。可以对它进行 `!!`操作,若为 `null` ,我们就会得到 `false`,否则我们就会得到 `true`。 73 | 74 | 示例: 75 | 76 | ```javascript 77 | let value = "Hello world"; 78 | alert( // 对 "Hello" 进行判断 79 | typeof value !== "object" ? false : 80 | Array.isArray(value) ? false : 81 | !!value 82 | ); // false 83 | // value = true -> false 84 | // value = 123 -> false 85 | // value = null -> false 86 | // value = [1, 2, 3] -> false 87 | // value = {a: 1, b: 2} -> true 88 | // value = window -> true 89 | ``` 90 | 91 | **精确判断数字** 92 | 93 | `NaN` 和 `±Infinity` 都属于 `number` 类型,但是我们在进行数学运算的时候并不希望将它们参与到运算中。我们只需要进行一些附加判断即可将它们与真正的数字区分开来。 94 | 95 | ```javascript 96 | let n = 100; 97 | alert( 98 | typeof n !== "number" ? false : 99 | isNaN(n) ? false : isFinite(n) 100 | ); // true 101 | // n = "123" -> false 102 | // n = NaN -> false 103 | // n = Infinity -> false 104 | // n = Number.MAX_VALUE -> true 105 | // n = Number.MAX_VALUE * 10 -> false 106 | ``` 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /启程/命名的值.md: -------------------------------------------------------------------------------- 1 | ## 请叫阮的名·命名的值 2 | 3 | --- 4 | 5 | ### 变量与常量 6 | 7 | 人类发明了各种各样的容器来盛放东西,而 JavaScript 的世界也有容器,用来存放表达式的值。这种容器,叫变量。 8 | 9 | **变量** 10 | 11 | 在 JavaScript 中,我们可以使用*变量*来存放一个值,这个值随时可以被改变。变量的定义像下面这样: 12 | 13 | ```javascript 14 | let a; 15 | a = 10; 16 | ``` 17 | 18 | 我们使用关键字 `let` 来表示一个变量声明的开始。`let a` 会产生一个名为 `a` 的变量,我们将这一步叫做**变量声明**,随后的 `a = 10;` 会把 10 这个值放进变量 `a` 中,这个过程叫**赋值**。 19 | 20 | 变量声明与赋值是两个过程,一个变量只能被声明一次,但是可以被多次赋值。正如它的名称所示,它的值是可以变的。第一次的声明与赋值可以被写到一行语句中: 21 | 22 | ```javascript 23 | let a = 10; 24 | ``` 25 | 26 | 我们可以像这样改变它的值: 27 | 28 | ```javascript 29 | a = 100; 30 | a = 12 * 3 + 20; 31 | a = "Hello world"; 32 | ``` 33 | 34 | 为变量赋值之后,我们可以像通常的表达式那样使用它: 35 | 36 | ```javascript 37 | let a = 10; 38 | alert(a); 39 | a = a + 1; 40 | alert(a); 41 | alert(a + 2); 42 | ``` 43 | 44 | 显示的结果分别为 10,11 和 13。 45 | 46 | 假如我们使用了一个从未出现的变量,会产生一个错误: 47 | 48 |  49 | 50 | 如果我们已经给 `hahaha` 赋值,那么可以使用它,不会产生错误,但是我们非常不推荐这种做法,使用变量前一定要记得声明。 51 | 52 |  53 | 54 | 如果你早就已经接触了 JavaScript,你或许曾在别的地方见过另一种声明变量的方式: 55 | 56 | ```javascript 57 | var a = 10; 58 | ``` 59 | 60 | `var` 关键字是 JavaScript 曾经使用的变量声明方式,但是这种方式存在一些缺陷,在2015年发布的新标准中被 `let` 所取代,一些细节我们会在后面谈到。我们理解它的含义即可,不建议使用它。 61 | 62 | **常量** 63 | 64 | 顾名思义,*常量*与变量类似,但是它的值是不可改变的。也就是说,只能赋值一次,之后如果尝试改变它的值,会产生一个错误。 65 | 66 |  67 | 68 | 第一次调用 `alert` 会正常显示 `name` 的值 `"Jim"` 。随后的赋值语句会带来如图所示的错误,并中断代码的执行,因此最后一行语句不会被执行。 69 | 70 | 常量的使用场景一般是强制某些不应改变的值**不可改变**,可以避免失误造成原有值被覆盖的情况。为了带来明显的视觉效果以与通常的变量区分,我们一般会使用大写字母来书写常量名称,并使用下划线“_”来连接常量名中包含的单词。 71 | 72 | ```javascript 73 | const MY_BIRTHDAY = "2005-2-6"; 74 | alert(MY_BIRTHDAY); 75 | ``` 76 | 77 | **标识符** 78 | 79 | JavaScript 中的变量名或常量名必须是合法的*标识符*。一个合法的标识符应当以以下字符开头: 80 | 81 | ``` 82 | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 83 | a b c d e f g h i j k l m n o p q r s t u v w x v z $ _ 84 | ``` 85 | 86 | 即二十六个英文大小写字母以及美元符号和下划线。 87 | 88 | 而其后跟随的字符可以是: 89 | 90 | ``` 91 | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 92 | a b c d e f g h i j k l m n o p q r s t u v w x v z $ _ 93 | 0 1 2 3 4 5 6 7 8 9 94 | ``` 95 | 96 | 即二十六个英文大小写字母、美元符号、下划线和十个阿拉伯数字。 97 | 98 | 除此之外的字符原则上可以使用,但是容易造成难以预料的错误。我们不推荐使用。关于 JavaScript 中的字符,我们将在第三章详细了解。 99 | 100 | 一个合法的标识符不能与已有的保留字发生冲突。保留字一些 JavaScript 语言内预留的、具有特殊含义的单词,如果你使用它们作为标识符,会产生语法错误。 101 | 102 | **** 103 | 104 | | | | | | | 105 | | :------: | :-------: | :--------: | :-------: | :----------: | 106 | | `abstract` | `arguments` | `boolean` | `break` | byte | 107 | | `case` | `catch` | `char` | `class` | const | 108 | | `continue` | `debugger` | `default` | `delete` | `do` | 109 | | ` double` | `else` | `enum` | `eval` | `export` | 110 | | `extends` | `false` | `final` | `finally` | `float` | 111 | | `for` | `function` | `goto` | `if` | `implements` | 112 | | `import` | `in` | `instanceof` | `int` | `interface` | 113 | | `let` | `long` | `native` | `new` | `null` | 114 | | `package` | `private` | `protected` | `public` | `return` | 115 | | `short` | `static` | `super` | `switch` | `synchronized` | 116 | | `this` | `throw` | `throws` | `transient` | `true` | 117 | | `try` | `typeof` | `var` | `void` | `volatile` | 118 | | `while` | `with` | `yield` | | | 119 | 120 | 除此之外,有一些 JavaScript 中预定义的函数、常量等也不应当被用作标识符,包括 `Object` `Ininity` `undefined` `isNaN` 等。 -------------------------------------------------------------------------------- /设计原理/JavaScript标准对象.md: -------------------------------------------------------------------------------- 1 | ## JavaScript 标准对象 2 | 3 | --- 4 | 5 | ### 内置对象 6 | 7 | *内置对象*(internal object)指的是 JavaScript 核心语言中所包含的类与对象。它们直接由 ECMAScript 标准定义,与运行环境没有关系,但任何 JavaScript 环境都必须预先按照标准实现这些对象,无论是台式计算机,还是移动设备,抑或是手掌大小的单片机。内置对象与语法本身,构成了 JavaScript 的核心语言。 8 | 9 | 内置对象既包含真真正正的对象(如 `Math`),又包括基本类型所对应的类(如 `Number`)和建立其他一些对象的类(如 `Promise`),还有一些就是单纯的函数和变量(如 `parseInt` 和 `NaN`)。内置对象如同构成 JavaScript 强大力量的基础元件,因此也叫*内置基元*。 10 | 11 | **1. 内置变量和普通函数** 12 | 13 | 我们之前已经介绍了三个内置变量:`Infinity`,`NaN` 和 `undefined`,还有四个内置函数:`parseInt`,`parseFloat`,`isNaN`,`isFinite`。除此之外还有一些函数: 14 | 15 | - `encodeURI` 和 `encodeURIComponent` 根据将一段普通文本根据*统一资源标识符*的要求编码为对应的*安全版本*。这些函数将在第九章介绍。 16 | - `decodeURI` 和 `decodeURIComponent` 执行相应编码的逆操作。这些函数将在第九章介绍。 17 | - `eval` 将一段字符串视为 JavaScript 代码并执行。如果代码是一个表达式,那么 `eval` 会求出它的值。由于必须对字符串进行编译和解释,因此 `eval` 执行的速度很慢。 18 | 19 | 以下是 `eval` 函数的示例。 20 | 21 | ```javascript 22 | let code = prompt("请输入一个算式"); 23 | if (/[^\d()+*/-%\s]/.test(code)) { 24 | alert("这不是一个算式!"); 25 | } else { 26 | alert(`算式的值是:${eval(code)}`); 27 | } 28 | ``` 29 | 30 | `eval` 函数具有诸多争议,它有时被称为 evil(邪恶的)。当编程语言的某项特性很容易被错误使用,这项特性就被视为邪恶的。使用 `eval` 的唯一原因是动态地执行运行时才产生的代码,但这些代码从何而来呢?如果代码的来源不受信任,就会使应用程序有被注入恶意代码的风险,甚至破坏应用程序。 31 | 32 | 根据人们的经验,如果我们需要使用 `eval` 来解析一些东西,我们先考虑一下是否有其它替代品可以达成同样目的。一些策略是单纯地解析而不执行,例如 `JSON.parse`。如果我们必须要使用 `eval`,就要保证代码一定是安全的,没有无限循环,没有奇怪的赋值或函数调用等。在上面的示例中,我们使用正则表达式对用户输入的内容进行检查,确保文本仅包含数字、括号和几个运算符,才会调用 `eval` 来求值。我们可以在实践中思考怎样为 `eval` 创建一个安全的执行环境。 33 | 34 | 35 | 36 | **2. Math** 37 | 38 | 39 | 40 | **3. Object** 41 | 42 | 43 | 44 | **4. Array** 45 | 46 | 47 | 48 | **5. Boolean、Number 和 String** 49 | 50 | 51 | 52 | **6. Function** 53 | 54 | 55 | 56 | **7. Date** 57 | 58 | 59 | 60 | **8. 错误对象** 61 | 62 | 技术上讲,我们可以使用任何东西来作为一个异常对象。甚至可以是基础类型,比如数字或者字符串。但是更好的方式是用对象,尤其是有 `name` 和 `message` 属性的对象(某种程度上和内置的异常有可比性)。 63 | JavaScript 有很多内置的标准异常构造器,我们也可以用它们来构造标准的异常对象。 64 | 65 | | JavaScript 标准异常构造器 | 描述 | 66 | | ------------------------- | --------------------------------------------------- | 67 | | `Error` | 默认或自定义的错误。 | 68 | | `EvalError` | 用错误的方式使用 `eval` 函数。 | 69 | | `InternalError` | JavaScript 引擎遇到的内部错误,如:“递归嵌套太多”。 | 70 | | `RangeError` | 数值变量或参数超出其有效范围。 | 71 | | `ReferenceError` | 无效的引用、求值过程。 | 72 | | `SyntaxError` | JavaScript 引擎在解析代码时遇到的语法错误。 | 73 | | `TypeError` | 变量或参数不属于有效类型。 | 74 | | `URIError` | 给 `encodeURI` 或 `decodeURI` 传递的参数无效。 | 75 | 使用异常构造器的方式如下: 76 | ```javascript 77 | let error = new Error(message); 78 | // 或者 79 | let error = new SyntaxError(message); 80 | let error = new ReferenceError(message); 81 | // ... 82 | ``` 83 | 对于内置的异常对象(不是对于其他的对象,而是对于异常对象),`name` 属性刚好是构造器的名字。`message` 则来自于参数所提供的异常信息。例如: 84 | ```javascript 85 | let error = new Error("不知道发生了什么 (O_o)??"); 86 | alert(error.name); // "Error" 87 | alert(error.message); // "不知道发生了什么 (O_o)??" 88 | ``` 89 | 我们可以使用任何东西来作为一个异常对象。甚至可以是基础类型,比如数字或者字符串。但是更好的方式是用对象,尤其是有 `name` 和 `message` 属性的对象。而内置的异常构造器同时为我们设定好了异常所属的类型,因此尽量使用具体的异常构造器。如果异常不是特定的,那么可以直接用 `Error` 构造器。 90 | 异常构造器可以通过 `new` 运算符建立新的异常对象,包含下列属性: 91 | - `message` —— 我们能阅读的异常提示信息。 92 | - `name` —— 异常名称(异常对象的构造函数的名称)。 93 | - `stack` —— 异常发生时的调用栈。 94 | 95 | 96 | 97 | **9. JSON** 98 | 99 | 100 | 101 | **10. Map 和 WeakMap ** 102 | 103 | 104 | 105 | **11. Set 和 WeakSet** 106 | 107 | 108 | 109 | **12. Proxy** 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | ### 宿主对象 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /启程/Hello-world.md: -------------------------------------------------------------------------------- 1 | ## 千里之行,始于足下·Hello world 2 | 3 | --- 4 | 5 | 你可能曾有过学习编程语言的打算,但是最艰难的恐怕就是那关键的第一步吧——如何上手?要做什么,才能做好写下第一行代码的准备,又该怎样让它成为一个精巧的“程序”呢?事实上,当你读完本章后,你恐怕就不会再有这样的迷惑了。 6 | 7 | 因为,我们将要学习的是这种可以在**任何地方**运行的编程语言——JavaScript!从每一台桌面或移动设备的浏览器,到服务器和多媒体领域,甚至嵌入式和正逐步成为现实的物联网。事实上,JavaScript 是如此地容易上手和学习,因为踏出第一步便如此简单:如我所说,JavaScript 是一种可以在浏览器上运行的编程语言。你只需要准备一个好用的现代浏览器,诸如 Google Chrome ,Mozilla Firefox 或 Microsoft Edge 等。我们将会用非常多的时间与浏览器打交道,因此,选择一个适合的浏览器,将会使我们的学习之路变得得心应手且愉快顺利。 8 | 9 | 编写和运行 JavaScript 代码最简单的方式是在浏览器地址栏中。是的,就是那个用于输入网址以便你去到因特网的任何地方的地址栏。如图所示: 10 | 11 |  12 | 13 | 我所使用的是运行在 Microsoft Windows 10 上的 Google Chrome 浏览器,如果你的浏览器类型或版本与我不同,可能会呈现出不一样的外观。这是没关系的。当然,为了我们接下来的愉快旅程考虑——使用一些 Chrome 或 Firefox 之类的**流行**浏览器会得到更一致的操作体验,更好的兼容性(关于兼容性的问题我们会在第八章详细谈到)。最重要的是,我们所学习的 JavaScript 语言遵循一个2015年正式发布的国际标准:ECMAScript 6。如果您的浏览器版本较低或“*没有跟上时代的步伐*”,将不能很好地运行我们所写的代码。这非常令人不愉快。无论如何,**请不要使用 Internet Explorer**。 14 | 15 | 回到正题。我们在浏览器地址栏中这样一句代码: `javascript:alert("Hello world")`,接下来按下 Enter 键,会发生什么有趣的事情呢? 16 | 17 | 看!一个弹出来的窗口!上面写着 Hello world 。我们已经成功运行了第一个 JavaScript 程序。 18 | 19 |  20 | 21 | Hello world 上方的“cn.bing.com”指我输入这行代码时页面所处的域名,你的应该会和我不一样。不必在意这个。 22 | 23 | 现在来分析一下这一行最简单的 JavaScript 代码: 24 | 25 | ```javascript 26 | javascript:alert("Hello world") 27 | ``` 28 | 29 | 前面的 ```javascript: ```标记是告诉浏览器把随后的文本当做 JavaScript 代码来执行,而不是一个网址或搜索内容。它只是一个说明性的标记,不是 JavaScript 语言所规定的。 30 | 31 | 其后的 ```alert``` 代表一个名为 ```alert``` 的函数。函数可以用来做一些事情,你只需要用它们的名字来召唤它。例如, ```alert``` 这个函数的作用是使浏览器弹出一个对话框,在上面显示一些信息。我们将会在第五章中详细讨论函数。 32 | 33 | ```(``` 和 ```)``` 两个括号表示使用 ```alert``` 这个函数,它们像一个大嘴巴,里面装着喂给函数的东西,这对小括号承担了*调用函数*的作用,因此称为*函数调用运算符*。其中包含的 ```"Hello world"``` 是一个*字符串*,它被函数调用运算符包住了,会被喂给 ```alert``` 函数。```alert``` 函数得到了 ```"Hello world"``` 这个字符串值,便会使浏览器弹出一个对话框,对话框的信息内容是我们传入的 ```"Hello world"``` 这个字符串。包裹```Hello world```的双引号是一对*字符串标记*,这个字符串的实际内容是双引号之间的内容。 34 | 35 | 输入之后,按一下 Enter,这行代码便被浏览器运行了。就是这样! 36 | 37 | 现在我们已经了解了这行最简单的 JavaScript 代码的结构与作用,现在我们可以做一点小练习,复习我们刚才所讨论的东西。 38 | 39 | --- 40 | 41 | **练习 2.1** 42 | 43 | 1. 在浏览器地址栏中输入并运行以下代码: 44 | 45 | ```javascript 46 | javascript:alert(1 + 1 + 1 + 1) 47 | ``` 48 | 49 | 2. 在浏览器地址栏中输入并运行以下代码: 50 | 51 | ```javascript 52 | javascript:alert("1" + "1" + "1" + "1") 53 | ``` 54 | 55 | 3. 观察运行结果,试猜想为什么会这样。 56 | 57 | --- 58 | 59 | 60 | 61 | 显然,我们不可能一直呆在浏览器地址栏中。我们总不可能在浏览器地址栏中写出一个“愤怒的小鸟”游戏,也不可能写出一个 QQ 或者微信。有个地方可以让我们更加方便地编写和运行 JavaScript 代码,它的链接如下: 62 | 63 | https://art-book.github.io/runner 64 | 65 | 在这个代码输入框里,你可以这样输入 Hello world 代码: 66 | 67 | ```javascript 68 | alert("Hello world"); 69 | ``` 70 | 71 | 点击运行按钮,会得到与刚才相同的效果。 72 | 73 |  74 | 75 | 嘿,你注意到了吗:我们写的是 ```alert("Hello world");```,后面多了一个分号! 76 | 77 | 分号表示一个语句的结尾,刚才我们写下的 ```alert("Hello world");``` 是一个独立的语句,需要用分号来结束。 78 | 79 | 你已经了解了编写 JavaScript 代码的基本感觉,现在让我们来尝试一些简单有趣的代码片段,在这个 JavaScript 运行器中好好玩耍! 80 | 81 | 1)这行代码每次运行都会得到一个位于 1 和 6 之间的不一样的骰子点数。 82 | 83 | ```javascript 84 | alert("你的骰子点数是" + Math.ceil(Math.random() * 6)); 85 | ``` 86 | 87 | 2)这行代码会以 ISO 标准格式显示当前时间。 88 | 89 | ```javascript 90 | alert(new Date()); 91 | ``` 92 | 93 | 3)这行代码会弹出一个输入框,并判断你所输入的数字是奇数还是偶数。它过于简单了,如果不是数字,它也会显示“偶数”。 94 | 95 | ```javascript 96 | alert(+prompt() % 2 ? "奇数" : "偶数"); 97 | ``` 98 | 99 | 4)这行代码会把运行器页面背景调成粉色。 100 | 101 | ```javascript 102 | document.body.style.backgroundColor = "pink"; 103 | ``` 104 | 105 | 5)这行代码可以让你随意更改页面内容(提示:快捷键 Ctrl-Z 可以撤销更改) 106 | 107 | ```javascript 108 | document.body.contentEditable = true; 109 | ``` 110 | 111 | 6)这行代码会更改运行按钮的行为。当你再次点击运行按钮时,它不会再执行其它代码,而是弹出一个 “Hi” 的对话框。刷新浏览器页面即可恢复原来的样子。 112 | 113 | ```javascript 114 | document.getElementById("run").onclick = () => alert("Hi"); 115 | ``` 116 | 117 | --- 118 | 119 | **练习 2.2** 120 | 121 | 1. 尝试将运行器的页面背景改为其他颜色。总共成功尝试了几种颜色? 122 | 2. 尝试把代码 1 进行扩展,把点数可能的范围扩大到1-30 。 123 | 3. 结合代码 3 和 代码 5,尝试把运行器按钮的背景颜色调成绿色。 124 | 125 | --- 126 | 127 | -------------------------------------------------------------------------------- /数据/解构赋值.md: -------------------------------------------------------------------------------- 1 | ## 人以群分·解构赋值 2 | 3 | --- 4 | 5 | JavaScript 提供了一类语法以简化赋值操作,可以根据一组数据,一次定义一组变量,像这样: 6 | 7 | ```javascript 8 | let [a, b] = [1, 2]; 9 | alert(a); // 1 10 | alert(b); // 2 11 | ``` 12 | 13 | 等号右边是一个通常的对象/数组字面量,而等号左边就写成与右边相匹配的格式,即一个*模式*,以满足我们的需要。 14 | 15 | 它实际上是如下方式的替代: 16 | 17 | ```javascript 18 | let arr = [1, 2]; 19 | let a = arr[0]; 20 | let b = arr[1]; 21 | ``` 22 | 23 | 这类语法被称为*解构赋值*,按字面意义上来理解,就是“解析一个结构,并进行赋值”。 24 | 25 | 26 | 27 | 28 | 29 | ### 数组解构 30 | 31 | 你可以将一组变量在声明时同时进行赋值操作。 32 | 33 | ```js 34 | let arr = ["one", "two", "three"]; 35 | let [one, two, three] = arr; 36 | alert(one); // "one" 37 | alert(two); // "two" 38 | alert(three); // "three" 39 | ``` 40 | 41 | 也可以将声明与赋值分离。 42 | 43 | ```javascript 44 | let a, b; 45 | [a, b] = [1, 2]; 46 | alert(a); // 1 47 | alert(b); // 2 48 | ``` 49 | 50 | 如果一个模式没有找到相匹配的值,相应的变量就会得到 `undefined`,因为不知道到该给它赋什么值,只能说明它是“未定义”的。 51 | 52 | ```javascript 53 | let [a, b, c] = [1, 2]; 54 | alert(a); // 1 55 | alert(b); // 2 56 | alert(c); // undefined 57 | ``` 58 | 59 | 为了避免发生这种情况,可以在模式中为变量设置一个默认值。如果找不到匹配值,就使用变量的默认值。 60 | 61 | ```javascript 62 | let [a = 3, b = 4, c = 5] = [1, 2]; 63 | alert(a); // 1 64 | alert(b); // 2 65 | alert(c); // 5 66 | ``` 67 | 68 | 在一个解构赋值的表达式中我们还可以交换两个已有变量的值,以避免使用*临时变量*。 69 | 70 | ```javascript 71 | let a = 3, b = 5; 72 | [a, b] = [b, a]; 73 | alert(a); // 5 74 | alert(b); // 3 75 | 76 | // 不使用解构赋值 77 | let temp = a; 78 | a = b; 79 | b = temp; 80 | alert(a); // 5 81 | alert(b); // 3 82 | ``` 83 | 84 | 你也可以忽略你不感兴趣的值: 85 | 86 | ```js 87 | let [a, , b] = [1, 2, 3]; 88 | alert(a); // 1 89 | alert(b); // 3 90 | 91 | // 甚至忽略所有值,但是没必要这样 92 | [, ,] = [1, 2, 3]; 93 | ``` 94 | 95 | 当解构一个数组时,可以使用*剩余模式*,将数组的“剩余部分”交给一个变量。 96 | 97 | ```js 98 | let [a, ...b] = [1, 2, 3]; 99 | alert(a); // 1 100 | alert(b); // [2, 3] 101 | ``` 102 | 103 | 注意:如果剩余模式右侧有逗号,会得到一个语法错误,因为剩余元素必须是数组的最后一个元素。 104 | 105 | ```js 106 | let [a, ...b,] = [1, 2, 3]; // SyntaxError: rest element may not have a trailing comma 107 | ``` 108 | 109 | 同时,使用剩余模式赋值的变量不能被设置默认值。 110 | 111 | ```javascript 112 | let [a, ...b = 2] = [3, 4] // SyntaxError: Invalid destructuring assignment target 113 | alert("a = " + a); // 不会执行 114 | alert("b = " + b); // 不会执行 115 | ``` 116 | 117 | 用于实现剩余模式的三个点号称为*Spread 操作符*。 118 | 119 | 120 | 121 | 122 | 123 | ### 对象解构 124 | 125 | 除了数组以外,你还可以对一个对象进行解构赋值。在数组解构中,变量被赋予的值取决于它的排列顺序,而在对象解构中,变量根据对象中对应的属性名被赋予值。 126 | 127 | ```js 128 | let o = {p: 42, q: true}; 129 | let {p, q} = o; 130 | alert(p); // 42 131 | alert(q); // true 132 | ``` 133 | 134 | 通过解构,无需声明即可赋值一个变量。 135 | 136 | ```js 137 | let a, b; 138 | ({a, b} = {a: 1, b: 2}); 139 | alert(a); // 1 140 | alert(b); // 2 141 | ``` 142 | 143 | 赋值语句周围的 `( ... )` 是使用对象字面解构赋值时不需要声明的语法。`{a, b} = {a: 1, b: 2}` 不是有效的独立语法,因为左边的 `{a, b}` 被认为是一个**块语句**而不是对象字面量。然而,`({a, b} = {a: 1, b: 2})` 是有效的,相当于`let {a, b} = {a: 1, b: 2}` 144 | 145 | 146 | 147 | --- 148 | 149 | Note: 150 | 151 | 你的`( ... )` 表达式需要一个分号在它前面,否则它也许会被当成上一行中的函数来执行。 152 | 153 | --- 154 | 155 | 156 | 157 | 我们也可以根据属性,将值赋给我们需要的变量名,而不一定与属性名重名。 158 | 159 | ```js 160 | let obj = {p: 42, q: true}; 161 | let {p: a, q: b} = obj; 162 | // 相当于 163 | // a = obj.p; 164 | // b = obj.q 165 | alert(a); // 42 166 | alert(b); // true 167 | ``` 168 | 169 | 变量也可以先赋予默认值。当要提取的对象没有对应的属性,变量的值就是它的默认值。 170 | 171 | ```js 172 | let {a = 10, b = 5} = {a: 3}; 173 | alert(a); // 3 174 | alert(b); // 5 175 | ``` 176 | 177 | 可以将上述方法结合起来。 178 | 179 | ```js 180 | let {a: first = 10, b: second = 5} = {a: 3}; 181 | alert(first); // 3 182 | alert(second); // 5 183 | ``` 184 | 185 | 模式中可以像普通对象字面量那样使用计算属性名,来确定要从对象中匹配的属性值。 186 | 187 | ```js 188 | let key = "name"; 189 | let { [key]: theName } = { name: "Pluto" }; 190 | alert(theName); // "Pluto" 191 | ``` 192 | 193 | 事实上,我们还可以像数组解构那样,对对象解构应用剩余模式: 194 | 195 | ```js 196 | let {a, b, ...others} = {a: 10, b: 20, c: 30, d: 40} 197 | alert(a); // 10 198 | alert(b); // 20 199 | // others = { c: 30, d: 40 } 200 | alert(others.c); // 30 201 | alert(others.d); // 40 202 | ``` 203 | 204 | 显然,如果一个属性不能作为合法的标识符名称,就需要用一个等价的方式来代替。 205 | 206 | ```js 207 | const obj = { "hello-world": "Oh!" }; 208 | const { "hello-world": helloWorld } = obj; 209 | 210 | alert(helloWorld) // "Oh!" 211 | ``` -------------------------------------------------------------------------------- /语句/异常处理.md: -------------------------------------------------------------------------------- 1 | ## 异常处理 2 | 3 | ------ 4 | 5 | 无论我们多么精通编程,有时我们的程序仍会不可避免的遭遇到一些错误,可能单纯是我们的程序编写出错,或是接收到了与我们预期不符的用户输入,或者是其它什么原因。通常,一段代码会在出错的时候停止执行,如果只是一个用于练习的小程序可能及时排查出问题倒没什么,但如果实在一个监测生命健康,或是多人网络游戏中,程序一旦因为遇到异常而停止执行,会造成难以预料的不良后果。JavaScript 提供了一种*`try...catch` 语句*,它会在捕捉到异常的同时不会使代码停止执行,还能根据得到的异常信息做一些更为合理的操作。 6 | 7 | 8 | 9 | ### 语法 10 | 11 | `try...catch` 结构由两部分组成:`try` 和 `catch`: 12 | 13 | ```javascript 14 | try { 15 | // 代码... 16 | } catch (e) { 17 | // 处理异常 18 | } 19 | ``` 20 | 21 | 它按照以下步骤执行: 22 | 23 | - 首先,执行 `try` 子句中包含的代码。 24 | - 如果执行过程中没有异常,那么忽略 `catch` 子句里面的代码,try 子句执行完之后离开这个 `try...catch` 语句去做其他事情。 25 | - 如果执行过程中发生异常,控制流就转移到了 `catch` 子句的开头。变量` e`是一个包含了异常信息的对象,也可以取其它名称,但是 `e` 可以看做 `error`(错误)或`exception`(异常)的缩写。 26 | 27 |  28 | 29 | 30 | 31 | > 图片来源:https://mmbiz.qpic.cn/ 32 | 33 | 所以,发生在 `try`子句的异常不会使代码停止执行:我们可以在 `catch` 子句里处理异常。 34 | 35 | 36 | 37 | 38 | 39 | ### try...catch 语句的使用 40 | 41 | 让我们来看更多的例子。 42 | 43 | 没有异常的例子: 44 | 45 | ```javascript 46 | try { 47 | alert("开始运行 try 子句"); 48 | // ...这里没有异常 49 | alert("try 子句运行完毕"); 50 | } catch (err) { 51 | alert("没有任何异常,catch 子句被忽略了"); 52 | } 53 | alert("现在继续执行"); 54 | ``` 55 | 56 | 包含异常的例子: 57 | 58 | ```javascript 59 | try { 60 | alert("开始执行 try 子句"); 61 | lalala; // 异常,变量未定义! 62 | alert("try 子句执行完了"); // (2) 63 | } catch(err) { 64 | alert("捕捉一只异常!"); 65 | } 66 | alert("现在继续执行"); 67 | ``` 68 | 69 | 要使得 `try...catch `能工作,代码必须是可执行的,换句话说,它必须是有效的 JavaScript 代码。 70 | 71 | 如果代码包含语法错误,那么` try...catch` 不能正常工作,例如含有未闭合的大括号: 72 | 73 | ```javascript 74 | try { 75 | {{{{{{{{{{{{ 76 | } catch(e) { 77 | alert("这不是合法的代码,这段 catch 子句也不会被执行"); 78 | } 79 | ``` 80 | 81 | 浏览器读取然后执行代码,发生在读取代码阶段的异常被称为*解析时错误*(parse-time),`try...catch` 也对它们无可奈何,因为这样的代码浏览器就读不懂,也就无法理解 `try...catch` 语句。`try...catch` 只能处理有效代码之中的异常。这类异常被称为*运行时错误*(runtime errors),有时候也称为 “`exceptions`”。 82 | 83 | 当一个异常发生之后,JavaScript 生成一个包含异常细节的对象。这个对象会作为一个参数传递给 `catch`: 84 | 85 | ```javascript 86 | try { 87 | // ... 88 | } catch(e) { 89 | // “异常对象”,可以用其他参数名代替 90 | // ... 91 | } 92 | ``` 93 | 94 | 对于所有内置的异常,`catch` 子句捕捉到的相应的异常的对象都有两个属性: 95 | 96 | `name` :异常名称,对于一个未定义的变量,名称是 “ReferenceError” 97 | 98 | `message` :关于异常的文字描述。 99 | 100 | 还有很多非标准的属性在绝大多数环境中可用。其中使用最广泛并且被广泛支持的是: 101 | 102 | `stack` :当前的调用栈。它是用于调试的,一个包含引发异常的嵌套调用序列的字符串。 103 | 104 | 例如: 105 | 106 | ```javascript 107 | try { 108 | lalala; // 异常,变量未定义! 109 | } catch(err) { 110 | alert(err.name); // ReferenceError 111 | alert(err.message); // lalala 未定义 112 | alert(err.stack); // 异常捕获过程的细节 113 | alert(err); // ReferenceError: lalala 未定义 114 | } 115 | ``` 116 | 117 | 118 | 119 | 120 | 121 | ### 异常处理的应用 122 | 123 | 让我们一起探究一下真实使用场景中 `try...catch` 的使用。 124 | 125 | 在前面的章节中,我们了解过质数判断算法,并编写了一个循环接收用户输入并给出判断结果的程序。我们对用户输入进行了检查,如果符合要求,那么往后执行;否则的话,会给出一个错误信息并终止程序。由于是在一个 `while` 语句的循环体内,直接使用 `break` 语句就能达到终止程序的目的。但是`break`语句的本意是“停止循环“,而非“中止程序”,如果不是在循环内运行,就不能使用 `break` 语句,此外,在 `break` 语句之前还需要告知用户遇到的问题。 126 | 127 | 遇到不合法输入的问题本质是“处理异常”,而非“结束程序”,因此我们的程序应该拥有一个处理异常的机制,同时将“遇到异常,暂停程序”和“告知用户遇到的异常”优雅地结合在一起。前一个需求我们已经有了 `try...catch` 语句,而对于后一个,另一种语句可以做到:*`throw` 语句*。它可以*标记*一个异常信息,称为*抛出异常*。它的语法如下所示: 128 | 129 | ```javascript 130 | throw 表达式; 131 | ``` 132 | 133 | 当遇到 `throw` 语句的时候,程序暂停执行后面的内容,带着表达式的值一层一层地退出控制流,直到遇到外层的 `try` 子句。如果没有 `try` 子句包裹可能会抛出异常的语句,那么异常信息就会被直接告知浏览器,整个程序也就真正停止运行了。我们用一个示例来观察一下 `throw` 语句与 `try..catch` 语句的搭配使用。 134 | 135 | ```javascript 136 | try { 137 | alert("一二三四五,上山打老虎"); 138 | throw "老虎来了"; 139 | alert("老虎没打到,打到小松鼠"); 140 | } catch (e) { 141 | alert(e); 142 | } 143 | ``` 144 | 145 | 这段代码在输出 `"一二三四五,上山打老虎"`之后,遇到了 `throw` 语句,就暂停执行后面的内容。程序带着 `"老虎来了"` 的信息逃离现场,遇到 `try` 子句,就相当于吃了一记定心丸,带着强大的武器去捕捉老虎,便开始执行 `catch` 语句,同时捕获了`"老虎来了"`的异常信息,并输出它。如果 `throw` 语句的处于其它语句内部,也会使程序执行到这里就带着异常信息撤退,倘若遇到了 `try` 语句,就说明这个异常被捕获了,异常信息作为异常对象被传递给 `catch` 子句的括号里绑定的变量。 146 | 147 | 有了 `throw` 语句和 `try...catch` 语句搭配使用,程序便有了强大的异常处理机制,即便遇到“未知的危险”也可临危不惧,异常已经被抓在了 `catch` 子句的手心里,正常执行程序时也不会因可能遇到的异常而手忙脚乱。利用异常处理机制,我们来改写一下前面的质数判断程序。 148 | 149 | ```javascript 150 | let n = parseInt(prompt("请输入一个大于 1 的正整数。")); 151 | while (true) { // 循环接受输入。 152 | try { 153 | if (isNaN(n) || !isFinite(n) || n <= 1) { 154 | throw "输入不符合要求,程序停止"; 155 | } 156 | let isPrime = (n === 2) || (n % 2 !== 0); 157 | for (let i = 3, last = Math.sqrt(n); i <= last; i += 2) { 158 | if (n % i === 0) { 159 | isPrime = false; 160 | break; // 这个 break 语句只退出当前所在的循环。 161 | } 162 | } 163 | alert(`${n}是一个${isPrime ? "质数" : "合数"}`); // 使用模板字符串来拼凑信息 164 | n = parseInt(prompt("请输入一个大于 1 的正整数。")); 165 | } catch (e) { 166 | alert(e); 167 | } 168 | } 169 | ``` 170 | 171 | 原先的版本中,程序一旦接受到了不符合要求的用户输入,就会退出循环,也就停止了程序;而这里用异常处理机制改写之后,即使遇到异常,程序只会跳过这一轮的正常处理,直接告知用户,程序依然保持运行,同时“抛出”——“捕获”异常的语义性也远比原先的“输出信息”“跳出循环”要清晰得多。充分利用异常处理机制,我们能够写出更加优雅和*健壮*的代码。对于不可预知的异常输入而仍然能保持正常运行,并将信息及时展现给用户,这种性质被称为程序的*鲁棒性*。 172 | 173 | 174 | 175 | 176 | 177 | ### 异常对象 178 | 179 | -------------------------------------------------------------------------------- /语句/while和do-while语句.md: -------------------------------------------------------------------------------- 1 | ## while 和 do-while 语句 2 | 3 | --- 4 | 5 | ### 循环结构 6 | 7 | 我们将开始接触 JavaScript 中的**循环结构**。顾名思义,循环结构能够在一定条件下循环执行同一段代码,这个过程称之为*迭代*。我们可以使用 *`while` 语句*来实现循环结构。 8 | 9 | `while` 语句看起来像这样: 10 | 11 | ```javascript 12 | while (条件) { 13 | 执行语句 14 | } 15 | ``` 16 | 17 | 像 if 语句的条件一样, `while` 语句的条件是一个表达式,称为*条件*,写在一对小括号中。大括号连同其中的执行语句被称为*循环体*。如果执行语句只有一行,也可以省略包裹它的大括号。 18 | 19 | - 对条件进行求值。 20 | - 如果得到的值被看做 `true`(条件成立),那么执行一次循环。否则不执行。 21 | - 循环体执行完毕后,再次对条件进行求值,如果成立则再次循环执行,否则停止。 22 | 23 | 用一个简单的示例来演示 `while` 语句的用法: 24 | 25 | ```javascript 26 | let n = 0; 27 | let x = 0; 28 | 29 | while (n < 3) { 30 | n += 1; 31 | x += n; 32 | } 33 | 34 | alert(n); // 3 35 | alert(x); // 6 36 | ``` 37 | 38 | 在每次循环中,`n` 都会自增 `1`,然后再把 `n` 加到 `x` 上。因此,在每轮循环结束后,`x` 和 `n` 的值分别是: 39 | 40 | - 第一轮后:`n` = 1,`x` = 1 41 | - 第二轮后:`n` = 2,`x` = 3 42 | - 第三轮后:`n` = 3,`x` = 6 43 | 44 | 当完成第三轮循环后,条件 `n`< 3 的值不再为真,因此循环终止。 45 | 46 | 现在我们要考虑用 `while` 语句进行一些实际应用。我们首先回忆一下高斯小时候那个著名的故事——你一定耳熟能详,对吧? 47 | 48 | > 高斯上小学时,有一天老师出了一道算术难题:计算 1+2+3+……+100 。这下可难倒了刚学数学的小朋友们,他们按照题目的要求,正把数字一个一个地相加.可这时,却传来了高斯的声音:“老师,我已经算好了!”老师很吃惊,高斯解释道:因为1+100=101,2+99=101,3+98=101,……,49+52=101,50+51=101,而像这样的等于101的组合一共有50组,所以答案很快就可以求出:101×50=5050 49 | 50 | 哦,我们不是高斯,所以我们可以使用 `while` 语句来进行循环计算,这样就解决了其他小朋友们的痛点。我们要干的事情就像任何一个不懂计算技巧的普通的小朋友那样: 51 | 52 | 1. 使用一个变量 `n`,存放初始值 `0` 。现在什么也没有,计算还没开始。 53 | 2. 使用另一个变量 i,用来计算每次应该被加上的值。`i` 每增加 `1`,`n` 就加上 `i`,直到 `i` 等于 `100`。 54 | 3. 现在 `n` 就包含了我们累加的值。 55 | 56 | 累加的过程使用 `while` 语句来处理,写成这样: 57 | 58 | ```javascript 59 | let n = 0; 60 | let i = 0; 61 | while (i < 100) { 62 | i += 1; 63 | n += i; 64 | } 65 | 66 | alert(n); // 5050 67 | ``` 68 | 69 | 上述代码演示了 `while` 语句的基本应用。使用循环结构,可以解决我们手工计算的一些常见痛点,避免带来冗余。 70 | 71 | 实际上,你也可以将这样简单有效的运算推广到更大的范围,例如从 `1` 加到 `10000`,或 `i` 增加的值换成其他。当然,计算量越大,等待计算完成的时间也就越长,如果数字大小超过了 `Number.MAX_VALUE`,就会溢出。(还记得第三章中的相关知识吗?:-D) 72 | 73 | 一个更常见的需求是*阶乘*。在数学上,`n` 的阶乘是指 1 × 2 × 3 × ... × n 这样的计算过程,其符号是 `n!` 。 74 | 75 | 我们已经有了从 1 累加到 100 的经验,而实现阶乘,看起来只是把加法运算改为乘法运算。 76 | 77 | ```javascript 78 | let n = 1; 79 | let i = 1; 80 | while (i < 5) { 81 | i += 1; 82 | n *= i; 83 | } 84 | 85 | alert(n); // 120 86 | ``` 87 | 88 | 这段代码实现了 5 的阶乘。`i` 作为*计数器*,依然是每次加上 1 ,而作为结果的 n 每次循环中乘以 i ,并作为新值。我们可以将它的步骤展开,以更清楚地观察运行过程: 89 | 90 | 1. n = 1, i = 1 91 | 2. i = 2, n = n * i = 1 * 2 = 2 92 | 3. i = 3, n = n * i = 2 * 3 = 6 93 | 4. i = 4, n = n * i = 6 * 4 = 24 94 | 5. i = 5, n = n * i = 24 * 5 = 120 95 | 96 | 我们可以从用户那里得到一个数字,并求出它的阶乘值。 97 | 98 | ```javascript 99 | let n = 1; 100 | let i = 1; 101 | let value = parseInt(prompt("请输入一个整数:")); 102 | while (i < value) { 103 | i += 1; 104 | n *= i; 105 | } 106 | 107 | if (!isFinite(n)) { 108 | alert("数字太大了!"); 109 | } else { 110 | alert(value + "的阶乘是:" + n); 111 | } 112 | ``` 113 | 114 | 我们可以输入一些数字来进行测试。如果我们输入的数字的阶乘值太大,超出了 JavaScript 的表示范围(得到 `Infinity`),那么我们会得到一个贴心的提示。或者,得到这个阶乘值(或其约数)。看起来一切正常。 115 | 116 | 但是!当我们输入负数呢?如果我们输入的内容无法解析为整数以至于得到 `NaN` 呢?我们会得出错误的结果。 117 | 118 | ```javascript 119 | value = 0; // 1,正确 120 | value = -1; // 1,错误 121 | value = -2; // 1,错误 122 | value = "Hello"; // 1,错误 123 | ``` 124 | 125 | 关于“负数是否具有阶乘”等数学概念不在这里讨论范围内,我们应当设立明确的界限,对得到的值进行检查。如果它不符合要求,就通知用户,并不进行后续计算。 126 | 127 | ```javascript 128 | let n = 1; 129 | let i = 1; 130 | let value = parseInt(prompt("请输入一个正整数:")); 131 | 132 | if (isNaN(value) || value < 0) { 133 | alert("无法进行计算!") 134 | } else { 135 | 136 | while (i < value) { 137 | i += 1; 138 | n *= i; 139 | } 140 | 141 | if (!isFinite(n)) { 142 | alert("数字太大了!"); 143 | } else { 144 | alert(value + "的阶乘是:" + n); 145 | } 146 | } 147 | ``` 148 | 149 | 这样,我们可以保证:只有当得到一个正确的值的时候,才会进行计算。 150 | 151 | 我们还可以开动脑筋,将这个程序赋予更多创意: 152 | 153 | ```javascript 154 | let n = 1; 155 | let i = 1; 156 | let value = parseInt(prompt("请输入一个正整数:")); 157 | 158 | while (!isNaN(value) && value >= 0) { 159 | while (i < value) { 160 | i += 1; 161 | n *= i; 162 | } 163 | 164 | if (!isFinite(n)) { 165 | alert("数字太大了!"); 166 | } else { 167 | alert(value + "的阶乘是:" + n); 168 | } 169 | value = parseInt(prompt("请输入一个正整数:")); 170 | } 171 | ``` 172 | 173 | 这个程序将我们已经学习的诸多概念融合在了一起,如果你一时没看明白这个程序究竟在做什么,可以多花点时间仔细看一看。这里解释一下这个程序所干的事情: 174 | 175 | 1. 得到一个用户输入的值(`value`)。 176 | 2. 如果这个值符合我们的要求,就开始执行后续过程。 177 | 3. 进行常规阶乘计算。 178 | 4. 通知用户关于阶乘计算的情况。 179 | 5. 再次要求用户输入一个值。 180 | 6. 回到步骤 2。 181 | 182 | 这个程序演示了 `while` 语句作为控制结构的一般应用。它控制了整个程序的运行流程,这类流程被称为*控制流*。我们将在本章后续了解到如何进一步完善控制流。在这个程序中,当你输入一个不符合要求的值时,控制流便会终止。当我们学习*异常处理*的概念之后,我们可以使用更加优雅的方式来处理异常和终止的情况。 183 | 184 | 185 | 186 | 187 | 188 | ### do-while 语句 189 | 190 | `while` 语句有一种变体,称为 *`do-while` 语句*。它的形式如下: 191 | 192 | ```javascript 193 | do { 194 | 执行语句 195 | } while (条件) 196 | ``` 197 | 198 | 与通常的 `while` 语句不同的是,它的循环体写在了 `do` 关键字后面,而循环条件则放在了循环体的后面。 199 | 200 | 在第一次查看条件之前,`do-while` 语句无论如何都会先执行循环体,然后再查看条件,判断是否进行下一次循环。除此以外与通常的 `while` 语句是完全等价的。 201 | 202 | ```javascript 203 | let n = 1; 204 | let i = 1; 205 | do { 206 | i += 1; 207 | n *= i; 208 | } while (n < 5) 209 | 210 | alert(n); // 120 211 | ``` 212 | 213 | `do-while` 语句适用于需要先执行一遍,再进行条件判断的情况。 -------------------------------------------------------------------------------- /语句/switch语句.md: -------------------------------------------------------------------------------- 1 | ## switch 语句 2 | 3 | --- 4 | 5 | ### 初识 switch 语句 6 | 7 | 在前文中,我们已经学习并尝试了**分支结构**。我们将在几个示例中进一步了解它的使用。 8 | 9 | 设想一下,我们有一个有奖猜数活动,参与者可以随机输入一个 1 和 3 之间的整数,我们告诉参与者是否猜中,或与答案相差多少。利用 `if` 语句,我们可以这样写: 10 | 11 | ```javascript 12 | let number = +prompt("请输入 1 和 3 之间的整数"); 13 | 14 | if (number === 1) { 15 | alert("太小了!"); 16 | } else if (number === 2) { 17 | alert("刚刚好!"); 18 | } else if (number === 3) { 19 | alert("太大了!"); 20 | } else { 21 | alert("哦,数字超出范围!"); 22 | } 23 | ``` 24 | 25 | 我们共需依次比较三种情况,根据每种情况作出相应回应。而不在我们考虑范围内的“其他情况”则放入 else 子句中处理。在需考虑的情况较少时,使用 `if` 语句以此判断尚可应付需求,但当我们需要考虑到情况变得多,使用 `if` 语句就会显得力不从心。此外,如果我们要用相同的方式分别处理不同的情况,使用 `if` 语句会相当麻烦。 26 | 27 | 为此,JavaScript 中提供了另一种实现分支结构的语句:*`switch` 语句*。 28 | 29 | `switch` 语句的一般格式如下: 30 | 31 | ```javascript 32 | switch (表达式) { 33 | case 情况1: 处理语句1; break; 34 | case 情况2: 处理语句2; break; 35 | case 情况3: 处理语句3; break; 36 | //... 37 | default: 默认处理语句; 38 | } 39 | ``` 40 | 41 | `switch` 语句遵循这样的执行顺序: 42 | 43 | - 每个 `case` 关键字都用于标明一个情况。 44 | - JavaScript 依次查看每种情况,然后对表达式求值,查看表达式的值是否能够与这种情况匹配。 45 | - 如果匹配(严格相等),就执行冒号后的处理语句。如果以 `break;` 结尾,那么终止 `switch` 语句。 46 | - 否则,继续查看下一个情况,以此类推。 47 | - 当所有列举的情况都查看完之后,如果有一个 `default` 标志,就执行它的处理语句,作为默认情况。 48 | 49 | 前面的例子可以使用 `switch` 语句改写如下: 50 | 51 | ```javascript 52 | let number = +prompt("请输入 1 和 3 之间的整数"); 53 | 54 | switch (number) { 55 | case 1: 56 | alert("太小了!"); 57 | break; 58 | case 2: 59 | alert("刚刚好!"); 60 | break; 61 | case 3: 62 | alert("太大了!"); 63 | break; 64 | default: alert("哦,数字超出范围!"); 65 | } 66 | ``` 67 | 68 | 69 | 70 | --- 71 | 72 | 练习 4.2.1 73 | 74 | 1. 找到一个可以使用 switch 进行处理的生活中的例子,并编写程序实现它。 75 | 76 | --- 77 | 78 | 79 | 80 | 81 | 82 | ### 使用 break 83 | 84 | 让我们回忆一下 `if` 语句的机制: 85 | 86 | > 对每个条件进行查看,如果成立,就执行相应处理语句,然后结束 `if` 语句。 87 | 88 | 当我们使用 `switch` 语句的时候,我们并不一定希望在找到匹配情况后,仍然继续匹配其余情况。但是,`switch` 语句有个特点:**当它匹配到一种情况之后,会继续执行之后其他情况的处理语句,**甚至包括 `default` 。 89 | 90 | 为了模仿 `if` 语句“干完事就走人”,不拖泥带水,我们需要在每一个 `case` 的处理语句后添加一行 `break;` 。 91 | 92 | ```javascript 93 | let fruit = prompt("请输入一种水果的名字:"); 94 | 95 | switch (fruit) { 96 | case "橙子": 97 | alert("橙子卖 0.59 美元。"); 98 | break; 99 | case "苹果": 100 | alert("苹果卖 0.32 美元。"); 101 | break; 102 | case "香蕉": 103 | alert("香蕉卖 0.48 美元。"); 104 | break; 105 | case "车厘子": 106 | alert("车厘子卖 3 美元"); 107 | break; 108 | case "芒果": 109 | case "桑葚": 110 | alert("芒果和桑葚卖 2.79 美元。"); 111 | break; 112 | default: 113 | alert("抱歉,本店没有水果" + fruit + "。"); 114 | } 115 | 116 | ``` 117 | 118 | `switch` 语句每当遇到匹配的情况,执行相应处理语句后,就会终止。 119 | 120 | 如果 `break;` 后面还有处理语句,那么它不会被执行,因为 `break;` 已经起到了终止 `switch` 语句的作用。 121 | 122 | 我们使用 `switch` 语句时一般都会添加 `break;` ,这是一种良好习惯。没有添加 `break;` 以至于所有 `case` 都会被查看一遍的 `switch` 语句被称为 *switch 穿越*,可能会引发一些问题,我们将在下文中看到 switch 穿越所展现出的效果。。 123 | 124 | 125 | 126 | 127 | 128 | ### 关联操作 129 | 130 | 这个例子阐述了利用 `switch` 语句进行的关联操作。如前文所述,当我们输入一个数字并匹配之后,它会执行其后,一直第一个到 `break;` 之前的所有处理语句。 131 | 132 | ```js 133 | let value = 1; 134 | let output = "输出: " 135 | switch (value) { 136 | case 10: 137 | output += "所以"; 138 | case 1: 139 | output += "你的"; 140 | output += "名字"; 141 | case 2: 142 | output += "是"; 143 | case 3: 144 | output += "什么"; 145 | case 4: 146 | output += "?"; 147 | alert(output) 148 | break; 149 | case 5: 150 | output += "!"; 151 | alert(output); 152 | break; 153 | default: 154 | alert("请选择一个 1 到 6 之间的数字!"); 155 | } 156 | ``` 157 | 158 | 尝试改变 `value` 的值,相信你会对 switch 的机制有更深的体会。如果你不是特意为了制造出这种效果,请记得:务必在每种情况的相应处理语句末尾添加 `break;`。 159 | 160 | 161 | 162 | --- 163 | 164 | 练习 4.2.3 165 | 166 | 1. 使用 `switch` 语句的穿越特性,写一个程序,模拟一个会根据指令来问好的机器人。 167 | 168 | --- 169 | 170 | 171 | 172 | 173 | 174 | ### 分组 175 | 176 | 生活中有什么事情会像在 1 ~ 3 之间猜一个数字这样简单而乏味呢——让我们将目光投向更“实际”的问题。 177 | 178 | 现在我们摇身一变成了动物保护专家,向好奇的小朋友普及动物保护的知识,告诉他们哪些动物已经灭绝而湮没在历史中,哪些动物在悬崖边上苦苦挣扎,哪些动物暂时毫无危险。 179 | 180 | ```javascript 181 | let animal = prompt("请输入一种动物的名字:"); 182 | switch (animal) { 183 | case "猫": 184 | case "金鱼": 185 | case "鸵鸟": 186 | case "企鹅": 187 | case "火鸡": 188 | case "马": 189 | alert(animal + "没有危险!"); 190 | break; 191 | case "大象": 192 | case "熊猫": 193 | case "江豚": 194 | alert(animal + "处于危险之中,我们要一起保护它们。"); 195 | break; 196 | case "渡渡鸟": 197 | case "恐龙": 198 | case "象鸟": 199 | alert(animal + "已经灭绝。"); 200 | break; 201 | default: 202 | alert("我没听过这种动物的名字。"); 203 | } 204 | ``` 205 | 206 | 我们对小朋友提出的问题进行了分类,只用一行处理代码,统一回应相同性质的提问。 207 | 208 | ------ 209 | 210 | 练习 4.2.4 211 | 212 | 1. 思考生活中有哪些实际问题可以使用 `switch` 进行分组处理。 213 | 214 | ------ 215 | 216 | 217 | 218 | 219 | 220 | ### 使用动态条件 221 | 222 | 我们用一个小示例来结束本节。 223 | 224 | ```js 225 | let i = Math.floor(Math.random() * 7) 226 | switch (i) { 227 | case ((i >= 0 && i <= 5) ? i : -1): // 如果 0 ≤ i ≤ 5,那么待匹配的值为 i ,否则为 -1。 228 | alert("0 ~ 5"); 229 | break; 230 | case 6: 231 | alert("6"); 232 | break; 233 | } 234 | ``` 235 | 236 | 如上所示,你可以在 `switch` 语句的 `case` 中进行一些运算,以此呈现出“动态”的匹配效果。 237 | 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript 艺术之旅 2 | 3 | --- 4 | 5 |  6 | 7 |  8 | 9 | 10 | 11 |  12 | 13 | --- 14 | 15 | **绪论需要细细斟酌,因此它的内容暂时空缺。** 16 | 17 | 本书的写作计划和章节划分可参看目录,其中添加了链接的章节名称代表着已经完成,或正在写作、可预览的内容。 18 | 19 | --- 20 | 21 | 待办事项列表:[TODO](TODO.md) 22 | 23 | --- 24 | 25 | 目录 26 | ======= 27 | - Station 1 绪论 28 | 29 | - Day 0 30 | - 这片土地上的旧时光 31 | 32 | - Station 2 启程 33 | - Day 1 34 | 35 | - [千里之行,始于足下](启程/Hello-world.md) 36 | 37 | - [辟自鸿蒙](启程/表达式与值.md) 38 | 39 | - [请叫阮的名](启程/命名的值.md) 40 | 41 | - [听风知雨·更进一步](启程/更进一步.md) 42 | - Day 2 43 | 44 | - [互联网的礼服·HTML](启程/HTML.md) 45 | 46 | - Station 3 数据山谷 47 | - Day 3 48 | - [万物原动力·逻辑](数据/逻辑.md) 49 | - [宇宙谐和论·数值](数据/数值.md) 50 | - Day 4 51 | 52 | - [交流的载体·字符串](数据/字符串.md) 53 | - Day 5 54 | 55 | - [道生万物·对象](数据/对象.md) 56 | 57 | - [时空列车·数组](数据/数组.md) 58 | 59 | - [物以类聚·数据类型](数据/数据类型.md) 60 | - [数据山谷的驿站](数据/第三章练习.md) 61 | 62 | - Station 4 语句河畔 63 | - Day 6 64 | - [正义的准绳·if 语句](语句/if语句.md) 65 | - [逐一排查·switch 语句](语句/switch语句.md) 66 | - Day 7 67 | - [以车代步·while 和 do-while 语句](语句/while和do-while语句.md) 68 | - [以梦为马·for 语句](语句/for语句.md) 69 | - [见微知著·for-in 和 for-of 语句](语句/for-in和for-of语句.md) 70 | - Day 8 71 | - [欲工先利器·语句优化](语句/语句优化.md) 72 | - [人以群分·解构赋值](数据/解构赋值.md) 73 | - Day 9 74 | - [安全的保障·异常处理](语句/异常处理.md) 75 | - [语句河畔的旅馆](语句/第四章练习.md) 76 | 77 | - Station 5 函数小镇 78 | - Day 10 79 | - [化繁为简·函数初步](函数/函数初步.md) 80 | - [手可摘星辰·函数和算法](函数/函数和算法.md) 81 | - [调兵遣将·方法](函数/方法.md) 82 | - Day 11 83 | - [大道至简·高阶函数](函数/高阶函数.md) 84 | - Day 12 85 | - [聚沙成塔·递归](函数/递归.md) 86 | - Day 13 87 | - 原子和宇宙·高级主题:函数式编程 88 | - [函数小镇的时光邮局](函数/第五章练习.md) 89 | 90 | - Station 6 事件博览会 91 | - Day 14 92 | - [电光火石·事件初探](事件/事件初探.md) 93 | - [山川相缪·文档对象模型](事件/文档对象模型.md) 94 | - Day 15 95 | - [高屋建瓴·HTML 控件](事件/HTML控件.md) 96 | - [硕果可采撷·DOM 操作](事件/DOM操作.md) 97 | - Day 16 98 | - 风声鹤唳·DOM 事件和定时器 99 | - 芥子纳须弥·事件的细节 100 | - Day 17 101 | - 行走在人间·移动设备事件 102 | - Day 18 103 | - 案例研究:富文本编辑器 104 | - 事件博览会的休息室 105 | 106 | - Station 7 原理图书馆 107 | - Day 19 108 | - [本是同根生·类和原型](设计原理/类和继承.md) 109 | - Day 20 110 | - [思考自我·可见性和属性描述符](设计原理/可见性和属性描述符.md) 111 | - [迷雾清泉·求值策略](设计原理/求值策略.md) 112 | - Day 21 113 | - [人间烟火·Symbol 和迭代器](设计原理/Symbol和迭代器.md) 114 | - Day 22 115 | - 白马非马·代理对象 116 | - Day 23 117 | - [物种起源·JavaScript 标准对象](设计原理/JavaScript标准对象.md) 118 | - 原理图书馆的会客厅 119 | 120 | - Station 8 软件开发公园 121 | - Day 24 122 | - 集思广益·使用 JavaScript 库 123 | - Day 25 124 | - 百炼成钢·测试 125 | - 分秒必争·性能 126 | - Day 26 127 | - 风雨无阻·兼容性 128 | - Day 27 129 | - [山中无岁月·模块化](软件开发/模块化.md) 130 | - Day 28 131 | - [山川异域,风月同天·国际化](软件开发/国际化.md) 132 | - Day 29 133 | - .[见微知著·风格与质量](软件开发/风格与质量.md) 134 | - 软件开发公园的沉思角 135 | 136 | - Station 9 分布式广场 137 | - Day 30 138 | - 让世界相连·互联网和信息传输 139 | - 殊途同归·数据交换格式 140 | - Day 31 141 | - 世界灯火·AJAX 142 | - Day 32 143 | - 鱼跃龙门·异步操作 144 | - Day 33 145 | - 光阴逆旅·分布式应用程序 146 | - 避风港湾·安全性 147 | - Day 34 148 | - 百代过客·客户端存储技术 149 | - 分布式广场的地下室 150 | 151 | - Station 10 图形和动画乐园 152 | - Day 35 153 | - 眼见为实·计算机图形 154 | - 绝世伴侣·级联样式表 155 | - Day 36 156 | - 游刃有余·可伸缩矢量图形 157 | - 案例研究:波浪进度球 158 | - Day 37 159 | - 挥洒青春·Canvas 160 | - 案例研究:画图工具 161 | - Day 38 162 | - 俯仰自如·WebGL 163 | - 图形和动画乐园的餐厅 164 | 165 | - Station 11 忍者道场 166 | - Day 39 167 | - 计研心算·算术表达式解析 168 | - 案例研究:编程语言 169 | - Day 40 170 | - 见素抱朴·正则表达式 171 | - Day 41 172 | - 水落石出·模板 173 | - Day 42 174 | - 闻风而兴·反应式编程 175 | - Day 43 176 | - 计算机的内心·二进制数据 177 | - 忍者道场的寝室 178 | 179 | - Station 12 魔法地下河 180 | - Day 44 181 | - 互通有无·再探 HTML 5 182 | - Day 45 183 | - 让数据说话·数据可视化 184 | - Day 46 185 | - 鹰瞵鹗视·图像处理 186 | - Day 47 187 | - 绕梁三日·音频处理 188 | - Day 48 189 | - 与时俱进·智能化 Web 应用 190 | - Day 49 191 | - 似水流年·WebRTC 192 | - 魔法地下河的码头 193 | 194 | - Station 13 星辰大海 195 | - Day 50 196 | - Node.js 服务器开发 197 | - 案例研究:聊天室 198 | - Day 51 199 | - 自动化工作流 200 | - Day 52 201 | - Electron 桌面开发 202 | - 案例研究:音乐播放器 203 | - Day 53 204 | - React Native 移动开发 205 | - 案例研究:天气日历 206 | - Day 54 207 | - WebAssembly 208 | - Day 55 209 | - 起点,终点:征途无尽 210 | - 星辰大海的山洞 211 | 212 | - 旅行手册 213 | - 指南 A 214 | JavaScript 语言参考 215 | - 指南 B 216 | Unicode 指南 217 | - 指南 C 218 | [键码映射表](附录/键码映射表.md) 219 | 220 | --- 221 | 222 | ## 关于本书 223 | 224 | 六年级某节平常的信息课上,隔壁座位的男生在翻一本 JavaScript 的书。 225 | 226 | 我借过来翻了翻,从此就踏上了一条不归路。 227 | 228 | 我还记得那本书平易浅显到一个小学生掌握 JavaScript 的基础知识毫无问题, 229 | 230 | 能够做出好玩的简单 Web 应用,在 DOM 和 Canvas 上挥洒自如。 231 | 232 | 甚至连分布式计算和 WebGL 等离一个小学生太远太抽象的知识,都在头脑中烙下印记, 233 | 234 | 成为一切的起点。 235 | 236 | 本书是一本从头开始的JavaScript书, 237 | 238 | 为了纪念我小学六年级时那段温暖祥和的日子, 239 | 240 | 为了向当年的那本入门书致敬。 241 | 242 | 243 | 244 | ## 关于作者 245 | 246 | 作者目前准高一,就读于广州市第六中学。本书主要写于初二至初三前期,之后暂时停滞。 247 | 248 | 对未来有一定的打算,但是长路漫漫,行止难至。 249 | 250 | 惟有一个人不眠的夜空里,总有繁星如昼。 251 | 252 | -------------------------------------------------------------------------------- /设计原理/类和原型.md: -------------------------------------------------------------------------------- 1 | ## 类和原型 2 | 3 | ------ 4 | 5 | ### JavaScript 的类 6 | 7 | 设想一下,现在我们是一家汽车经销商,拥有随时待命的工厂。每当我们经手一辆新的汽车,我们就可以写出一个汽车对象,拥有它自己的属性。 8 | 9 | ```javascript 10 | let car = { 11 | brand: "Honda Civic", 12 | color: "blue" 13 | }; 14 | ``` 15 | 16 | 如果只有寥寥几辆的汽车需求,那么这种办法尚可接受;但是,如果汽车订单多了起来,我们恐怕不能像这样一辆辆手工生产。JavaScript 赋予了我们一种机器,可以根据设计图纸批量生产出汽车——想要多少就有多少! 17 | 18 | 我们知道,每辆汽车都属于“汽车”这类产品,同时所有的汽车都会拥有自己的 `brand` `color` 属性,我们可以制定好汽车产品的原型,每次生产时只需要说明它的品牌与颜色。现在是时候掀开这台神奇机器的面纱了! 19 | 20 | ```javascript 21 | class Car {}; 22 | ``` 23 | 24 | 嘿,等等,这是什么!`class` 是做什么的? 25 | 26 | 其实, `class` 是一个新的关键字,用于表示“一类”什么东西,用 JavaScript 的话说,是*定义了一个类*。 `Car` 就是这个类(“这类东西”)的名称,一般使用大写字母开头,这里我们定义了 `Car` 这个类以表示汽车。其后的大括号将会包含生产汽车所需要的一些工具。 27 | 28 | 有了 `Car` 类,我们就可以开动机器快速生产出一辆新的汽车。 29 | 30 | ```javascript 31 | let car = new Car(); 32 | ``` 33 | 34 | 这个写法是不是有些眼熟?我们在第三章中接触过。在第三章中,我们了解到: `new` 关键字用于*生成一个构造器的实例*,在这里 `Car` 就承担了构造器的作用,我们写下 `new Car()` ,也就相当于拥有了一辆新的汽车。 35 | 36 | 但是,我们会发现这个新的汽车并没有 `brand` 和 `color` 属性。 37 | 38 | ```javascript 39 | alert(car.brand); // undefined 40 | alert(car.color); // undefined 41 | ``` 42 | 43 | 所以,仅仅写出 `class Car` 是不够的,我们需要画好设计草图,说明这类汽车将会拥有什么属性。我们可以在 `Car` 类中写出一个名为 `constructor` 的*方法*。 44 | 45 | ```javascript 46 | class Car { 47 | constructor (brand, color) {} 48 | }; 49 | ``` 50 | 51 | 这个 `constructor` 又是做什么的呢?它就是我们将来每次生产汽车时所遵循的设计草图。它是一个特殊的方法,称为*构造函数*。就像这个名字所提示的那样,它的作用是构造一个对象。在构造一个汽车对象时我们需要做什么呢?当然是确定它的牌子与颜色。 52 | 53 | ```javascript 54 | class Car { 55 | constructor (brand, color) { 56 | this.brand = brand; 57 | this.color = color; 58 | } 59 | }; 60 | ``` 61 | 62 | 现在,我们再来生成新的汽车对象。 63 | 64 | ```javascript 65 | let car = new Car("Honda Civic", "blue"); 66 | alert(car.brand); // "Honda Civic" 67 | alert(car.color); // "blue" 68 | ``` 69 | 70 | 现在它是一辆拥有自己的属性的汽车了!我们只需要将它的品牌和颜色值当做构造函数的参数,多么容易! 71 | 72 | 现在回来看 `Car` 类的定义。它的构造函数 `constructor` 接受两个参数 `brand` 和 `color`,分别对应品牌和颜色。其后两行代码的含义是:将汽车的 `brand` 和 `color` 属性设置为参数 `brand` 和 `color` 的值。 73 | 74 | 在类的定义中,**`this` 关键字表示将会构造的对象本身,它的属性表示对象将会拥有的属性。** 75 | 76 | 也就是说,当我们写下 `this.xxx = yyy` 时,我们就说明了将来生成的对象的 `xxx` 属性的值会是 `yyy`。我们还记得第三章中引入的概念——“实例”和“实例化”——吗?现在我们可以阐述一下类所发挥的作用了。 77 | 78 | 首先,`Car` 是一个类,它拥有一个构造函数。当我们像这样:`new Car("any", "any")` 实例化一个类时,我们会接受一些参数,实际上调用了类的构造函数,并在构造函数中完成了完成了构造一个对象所需做的事情。 79 | 80 | 在 JavaScript 中,一个类是一种特殊的函数。但是它不能像通常的函数那样直接调用。 81 | 82 | ```javascript 83 | new Car("Unknown", "black"); // OK 84 | Car("Unknown", "black"); // TypeError: Class constructor Car cannot be invoked without 'new' 85 | ``` 86 | 87 | 除了 `constructor` 之外,类还可以拥有其它的方法,它们的形式像在对象字面量中一样,不过应该省略逗号。 88 | 89 | ```javascript 90 | class Car { 91 | constructor (brand, color) { 92 | this.brand = brand; 93 | this.color = color; 94 | } 95 | toString () { 96 | return `This car's brand is ${this.brand} and its color is ${this.color}.`; 97 | } 98 | } 99 | let car = new Car("Byd Auto", "silver"); 100 | alert(car.toString()); // "This car's brand is Byd Auto and its color is silver." 101 | ``` 102 | 103 | 所有的类都具有一个 `prototype` 属性,它是所有实例的*原型*,用于规定类的定义中所包含的东西。在一个类中, `this` 关键字实际上指这个原型。我们可以手动为原型的属性赋值,但是请注意:**我们在 `prototype` 属性上手动定义的方法,是无法访问 `this` 的。**也就是说,如果我们要为类添加构造函数或其他方法,必须在类的定义里面。 104 | 105 | ```javascript 106 | class Car {}; 107 | Car.prototype.model = "Unkonw"; // 默认 108 | Car.prototype.color = "black"; // 默认 109 | 110 | // 这个构造函数无法对 this 进行操作! 111 | Car.prototype.constructor = () => { 112 | this.model = "Saic Motor"; 113 | this.color = "white"; 114 | } 115 | let car = new Car() 116 | alert(car.model); // "Unknown" 117 | alert(car.color); // "black" 118 | ``` 119 | 120 | 121 | 122 | 123 | 124 | ### 面向对象 125 | 126 | 在前面章节的示例中,一个程序通常由几个函数组成,一个函数负责一项功能,几个函数组合起来完成程序的任务,最后写几个语句来调用函数。函数在对象中,就成了方法——它看起来只是把函数的位置转移到了对象中而已。 127 | 128 | 但是现在,我们可以将“要做什么事情”交给对象自己来管理,而一个完整的程序,实际上就是对不同对象的操作。我们可以使用对象和类作为程序组织的基本结构,程序所做的事情由不同的对象进行处理,而不是像先前那样写出一堆零散的函数和流程。这种程序设计的思想称为*面向对象编程*。 129 | 130 | > 面向对象程序设计是一种程序开发的抽象方针。它可能包含数据、属性、代码与方法,对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关联的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。 131 | > 132 | > ——Wikipedia 133 | 134 | Wikipedia 描述了面向对象程序设计的基本概念,更专业的叫法是“面向对象范式”。从面向对象的角度来看,应用程序是一组彼此通信的“对象”。具有一些相似特征的对象可以用相同方式构造出来,承担这一任务的就是类。对象和类一般都是基于现实世界中的事物,例如仓库中的产品或是一个自然人。对象包含数据,并根据其数据执行一些操作,而一个类则是用于构造对象的模板。对象之间用接口来互通有无,将接口与实现分离。这是一个好主意,它通常称为*封装*。 135 | 136 | 听起来是否有些熟悉——我们在第五章的开头部分就阐述过将操作的细节封装在不同函数的概念。只不过,面向对象的思考方式更进一步:它使函数抱团合体,使数据得以妥善保存与操作,使应用程序成为一个有机的整体。 137 | 138 | JavaScript 中的面向对象方式是*基于原型*的,所有的对象都由某一个类构造而来,每个类都具有一个 `prototype` 属性,它本身是一个对象的模板,当我们实例化一个对象时,就会根据类的 `prototype` 确定对象会包含什么内容,同时执行构造函数,完成实例化时需要做的一些工作,类的 `prototype` 属性就是实例对象的“原型”。在 JavaScript 中,我们可以通过包含已有的原型,来设计新的原型,这个过程称为*继承*,我们将在下一小节中了解到。 139 | 140 | 所有对象的都有一个共同的祖先,它是一个类,称为 `Object`,意思就是“对象”。它的原型包括了任何对象都应该具有的一些信息。是不是有些眼熟?我们已经在第三章接触对象时见到了它。我们还记得,当我们实例化(`new`)`Object` 时,我们便会得到一个空对象。`Object` 类和原型具有许多细节,我们将在后面的章节中详细了解。 141 | 142 | 面向对象是一种思想,它为我们指导了编写出具有专业性的代码的方式,它的基本形式是将一切数据看做一个个互相关联又彼此独立的对象,将程序的运作转化为对象之间的交流,它的重要特点是**隐藏对象的状态**,同时使我们的注意力放在如何操作对象,而非零散的“流水账式”的编程。在这个过程中,类的作用是**为我们定制我们需要的对象**。 143 | 144 | 145 | 146 | 147 | 148 | ### 继承 149 | 150 | 假设我们就像楚辞中的司命神一样掌管人类的寿夭轮回、生息繁衍,用一个类来概述世间所有人类的本质。 151 | 152 | ```javascript 153 | class Human 154 | { 155 | constructor (name, age) { 156 | this.name = name; 157 | this.age = age; 158 | } 159 | } 160 | 161 | ``` 162 | 163 | 164 | 165 | 我们知道下述事实: 166 | 167 | ``` 168 | 人类的概念包括成年人和儿童。 169 | ``` 170 | 171 | 172 | 173 | 在面向对象相关的技术中,“抽象基类”这个术语常用来描述一个 174 | 175 | 176 | 177 | 178 | 179 | ### 原型链 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /语句/if语句.md: -------------------------------------------------------------------------------- 1 | ## if 语句 2 | 3 | ------ 4 | 5 | 我们已经在第三章中了解了 JavaScript 中数据的使用,掌握到的预备知识是我们具备了随心所欲操控数据的能力,在这一章中我们将学习 JavaScript 中的*语句*,以编写出“真正的”程序,并逐步将我们头脑中的逻辑,转化为程序真切的运行过程。 6 | 7 | 在前面的运行示例中,我们接触到的都是顺序结构,即程序从第一条语句,逐行执行到结尾,而在这一章中我们将了解到*分支结构*和*循环结构*。 8 | 9 | 我们首先要学习的是 *`if` 语句*。它用于实现分支结构。 10 | 11 | 想象一下,当我们要去买芹菜的时候,我们会执行这样的过程: 12 | 13 | 1. 出门,找到菜市场 14 | 2. 挑选芹菜 15 | 3. 付钱,将菜带回家。 16 | 17 | 这就是我们所说的顺序结构。但实际上,我们买菜可能会经历这样的过程: 18 | 19 | 1. 出门,找到菜市场 20 | 21 | 2. 寻找卖芹菜的摊位 22 | 23 | 如果有卖芹菜的 24 | 25 | 1. 买一斤芹菜 26 | 27 | 2. 称重,付款,回家 28 | 29 | 30 | 如果没有卖芹菜的 31 | 32 | 1. 看看有没有其他适合的蔬菜 33 | 2. 称重,付款,回家 34 | 35 | 以上过程的结构称为*分支结构*,我们可以用 `if` 语句来在程序中实现分支结构,它的*语法*是这样的: 36 | 37 | ```javascript 38 | if (条件) { 39 | 执行语句 40 | } 41 | ``` 42 | 43 | 一条 `if` 语句以关键字 `if` 开头,其后跟随一对括号,括号中是一个逻辑表达式,用于表示执行语句的条件。 44 | 45 | 例如: 46 | 47 | ```javascript 48 | let a = 4; 49 | if (a > 3) { 50 | alert("a 大于 3"); 51 | } 52 | ``` 53 | 54 | 这段代码中的 `if` 语句的条件是 `a > 3`,所执行的语句是 `alert("a 大于 3");` 。显然,`a` 大于 `3`,因此条件成立(逻辑表达式得到 `true`),那么执行大括号中的语句——显示出 `"a 大于 3"` 这行内容。 55 | 56 | `if` 语句只管理它大括号中的内容,其他部分不受条件影响。 57 | 58 | 倘若我们要考虑两种情况(如示例中的“有卖芹菜的摊位”与“没有卖芹菜的摊位”),那么我们可以使用 `if` 语句的另一种形式。 59 | 60 | ```javascript 61 | if (条件) { 62 | 语句1 63 | } else { 64 | 语句2 65 | } 66 | ``` 67 | 68 | 这种形式的作用是:如果条件成立,那么执行代码1中的内容,否则,执行代码2。 69 | 70 | `else` 关键字所*引导*的内容称为 *else 子句*,它用于说明“条件不成立”这一情况。 71 | 72 | 示例: 73 | 74 | ```javascript 75 | let a = 4; 76 | if (a > 5) { 77 | alert("a 大于 5"); 78 | } else { 79 | alert("a 小于等于 5"); 80 | } 81 | ``` 82 | 83 | 在示例中,由于 `a` 的值为 `4`,`if` 语句的判断条件不成立(得到 `false`),所以不会显示 `"a 大于 5"`,而是执行 `else` 子句中的语句,显示 `"a 小于等于 5"`。如果 `a` 的值大于 `5`,符合判断条件的话,那么就会显示 `"a 大于 5"`。 84 | 85 | 我们似乎已经能够处理条件成立和不成立两种情况了。但现实生活比这复杂的多,我们可能会遇到许多其他情况,需要对每种情况一一加以判断并分别作出相应决定。在 JavaScript 中,我们可以使用 `if` 语句的高级形式,像这样: 86 | 87 | ```javascript 88 | let score = 85; 89 | if (score >= 90) { 90 | alert("优秀"); 91 | } else if (score >= 80) { 92 | alert("良好"); 93 | } else if (score >= 60) { 94 | alert("及格"); 95 | } else { 96 | alert("不及格"); 97 | } 98 | ``` 99 | 100 | 上述代码模拟了一种常见情景:将成绩分为不同层次,并作出对应通知。 101 | 102 | 它的执行过程会先从第一个条件开始,如果条件成立,那么执行其后的语句;如果条件不成立,那么尝试判断第二个条件,若成立则执行相应语句,否则判断第三个条件……直到最后一条 `else` 子句,即当所有可能条件都不成立时,执行其中的语句。在上述代码中,分数大于等于 `80`,我们便得到了“良好”。 103 | 104 | 我们在第三章已经阐述过,JavaScript 会将一些值视为“真”,另一些视为“假”,以此进行逻辑运算,而不仅仅是局限于布尔值。同样,在 `if` 语句的条件并不要求得到一个布尔值,只要得到的值被视作“真”,就会执行相应语句。 105 | 106 | 因此,假如我们有如下代码: 107 | 108 | ```javascript 109 | // 判断一个数字是奇数还是偶数。 110 | // 如果它除以 2 的余数为 0,即能被 2 整除,那么是偶数。 111 | // 否则为奇数。 112 | let number = 100; 113 | if (number % 2 === 0) { 114 | alert("偶数"); 115 | } else { 116 | alert("奇数") 117 | } 118 | ``` 119 | 120 | 当条件的值为 0 时,它会被当做假,那么我们可以用更方便的形式书写条件: 121 | 122 | ```javascript 123 | let number = 100; 124 | if (number % 2) { // 余数不为 0,会当做“真” 125 | alert("奇数"); 126 | } else { // 余数为 0,会当做“假” 127 | alert("偶数") 128 | } 129 | ``` 130 | 131 | `if` 语句是我们接触到的第一个 JavaScript 控制语句。我们可以用它来描述真实世界中的各类选择。 132 | 133 | 一条简洁明快的 `if` 语句,将一切分成了真假两个世界,中间隔着逻辑这条天河,它向何处流动,取决于你的思考。逻辑的伟力在于泾渭分明,逻辑的生命在于它所带来的不容逾越的秩序。 134 | 135 | 136 | 137 | --- 138 | 139 | 练习 4.1.1 140 | 141 | 1. 写一个幸运转盘的程序,每次根据一个随机数字的范围来决定颁发什么奖品。 142 | 2. 写一个程序,让用户输入出生年份,判断用户的生肖属相。如果不是一个合理的年份,就显示一个错误。 143 | 144 | --- 145 | 146 | 147 | 148 | 我们可以用 `if` 语句来处理一些生活中常见的、需要进行繁琐的分类讨论的问题,例如个人所得税的计算。 149 | 150 | 假设我们的父母(成年人也可以假设为自己)是工薪阶层,每个月都可能需要根据月收入缴纳一笔个人所得税,数额会被划分为不同的层级,面临的税率和所要缴纳的相应税款也不一样。根据中国法律规定,个人所得税的起征点是 3500 元。 151 | 152 | > 在实际工作中,对于某些个人所得收入采用税后收入的概念,比如支付税后多少多少金额。这时,需要将税后的收入按一定公式换算为应税所得,然后再按照一般方法计算应交的税款。否则,将导致税款的少征。这里,在换算为应税所得过程中需要适用的税率及速算扣除数不能按照含税级距的税率表来套用,必须使用不含税级距的税率表。这就是不含税级距税率表产生的原因。这里的不含税级距指的是“税后收入”级距。 153 | 154 | 截止到 2011 年,中国的个人所得税税率如下表所示: 155 | 156 | | 级数 | 含税级距 | 不含税级距 | 税率(%) | 速算扣除数 | 157 | | ---- | ---------------------------- | ---------------------------- | ------- | ---------- | 158 | | 1 | 不超过1500元 | 不超过1455元的 | 3 | 0 | 159 | | 2 | 超过1500元至4,500元的部分 | 超过1455元至4,155元的部分 | 10 | 105 | 160 | | 3 | 超过4,500元至9,000元的部分 | 超过4,155元至7,755元的部分 | 20 | 555 | 161 | | 4 | 超过9,000元至35,000元的部分 | 超过7,755元至27,255元的部分 | 25 | 1,005 | 162 | | 5 | 超过35,000元至55,000元的部分 | 超过27,255元至41,255元的部分 | 30 | 2,755 | 163 | | 6 | 超过55,000元至80,000元的部分 | 超过31,375元至45,375元的部分 | 35 | 5,505 | 164 | | 7 | 超过80,000元的部分 | 超过57,505的部分 | 45 | 13,505 | 165 | 166 | 备注: 167 | 168 | - 本表含税级距指以每月收入额减除费用 **3500 元**后的余额或者减除附加减除费用后的余额。 169 | - 含税级距适用于由纳税人负担税款的工资、薪金所得。 170 | - 不含税级距适用于由他人(单位)代付税款的工资、薪金所得。 171 | 172 | 我们可以根据税率的级数进行分类讨论,有点像中学数学课上学过的分段函数。 173 | 174 | ```javascript 175 | let income = parseFloat(prompt("请输入原始收入")); 176 | 177 | let basic = 3500; // 个人所得税起征点 178 | let gap = income - basic; // 税前收入与起征点之差 179 | let tax = 0; // 应付税额 180 | if (gap <= 0) { 181 | tax = 0; 182 | } else if (gap > 0 && gap <= 1500) { 183 | tax = gap * 0.03; 184 | } else if (gap > 1500 && gap <= 4500) { 185 | tax = gap * 0.1 - 105; 186 | } else if (gap > 4500 && gap <= 9000) { 187 | tax = gap * 0.2 - 555; 188 | } else if (gap > 9000 && gap <= 35000) { 189 | tax = gap * 0.25 - 1005; 190 | } else if (gap > 35000 && gap <= 55000) { 191 | tax = gap * 0.3 - 2775; 192 | } else if (gap > 55000 && gap <= 80000) { 193 | tax = gap * 0.35 - 5505; 194 | } else { 195 | tax = gap * 0.45 - 13505; 196 | } 197 | 198 | alert(Math.floor(tax)); 199 | ``` 200 | 201 | 这个例子具有相当的实用性,要不要考虑将自己或家人的收入通过这个程序计算一下,看看是否与实际情况吻合呢? 202 | 203 | -------------------------------------------------------------------------------- /语句/for-in和for-of语句.md: -------------------------------------------------------------------------------- 1 | ## for-in 和 for-of 语句 2 | 3 | --- 4 | 5 | JavaScript 提供了 for 语句的两种变体用于更加灵活地实现遍历,不但能遍历数组的索引和值,也能遍历对象的成员,并将得到的值赋给一个变量。 6 | 7 | ### 属性遍历 8 | 9 | 我们可以使用 *`for-in` 语句*来遍历一个对象中的所有属性名称。`for-in` 语句的形式如下: 10 | 11 | ```javascript 12 | for (let 变量 in 对象) { 13 | 处理语句 14 | } 15 | ``` 16 | 17 | `for-in` 语句会依次访问对象中的每个属性的名称,并将得到的字符串存放在指定的变量中,这个过程会对每一个*可遍历*的属性都执行一次。 18 | 19 | ```javascript 20 | const person = { 21 | name: "Jason", 22 | age: 30, 23 | sex: "male", 24 | job: "teacher" 25 | }; 26 | 27 | for (let i in person) { 28 | alert(i); 29 | } 30 | // "name" 31 | // "age" 32 | // "sex" 33 | // "job" 34 | ``` 35 | 36 | 有了属性名,我们也就能同时得到它的值: 37 | 38 | ```javascript 39 | for (let i in person) { 40 | alert(person[i]); 41 | } 42 | // "Jason" 43 | // 30 44 | // "male" 45 | // "teacher" 46 | ``` 47 | 48 | 于是,我们可以简单地打印出一个对象的内容: 49 | 50 | ```javascript 51 | let s = "{\n"; 52 | for (let i in person) { 53 | s += `${i}: ${person[i]}\n`; 54 | } 55 | s += "}"; 56 | alert(s); 57 | ``` 58 | 59 | 结果如图所示: 60 | 61 |  62 | 63 | 64 | 65 | `for-in` 语句提供了对对象内容进行操作的快捷方式。在这个遍历的过程中,我们可以干许多事情。比如——给每个属性都重新起一个名字,抛弃原来的: 66 | 67 | ```javascript 68 | for (let i in person) { 69 | person["属性-" + i] = person[i]; 70 | delete person[i]; 71 | } 72 | ``` 73 | 74 | 这时再用之前的方式查看对象内容,就会看到每个属性的名字都被改变了。 75 | 76 | ``` 77 | { 78 | 属性-name: Jason 79 | 属性-age: 30 80 | 属性-sex: male 81 | 属性-job: teacher 82 | } 83 | ``` 84 | 85 | 我们还可以更进一步:为每个属性都进行编号,毕竟, `for-in` 语句的本质还是循环,可以做一些适合循环做的事情。 86 | 87 | ```javascript 88 | let count = 1; 89 | for (let i in person) { 90 | person[`第${count}个属性-${i}`] = person[i]; 91 | delete person[i]; 92 | count += 1; 93 | } 94 | // { 95 | // 第1个属性-name: Jason 96 | // 第2个属性-age: 30 97 | // 第3个属性-sex: male 98 | // 第4个属性-job: teacher 99 | // } 100 | ``` 101 | 102 | 要知道 `for-in` 语句赋予了我们随意与属性和值打交道的权力——是的,我们甚至可以*交换*属性的名称与值的位置。**当然,如果原本的值就不是一个*基本类型*,我们还是不要这样做,否则会发生奇怪的事情。** 103 | 104 | ```javascript 105 | const object = { 106 | name: "Andy", 107 | checked: true, 108 | anotherObj: { 109 | a: 1, 110 | b: 2 111 | } 112 | }; 113 | 114 | for (let i in object) { 115 | let newName = object[i]; // 将原本的值存放起来 116 | if (typeof newName !== "object") { 117 | // 它不是一个对象,目测是基本类型 118 | 119 | object[newName] = i; // 值的内容来命名一个新的属性,它的值就是原本的属性名 120 | delete object[i]; // 原来的属性还在,但我们不需要它了 121 | } 122 | } 123 | // 再用之前的方式查看一下对象里的情况 124 | // { 125 | // anotherObj: [object Object] 126 | // Andy: name 127 | // true: checked 128 | // } 129 | ``` 130 | 131 | 又是 `"[object Object]"` !恐怕你已经猜测到了我们所要避免的问题所在了。这个奇怪的东西我们将会在第七章详细讨论到,现在我们只需简单了解这一情况。 132 | 133 | 使用 `for-in` 语句,我们可以自由地查看、操作一个对象的内容。它是否使我们与对象更亲近了? 134 | 135 | --- 136 | 137 | Note:我们只能遍历一个对象中的*可枚举属性*,我们将在下文了解这些概念。 138 | 139 | --- 140 | 141 | 142 | 143 | 144 | 145 | ### 可迭代对象 146 | 147 | 不单单是对象,我们也可以使用 `for-in` 语句来遍历数组,它提供了比前一节所介绍的更为简便的方法。在第三章中我们已经知道,**数组也是一种特殊的对象,它的索引都是属性,元素就是属性的值**,我们可以使用类似的方式来遍历它。 148 | 149 | ```javascript 150 | let array = ["aa", "bb", "cc", "dd", "ee", "ff"]; 151 | for (let i in array) { 152 | alert(`${i}: ${array[i]}`); 153 | } 154 | // 0: aa 155 | // 1: bb 156 | // 2: cc 157 | // 3: dd 158 | // 4: ee 159 | // 5: ff 160 | ``` 161 | 162 | 数组与我们通常所写的对象的本质区别在于,它是*可迭代的*,也就是说每个成员的排列方式都遵循固定的顺序,我们可以通过固定的方式来依次访问每个成员。还有什么东西也是这样的呢?字符串! 163 | 164 | ```javascript 165 | let s = "Hello world"; 166 | for (let i in s) { 167 | alert(`第${i}个字符是 "${s[i]}"`); 168 | } 169 | // 第0个字符是 "H" 170 | // 第1个字符是 "e" 171 | // 第2个字符是 "l" 172 | // 第3个字符是 "l" 173 | // 第4个字符是 "o" 174 | // 第5个字符是 " " 175 | // 第6个字符是 "w" 176 | // 第7个字符是 "o" 177 | // 第8个字符是 "r" 178 | // 第9个字符是 "l" 179 | // 第10个字符是 "d" 180 | ``` 181 | 182 | 字符串可以看做“字符的数组”,也就可以通过通常的方式遍历其中包含的每一个字符。 183 | 184 | 185 | 186 | --- 187 | 188 | Note: 189 | 190 | 每一个可迭代对象都包含一个**迭代器**。迭代器涉及 JavaScript 中一些相对复杂的概念,我们将在第七章中详细了解。 191 | 192 | --- 193 | 194 | 195 | 196 | for 语句的另一种变体—— *`for-of` 语句*更关注对值的操作,当我们只需要遍历一些值时,我们就可以使用它。 197 | 198 | `for-of` 语句的形式与 `for-in` 语句类似: 199 | 200 | ```javascript 201 | for (let 变量 in 对象) { 202 | 执行操作 203 | } 204 | ``` 205 | 206 | 用 `for-of` 语句来遍历数组中的每个值会格外方便。 207 | 208 | ```javascript 209 | const arr = ["aa", "bb", "cc", "dd", "ee", "ff"]; 210 | for (let i of arr) { 211 | alert(i); 212 | } 213 | 214 | // "aa" 215 | // "bb" 216 | // "cc" 217 | // "dd" 218 | // "ee" 219 | // "ff" 220 | ``` 221 | 222 | 与 `for-in` 语句的显著不同之处在于,`for-of` 语句只能对**可遍历对象**进行遍历。如果你对一个普通对象使用 `for-of` 语句,会得到一个错误。 223 | 224 | ```javascript 225 | // person 对象就是先前的那个 226 | for (let i of person) { 227 | alert(i); 228 | } // TypeError: person is not iterable 229 | ``` 230 | 231 | 但是不必就此打住:还记得第三章中见到的 `Object.keys` `Object.values` `Object.entries` 三个函数吗?它们得到的是数组!换句话说,我们可以借助于它们来遍历普通对象! 232 | 233 | ```javascript 234 | for (let [name, value] of Object.entries(person)) { 235 | alert(`${name}: ${value}`); 236 | }; 237 | // name: Jason 238 | // age: 30 239 | // sex: male 240 | // job: teacher 241 | ``` 242 | 243 | 或者使用 `Object.values` 作为跳板,直接对值进行遍历。 244 | 245 | ```javascript 246 | for (let value of Object.values(person)) { 247 | alert(value); 248 | } 249 | // "Jason" 250 | // 30 251 | // "male" 252 | // "teacher" 253 | ``` 254 | 255 | 假如我们有一个数组,里面的元素都是对象,利用前一章中了解到的解构赋值,我们可以根据对象的属性来进行处理。 256 | 257 | ```js 258 | const peoples = [ 259 | { 260 | name: 'Mike Smith', 261 | family: { 262 | mother: 'Jane Smith', 263 | father: 'Harry Smith', 264 | sister: 'Samantha Smith' 265 | }, 266 | age: 35 267 | }, 268 | { 269 | name: 'Tom Jones', 270 | family: { 271 | mother: 'Norah Jones', 272 | father: 'Richard Jones', 273 | brother: 'Howard Jones' 274 | }, 275 | age: 25 276 | } 277 | ]; 278 | 279 | for (let {name: n, family: {father: f}} of peoples) { 280 | alert('Name: ' + n + ', Father: ' + f); 281 | } 282 | // "Name: Mike Smith, Father: Harry Smith" 283 | // "Name: Tom Jones, Father: Richard Jones" 284 | ``` 285 | 286 | 287 | 288 | 289 | 290 | -------------------------------------------------------------------------------- /设计原理/求值策略.md: -------------------------------------------------------------------------------- 1 | ## 迷雾清泉·求值策略 2 | 3 | --- 4 | 5 | ### valueOf 6 | 7 | JavaScript 通过内置的 `valueOf` 方法来将每一个对象都转换为基本值,如果一个对象自身就是基本值(如数值对象),其 `valueOf` 方法的返回值就是这个对象。如果在一个表达式里面,JavaScript 预期一个对象是基本值,就会悄悄调用这个方法,而不需要我们手动调用。每个对象都拥有 `valueOf` 方法。`Object` 类的原型拥有 `valueOf` 方法,所有对象都继承了它的 `valueOf` 方法,并根据自己的需求定义自己的 `valueOf` 以覆盖原先的。 8 | 9 | 隐式调用对象的 `valueOf` 方法以求出所需值的过程称为*求值*。只有在表达式需要一个可供计算的数值,而对象类型并不满足要求的情况下,才会自动调用 `valueOf` 方法,否则不会。对于 `Array` 等内置的类,我们可以在必要时重写它们原型上的 `valueOf` 方法,也可以直接定义一个具有 `valueOf` 成员属性的对象。 10 | 11 | ```javascript 12 | Array.prototype.valueOf = () => 100; 13 | alert([]); // 这里不需要一个数值,所以没有调用 valueOf 方法 14 | alert([] + 50); // 150 15 | 16 | alert([] + { valueOf: () => 200 }); // 300 17 | ``` 18 | 19 | 不同类型对象的 `valueOf` 方法的默认返回值: 20 | 21 | | **类型** | **返回值** | 22 | | :--------- | :------------------------------------------- | 23 | | `Array` | 返回数组对象本身。 | 24 | | `Boolean` | 布尔值本身。 | 25 | | `Date` | 从 1970 年 1 月 1 日午夜开始到现在的毫秒数。 | 26 | | `Function` | 函数本身。 | 27 | | `Number` | 数值本身。 | 28 | | `Object` | 对象本身(这是默认情况) | 29 | | `String` | 字符串值本身。 | 30 | | 其它 | Math 和 Error 对象没有 valueOf 方法。 | 31 | 32 | 假设我们有一个自己的类,需要改变它的实例的默认求值方式,可以定义这个类的专属 `valueOf` 方法,以返回我们需要的值。要注意的一点是,`valueOf` 是不应当有形参的。 33 | 34 | ```javascript 35 | class Rational { 36 | constructor(den, num) { 37 | Object.assign(this, {den, num}); 38 | } 39 | valueOf() { 40 | return [this.den, this.num]; 41 | } 42 | }; 43 | 44 | let r1 = new Rational(10, 20); 45 | alert(r1.valueOf()); // 10,20 46 | alert(r1); // 10,20 47 | ``` 48 | 49 | 重定义 `valueOf` 的一大用处就是使得我们自己的对象可以被处理为原始值并参与计算,使对象在外观上就像普通的值。我们还可以在对对象求值的时候额外执行一些操作。 50 | 51 | ```javascript 52 | class AnotherNumber { 53 | constructor(value = 0) { 54 | this.value = value; 55 | } 56 | valueOf() { 57 | return this.value; 58 | } 59 | }; 60 | 61 | let n = new AnotherNumber(100); 62 | alert(n / 20); // 5 63 | 64 | class SpecialClass { 65 | valueOf() { 66 | alert("我被求值了!"); 67 | } 68 | }; 69 | 70 | let sp = new SpecialClass(); 71 | sp.valueOf(); // "我被求值了!" 72 | sp; // 不需要数值,所以没有调用 valueOf 73 | sp && sp && sp; // 不需要数值,所以没有调用 valueOf 74 | sp + 1; // "我被求值了!" 75 | ``` 76 | 77 | 78 | 79 | 80 | 81 | ### toString 82 | 83 | JavaScript 对象中的另一个内置方法是 `toString`。当对象所处的表达式期望一个字符串参与运算,而对象本身并不是字符串时,就会隐式调用 `toString` 方法。可以理解为:`valueOf` 将对象转换为数值,而 `toString` 将对象转换为字符串形式。对于基本类型的值,`toString` 所返回的值就是这个值看起来的样子,如 `100` 转换为 `"100"`,`true` 转换为 `"true"` 等。而用对象字面量创建的对象,即“复杂对象”,情况则大不一样,它的 `toString` 方法返回一个特殊的字符串:`"[object Object]"` 。这个字符串的含义大致为“`Object` 对象”。 84 | 85 | 数组虽然也是复杂对象的一种形式,但是 `Array` 原型上的 `toString` 方法经过了重定义,可以返回这个数组自身的内容。对于数组内的每个成员,`Arrar.prototype.toString` 会进一步调用成员的 `toString` 方法,如果成员是 `null` 和 `undefined` 则会直接跳过。 86 | 87 | ```javascript 88 | let array = [1, 2, 3, 4, "Hello", true, null, undefined, "world"]; 89 | let array2 = [{ toString: () => "I am an object" }, [1, 2, 3, 4, [5, 6, 7, 8]]]; 90 | alert(array.toString()); // 1,2,3,4,Hello,true,,,world 91 | alert(array); // 1,2,3,4,Hello,true,,,world 92 | alert(array2); // I am an object,1,2,3,4,5,6,7,8 93 | ``` 94 | 95 | 函数的 `toString` 方法有些特殊,它会返回这个函数的全部定义,如果调用一个类(本质上是函数)自身而非原型的 `toString` 方法也是如此。“函数定义”所包含的字符串,是从标识这个函数的第一个字符开始,到函数体的最后一个字符。如果函数定义中包含了注释,在旧一些的浏览器中不会呈现,而在最新的浏览器中,函数定义中的注释也会被 `toString` 显示。 96 | 97 | ```javascript 98 | let f = () => 100; 99 | alert(f.toString()); 100 | alert(f); 101 | 102 | let f2 = function(a, b) { 103 | alert(a + b); 104 | }; 105 | alert(f2); // function(a, b) { 106 | // alert(a + b); 107 | // } 108 | 109 | const f3 = (a) => { 110 | let b = a + 100; 111 | return function() { 112 | return b; 113 | }; 114 | }; 115 | alert(f3); // (a) => { 116 | // let b = a + 100; 117 | // return function() { 118 | // return b; 119 | // }; 120 | // } 121 | 122 | class C { 123 | constructor() { 124 | this.value = 0; 125 | } 126 | }; 127 | alert(C); // class C { 128 | // constructor() { 129 | // this.value = 0; 130 | // } 131 | // } 132 | ``` 133 | 134 | 如果一个函数/类是原生的,那么调用它的 `toString` 方法会返回 `function 函数名/类名() { [native code] }"`。 135 | 136 | ```javascript 137 | // native code 就是“原生代码”的意思 138 | alert(alert); // "function alert() { [native code] }" 139 | alert(parseInt); // "function parseInt() { [native code] }" 140 | alert(Number); // "function Number() { [native code] }" 141 | alert(Boolean); // "function Boolean() { [native code] }" 142 | alert([].toString); // "function toString() { [native code] }" 143 | alert(Object.hasOwnProperty); // "function hasOwnProperty() { [native code] }" 144 | ``` 145 | 146 | 在 JavaScript 中,每一个类都拥有一个叫做 `[[Class]]` 的内部属性。这个内部属性意味着类的“类别”。所有内置类都具有对应的 `[[Class]]` 标识,如 `Array` 的 `[[Class]]` 是 `Array`,`Number` 的 `[[Class]]` 是 `Number` 等。`null` 和 `undefined` 也拥有以自身命名的 `[[Class]]` 标识。 147 | 148 | 而 `Object` 类以及所有我们自定义的类,其 `[[Class]]` 的值是 `Object`。访问 `[[Class]]` 的唯一办法,是用 `Object.prototype.toString.call` 调用类的实例。这样,就不是使用某个值经过重新定义的 `toString`,而是像真正的对象一样获取其 `[[Class]]` 标识。 149 | 150 | ```javascript 151 | alert(Object.prototype.toString.call(null)); // "[object Null]" 152 | alert(Object.prototype.toString.call([1, 2, 3])); // "[object Array]" 153 | alert(Object.prototype.toString.call(() => 0)); // "[object Function]" 154 | alert(Object.prototype.toString.call(new Date()); // "[object Date]" 155 | ``` 156 | 157 | 原生对象有自己的 `toString` 方法,用来标识自己。 158 | 159 | ```javascript 160 | alert(Math); // "[object Math]" 161 | alert(window); // "[object Window]" 162 | alert(document.createElement("div")); // "[object HTMLDivElement]" 163 | ``` 164 | 165 | 166 | 167 | --- 168 | 169 | Tips: 170 | 171 | 如果一个对象同时具有 `valueOf` 方法和 `toString` 方法,那么总会优先调用它的 `valueOf` 方法。 172 | 173 | --- -------------------------------------------------------------------------------- /设计原理/Symbol和迭代器.md: -------------------------------------------------------------------------------- 1 | ## 人间烟火·Symbol 和迭代器 2 | 3 | --- 4 | 5 | ### Symbol 是什么 6 | 7 | 发布于2015年的 ECMAScript 6 标准为 JavaScript 带来了一种新的原始数据类型——Symbol。就像早已存在的 `Boolean`、`Number` 和 `String` ,JavaScript 提供了一个 `Symbol` 函数来创造新的 Symbol 类型的值。但与其他原始类型不同,`Symbol` 不是类,不能用 `new` 来创建,也没有相应的字面量形式。要想使用 Symbol 值,我们唯一的方法是直接调用 `Symbol` 函数: 8 | 9 | ```javascript 10 | alert(Symbol()); // Symbol() 11 | alert(typeof Symbol()); // "symbol" 12 | alert(new Symbol()); // TypeError: Symbol is not a constructor 13 | ``` 14 | 15 | Symbol 是什么呢? 16 | 17 | 简单来说,Symbol 相当于一种*唯一标识符*,每个 Symbol 值诞生后就是独一无二的,就像枝头一片叶子长出,世界上就再也不会有另一片与它完全相同的叶子。我们可以给 Symbol 赋予一个标识,但即便是使用相同标识创建的两个 Symbol 值,它们彼此之间也是不相等的。 18 | 19 | ```javascript 20 | let s1 = Symbol(); 21 | let s2 = Symbol(); 22 | alert(s1 === s1); // true 23 | alert(s1 === s2); // false 24 | alert(s1 === Symbol()); // false 25 | 26 | let s3 = Symbol("love"); 27 | let s4 = Symbol("love"); 28 | alert(s3 === s4); // false 29 | ``` 30 | 31 | Symbol 的一大用途就是:创建独一无二的对象键名。就像一把指纹锁,当用一个 Symbol 值作为对象的键时,这个键所对应的值只有用同一个 Symbol 值才能访问到。 32 | 33 | ```javascript 34 | const NAME = Symbol(); 35 | let person = { 36 | [NAME]: "Modi" 37 | }; 38 | 39 | alert(person[NAME]); // "Modi" 40 | 41 | const AnotherNAME = Symbol(); 42 | person[AnotherNAME] = () => alert("Hello Modi"); 43 | person[AnotherNAME](); // "Hello Modi" 44 | ``` 45 | 46 | 47 | 48 | 49 | 50 | ### 迭代器 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ### 迭代协议 59 | 60 | Symbol 值本身带来的意义几乎只是为 JavaScript 增加了一种“创建唯一无二的值”的方式,但是,用于构造 Symbol 值的 `Symbol` 函数,其本身的用途却不仅仅是构造 Symbol 值这么简单。事实上,JavaScript 中许多原本保留的内部细节,都通过 `Symbol` 的一批属性暴露给了我们,这使得 `Symbol ` 包含一组非常强大的工具,能帮助我们在探究 JavaScript 的语言构造和内部设计上如虎添翼。 61 | 62 | ECMAScript 标准定义了一批用来在语言内部实现某些特性的属性,这些属性以前缀 `@@` 标记,在 ECMAScript 6 以前,它们是无法被我们直接访问到的。一个例子是`@@iterator` 方法,它会使对象成为*可迭代对象*。当需要对一个对象进行迭代时(例如在 `for...of` 语句中),它的 `@@iterator` 方法会在不传参情况下被调用,并返回一个迭代器,这个迭代器提供每次迭代所需要的值。 63 | 64 | 一些内置类拥有默认的 `@@iterator` 方法,以展现出可供迭代的性质,例如 `Array`、`String` 等,而其他类(如 `Object`)则没有。 65 | 66 | `@@iterator` 方法代表 JavaScript 中的*可迭代协议*,凡是实现了正确的 `@@iterator` 方法的对象,就符合可迭代协议,那么这个对象就是*可迭代的*。可迭代协议允许 JavaScript 对象去定义或定制它们的迭代行为,例如在 `for...of` 语句中被遍历时,有什么值会被访问到。可迭代对象就是符合迭代协议、能够展现出正确的迭代行为的对象,它们必然拥有 `@@iterator` 。 67 | 68 | 来整理一下这些术语的关系:**一些对象拥有定义正确的 `@@iterator` 内部方法,它们符合可迭代协议,是可迭代对象。它们的 `@@iterator` 方法实际上是迭代器函数,它返回一个迭代器,每次迭代时会自动得到一个值。** 69 | 70 | 为了在每次迭代时提供一个新值, `@@iterator` 方法可以被实现为一个**生成器函数**。我们不能直接访问 `@@iterator` 这样的内部方法,但是可以通过 **`Symbol.iterator`** 访问到,这是一个预定义的 `Symbol` 值。因此,我们可以像这样定义一个最简单的可迭代对象。 71 | 72 | ```javascript 73 | let it = { 74 | *[Symbol.iterator]() { 75 | yield 1; 76 | yield 2; 77 | yield 3; 78 | } 79 | }; 80 | ``` 81 | 82 | 我们看到, `it` 已经定义了正确的 `@@iterator` 方法,它现在是一个符合迭代协议的可迭代对象了。一些 JavaScript 的语法特性,在语义上只对序列有效,这就要求某个对象必须是符合可迭代协议的,例如序列展开运算符 `...`、`for...of` 语句等。来看看我们的对象能否得到认可: 83 | 84 | ```javascript 85 | alert([...it]); // 1,2,3 86 | for (let i of it) { 87 | alert(i); 88 | } 89 | // 1 90 | // 2 91 | // 3 92 | ``` 93 | 94 | 成功了!总的来说,这些语法特性依赖可迭代协议。 95 | 96 | 那么,如果一个对象实现了 `@@iterator` ,却不符合可迭代协议,会怎样呢? 97 | 98 | ```javascript 99 | let fakeIt = { 100 | [Symbol.iterator] () { 101 | return "Hello"; 102 | } 103 | }; 104 | [...fakeIt]; // TypeError: Result of the Symbol.iterator method is not an object 105 | ``` 106 | 107 | 上文中说 `@@iterator` 方法是一个迭代器函数,又说它必须被实现为一个生成器函数。那么,这些名词究竟有什么关系呢?它们的逻辑关系可以描述如下: 108 | 109 | - 生成器函数是函数,它调用后返回一个对象,这个对象是生成器。 110 | - 迭代器函数是函数,它调用后返回一个对象,这个对象是迭代器。 111 | - 生成器是迭代器的一种。 112 | 113 | 这里似乎令人一头雾水,因为我们还没有了解**迭代器**的概念。 114 | 115 | 简单来说,迭代器定义一个序列,它拥有 `next` 方法,每次调用 `next` 方法,意味着从序列中获取了下一个值。它返回一个对象,包含两个属性。 116 | 117 | - `value`,它代表本次迭代所产生的值,这个值来自预定义的序列。 118 | - `done`,如果它为 `true`,代表这个序列已经终结,不再进行迭代。如果它为 `false`,迭代还未技术,这个序列还会继续产生新值。 119 | 120 | 一个迭代器对象完成迭代过程后,我们说它被*消耗*了。在它产生序列中的最后一个值之后,`done` 方法应当被设为 `true`。 121 | 122 | 数组是最常见的序列,它本身也包含一个迭代器,即 `@@iterator`方法,这个迭代器可以依次返回数组中的每个成员。显然,因为把 `@@iterator` 定义为迭代器,所以数组本身是可迭代对象。 123 | 124 | 下面实现了一个简单的迭代器函数,它构造一个可以代表无穷序列的迭代器。 125 | 126 | ```javascript 127 | const makeIterator = (start = 0, end = Infinity, step = 1) => { 128 | let nextIndex = start; 129 | let count = 0; 130 | 131 | return { 132 | next() { 133 | let result; 134 | if (nextIndex < end) { 135 | result = { value: nextIndex, done: false } 136 | nextIndex += step; 137 | count += 1; 138 | return result; 139 | } 140 | return { value: count, done: true } 141 | } 142 | }; 143 | }; 144 | ``` 145 | 146 | 测试一下: 147 | 148 | ```javascript 149 | let it = makeIterator(1, 5); // 这个迭代器代表 1 ≤ n < 5 的正整数序列 150 | it.next(); // { value: 1, done: false} 151 | it.next(); // { value: 2, done: false} 152 | it.next(); // { value: 3, done: false} 153 | it.next(); // { value: 4, done: false} 154 | it.next(); // { value: 4, done: true} 155 | ``` 156 | 157 | 158 | 159 | --- 160 | 161 | Note: 162 | 163 | 注意:可迭代协议和迭代器协议是两个容易混淆的不同概念。 164 | 165 | - 迭代器协议要求对象拥有 `next` 方法,使一个对象可以预定义一个序列,并且每次迭代时按顺序提供序列的值。这种对象叫**迭代器**。 166 | - 可迭代协议要求对象拥有 `@@iterator` 方法,这个方法应当是一个迭代器,它从外观上呈现为一个序列,实际上是还原了迭代器所定义的序列。**这个对象是可迭代对象。** 167 | 168 | 迭代器和可迭代对象的关系可以描述为发动机和汽车。可迭代对象像汽车,可以在道路上行使,但真正驱动它的是迭代器这台发动机。 169 | 170 | 可迭代协议和迭代器协议统称为迭代协议。 171 | 172 | --- 173 | 174 | 175 | 176 | 我们也可以把 `makeIterator` 作为一个另一个对象的 `@@iterator` 方法,构造一个新的可迭代对象: 177 | 178 | ```javascript 179 | let happyObject = { 180 | // 不能直接把 makeIterator 作为 @@iterator 的值,因为这样会构造无穷序列 181 | [Symbol.iterator]: () => makeIterator(1, 10) 182 | }; 183 | 184 | alert([...happyObject]); // 1,2,3,4,5,6,7,8,9 185 | ``` 186 | 187 | 我们看到,只要对象有一个符合迭代器协议的`@@iterator` 方法,它本身就符合可迭代协议,成为可迭代对象。这样就可以回答前面的问题了:生成器函数是 JavaScript 内置的一种默认迭代器函数,它可以便捷地提供可迭代对象所需要的序列。其实一个对象既可以是可迭代对象,又可以是迭代器,要做到这点十分容易。 188 | 189 | 用一个更进一步的例子来结束有关迭代协议的内容,这个例子会构造一段序列,包含 $ 1 \le n \lt 40 $ 的所有奇数。 190 | 191 | ```javascript 192 | // 建立一个迭代器函数 193 | const oggIterator = () => { 194 | let nextIndex = 1; 195 | let count = 0; 196 | 197 | return { 198 | next() { 199 | let result = { value: count, done: true }; 200 | if (nextIndex < 40) { 201 | result = { value: nextIndex, done: false } 202 | nextIndex += step; 203 | count += 2; 204 | return result; 205 | } 206 | return result; 207 | }; 208 | }; 209 | }; 210 | 211 | // 进一步构造成可迭代对象 212 | let oggObject = { 213 | [Symbol.iterator]: oggIterator 214 | }; 215 | alert([...oggIterator]); 216 | // 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39 217 | ``` 218 | 219 | 220 | 221 | --- 222 | 223 | 练习 7.4.2 224 | 225 | 1. 编写一个构造完全平方数序列的迭代器,上限自定。 226 | 2. 利用上一个练习中的迭代器,编写一个可迭代对象,将其构造为数组。 227 | 228 | --- -------------------------------------------------------------------------------- /语句/for语句.md: -------------------------------------------------------------------------------- 1 | ## for 语句 2 | 3 | --- 4 | 5 | ### 基本概念 6 | 7 | while 和 do-while 语句可以用于实现循环结构,除此以外,JavaScript 中提供了另一种更加灵活快捷的方式来进行循环(或者叫迭代):*`for` 语句*。 8 | 9 | 一个 `for` 语句看起来像这样: 10 | 11 | ```javascript 12 | for (初始化表达式; 条件; 增量表达式) { 13 | 执行语句 14 | } 15 | ``` 16 | 17 | 等等,`for` 语句的小括号中包含了三个东西!它们都是什么? 18 | 19 | 首先是*初始化表达式*。它用于说明哪些值会被用在循环中。例如,在上一节的阶乘示例中,我们在进行计算之前要先设置变量 `i` 和 `n` 的值为 `1`,这类操作就是*初始化*。你可以将初始化的操作直接放在 `for` 语句里,称为初始化表达式。 20 | 21 | 初始化表达式的分号后面是*条件*,它表示控制循环进行的条件,与 while 语句是一致的。 22 | 23 | 而*增量表达式*用于在每次循环后,改变控制循环的变量的值,以此达到控制循环次数的作用。 24 | 25 | 事不宜迟,用一个简单的示例来看一下 `for` 语句的使用: 26 | 27 | ```javascript 28 | for (let i = 0; i < 5; i += 1) { 29 | alert(i); 30 | } 31 | // 0 32 | // 1 33 | // 2 34 | // 3 35 | // 4 36 | ``` 37 | 38 | 1. 首先设置控制循环的变量 `i` 的值为 `0`。 39 | 2. 查看 `i` 的值是否满足条件。 40 | 3. 满足,那么执行循环体的语句,显示出 `i` 的值。 41 | 4. 循环体结束,根据增量表达式,改变 `i` 的值,为下一次循环做准备。 42 | 5. 回到步骤 2。 43 | 44 | 如果 `i` 的值一开始就不满足条件,那么循环体一次也不会被执行,像 while 语句一样。 45 | 46 | 上一节中的计算 1 + 2 + 3 + ... + 100 的示例,使用 `for` 语句可以改写如下: 47 | 48 | ```javascript 49 | let n = 0; 50 | for (let i = 1; i < 100; i += 1) { 51 | n += i; 52 | } 53 | alert(n); // 5050 54 | ``` 55 | 56 | 我们使用 `i` 作为控制循环的变量,每次循环后它的值便会 +1 ,同时 `i` 也起到了从 1 增长到 100 ,用于使 `n` 进行累加的作用。 57 | 58 | 事实上,为了充分利用 `for` 语句,我们还可以更进一步: 59 | 60 | ```javascript 61 | for (let i = 1, n = 0; i < 100; i += 1, n += i) { 62 | 63 | } 64 | alert(n); // 5050 65 | ``` 66 | 67 | 我们可以在初始化表达式的位置上写几个用于进行初始化的表达式,只需使用逗号隔开。 68 | 69 | 同样,增量表达式也可以对不同的变量进行增量处理。它的求值顺序是从左到右的,也就是说,先计算了 `i += 1` ,然后再处理 `n += 1`。 70 | 71 | 如果我们的循环体没有语句,我们根本就不用写大括号,直接省略就好了!。 72 | 73 | ```javascript 74 | for (let i = 1, n = 0; i < 100; i += 1, n += i) 75 | 76 | alert(n); 77 | ``` 78 | 79 | 但是运行这段代码,就会发现,`alert` 不会在循环结束后执行,而是每进行一次循环都会显示一次当前 `n` 的值。因此,你一共要点一百次“确认”,直到循环结束。 80 | 81 | 现在,刷新页面,一切恢复正常。 82 | 83 | 为什么会这样?因为 `for` 语句和 while 语句一样,如果没有写大括号,会将循环头部(即一对小括号包裹的内容)的后面遇到的第一个语句当做是循环体,因此 `alert(n)` 被循环执行了。解决这个问题的办法是在循环头部后面写一个分号 `;` ,用一个*空语句*来代替循环体。 84 | 85 | ```javascript 86 | for (let i = 1, n = 0; i < 100; i += 1, n += i) ; 87 | // ; (更推荐写在第二行) 88 | alert(n); // 5050 89 | ``` 90 | 91 | 92 | 93 | --- 94 | 95 | 练习 4.4.1 96 | 97 | 1. 创建一个 1 ~ 100 的循环,当数字 `n` 是奇数时,打印 “ `n`是奇数”,否则打印“`n`是偶数”。 98 | 99 | 提示:使用运行器提供的 `document.write` 函数来进行“打印”操作。 100 | 101 | 2. 显示一个九九乘法表,使用 `document.writeln` 函数来打印每一行。 102 | 103 | 提示:你需要将一个 `for` 语句写在另一个内部,使用它们的控制变量来输出因数。 104 | 105 | 106 | 107 | 108 | 109 | 110 | ### 迭代算法 111 | 112 | 我们在这里第一次接触*算法*一词。Wikipedia 对此的定义如下: 113 | 114 | > 在数学和计算机科学中,**算法**是一个明确的、关于如何解决一类问题的规范。算法可以执行计算,数据处理、自动推理和其他任务。算法可以在有限的空间和时间内表达。从初始状态和初始输入开始,描述了一系列计算,当执行时,通过有限个明确定义的连续状态,最终产生“输出” ,并终止于最终结束状态。 115 | 116 | 当我们要实现某种功能时,我们将会用精确的语言,描述我们所要实施的步骤。例如在上文中对于循环过程的描述就叫算法。迭代算法则是用迭代等方式实现的算法,通俗来讲,使用循环和条件控制来进行一系列运算,以得到我们需要的结果。上文中的累加和阶乘等运算就属于迭代算法。 117 | 118 | 我们将会在本节深入了解迭代算法,一个常见的实际应用就是检测一个数是否为质数。 119 | 120 | 如果你忘记了什么叫质数,我们可以先复习一下小学数学书上对于质数的描述: 121 | 122 | > 如果一个大于 1 的整数只有 1 和它本身两个因数,那么它就是一个质数,否则就是合数。 123 | > 124 | > 2 是最小的质数,1 既不是质数也不是合数。 125 | 126 | 换句话说,一个整数如果大于 1,并且不能整除除 1 以外的所有比它小的整数,那么它就是一个质数。 127 | 128 | 我们很快就可以得到判断一个数 n 是否为质数的思路: 129 | 130 | 1. 如果这个数不大于 1 或不为整数,那么它必定不是质数。 131 | 2. 从 2 开始,列举从 2 到 n-1 的所有整数,用 n 除以列举的数。 132 | 3. 如果得到的余数为 0,说明 n 可以整除它,那么 n 不是质数。 133 | 4. 如果列举完后也没有找到一个数可以被 n 整除,那么 n 是质数。 134 | 135 | 我们可以根据这个思路尝试写出代码,列举数字的工作自然就交给 `for` 语句。 136 | 137 | ```javascript 138 | let n = 100; 139 | let isPrime = true; // 假设它是一个质数 140 | for (let i = 2; i < n; i += 1) { 141 | if (n % i === 0) { 142 | isPrime = false; 143 | } 144 | } 145 | alert(isPrime ? "质数" : "合数"); // "合数" 146 | ``` 147 | 148 | 通过列举它可能的因数,尝试进行整除,这种策略称为*试除法*。 149 | 150 | 这个代码可以正常工作,但我们很快就发现了它的问题:当我们发现 `n` 不是一个质数的时候,应该终止计算并告知结果。但是这里,即使我们发现了 `n` 是合数,`for` 语句也不会停下来,又白白将剩下的循环运行完。 151 | 152 | 因此,我们应当采取策略:当我们知道它不是一个质数的时候,我们就不再进行试除了,而是报告结果。 153 | 154 | ```javascript 155 | let n = 100; 156 | let isPrime = true; // 假设它是一个质数 157 | for (let i = 2; i < n; i += 1) { 158 | if (n % i === 0) { 159 | isPrime = false; 160 | break; 161 | } 162 | } 163 | alert(isPrime ? "质数" : "合数"); // "合数" 164 | ``` 165 | 166 | 这里再次出现了 `break;` 语句。它在这里的作用是**直接终止循环**。 167 | 168 | 169 | 170 | 我们知道,一个合数最大的因数不会超过它的平方根,例如 100 最大的因数就是 10 ,判断一个整数是否为质数,只需列举到它的平方根进行试除就足够了: 171 | 172 | ```javascript 173 | let n = 100; 174 | let isPrime = true; // 假设它是一个质数 175 | for (let i = 2, last = Math.sqrt(n); i <= last; i += 1) { 176 | if (n % i === 0) { 177 | isPrime = false; 178 | break; 179 | } 180 | } 181 | alert(isPrime ? "质数" : "合数"); // "合数" 182 | ``` 183 | 184 | 由于除了 2 以外的所有质数都是奇数,因此我们可以进行一个简单的判断: 185 | 186 | - 如果输入的数字是 2 ,那么它是一个质数。 187 | - 如果输入的数字不是 2,但能被 2 整除,那么它是一个合数。 188 | - 从 3 开始列举它的因数,每次 +2,使列举的值始终是奇数。 189 | 190 | ```javascript 191 | let n = 100; 192 | let isPrime = (n === 2) || (n % 2 !== 0); 193 | for (let i = 3, last = Math.sqrt(n); i <= last; i += 2) { 194 | if (n % i === 0) { 195 | isPrime = false; 196 | break; 197 | } 198 | } 199 | alert(isPrime ? "质数" : "合数"); // "合数" 200 | ``` 201 | 202 | 203 | 204 | 我们的程序可以用于处理用户输入并得到结果了,不过务必记得进行输入检查。 205 | 206 | ```javascript 207 | let n = parseInt(prompt("请输入一个大于 1 的正整数。")); 208 | while (true) { // 循环接受输入。 209 | if (isNaN(n) || !isFinite(n) || n <= 1) { 210 | alert("输入不符合要求,程序停止"); 211 | break; // 如果输入不符合要求,就停止循环接受输入。 212 | } 213 | 214 | let isPrime = (n === 2) || (n % 2 !== 0); 215 | for (let i = 3, last = Math.sqrt(n); i <= last; i += 2) { 216 | if (n % i === 0) { 217 | isPrime = false; 218 | break; // 这个 break 语句只退出当前所在的循环。 219 | } 220 | } 221 | alert(`${n}是一个${isPrime ? "质数" : "合数"}`); // 使用模板字符串来拼凑信息 222 | n = parseInt(prompt("请输入一个大于 1 的正整数。")); 223 | } 224 | ``` 225 | 226 | 我们的质数判断程序遵循的基本流程是“输入-处理-输出”。为了避免每次输出后都要重新运行才能开始新的流程,我们可以用一个循环将流程包进去。由于我们已经认识了 break 语句,因此可以自由决定 while 循环何时终止。循环头的条件用 `true` 来表示“条件始终成立”,表示它不再管条件判断,只需不断进行循环以重复相同的流程。这样的程序称为“Read-Eval-Print Loop”(输入-处理-输出循环),缩写为 **REPL**。 227 | 228 | 229 | 230 | --- 231 | 232 | 练习 4.4.2 233 | 234 | 1. 本节提供了一个完整的用于判断质数的 REPL 示例程序,请在此基础上对它进行修改:如果 `n` 是一个合数,那么同时显示发现的第一个因数。 235 | 236 | 2. 对本节的示例程序进行扩充,接受一个用户输入的整数 n,查找 2 ~ n 范围内的所有质数并显示。 237 | 238 | (提示:将找到的质数放在数组中) 239 | 240 | --- 241 | 242 | 243 | 244 | 245 | 246 | ### 数组遍历 247 | 248 | 假如我们有一列排列整齐的课桌,每张课桌上都写着使用它的学生的姓名,现在我们要依次浏览并记录每张课桌上的姓名,最直观的的办法显然是:从第一张课桌开始,记录课桌上的信息,然后走到下一个课桌,以此类推。 249 | 250 | 这个过程用精确的语言描述一下: 251 | 252 | 1. 走到第一张课桌的位置,记录信息 253 | 2. 走到下一张课桌的位置,如果这里确实还有课桌,就继续记录。 254 | 3. 如果没有课桌了,就停止这个过程。 255 | 4. 否则,回到步骤 2。 256 | 257 | 我们应该怎样用 JavaScript 来实现这个过程呢?相信答案已经呼之欲出了——循环!使用循环来解决这个问题。 258 | 259 | ```javascript 260 | let queue = ["Sonam", "Susanna Kliment", "Unnr Radmila", "Davide", "Rebekah "]; 261 | 262 | for (let i = 0; i < queue.length; i += 1) { 263 | alert(`第${i}个学生的姓名是:${queue[i]}`); 264 | } 265 | // Sonam 266 | // Susanna Kliment 267 | // Unnr Radmila 268 | // Davide 269 | // Rebekah 270 | ``` 271 | 272 | 我们使用 `for` 语句依次访问了数组中的每一个元素,变量 `i` 表示数组元素的*索引*,它是一个约定俗成的名称。如果这个索引值小于数组长度,说明还没有到数组尽头,那么就继续进行处理,否则就停止循环。依次访问数组每一个元素的过程称为*遍历*。 273 | 274 | -------------------------------------------------------------------------------- /数据/对象.md: -------------------------------------------------------------------------------- 1 | ## 道生万物·对象 2 | 3 | --- 4 | 5 | ### 对象的概念 6 | 7 | **构造器与字面量** 8 | 9 | *字面量*是一种值的表示法。通过直接写出一个值所包含的内容,来创建这个值,这种**形式**被称为字面量。 10 | 11 | 如:"Hello world" 就是一个字符串字面量,1234.5678 就是一个数字字面量。 12 | 13 | 字面量与*创建实例*相对。在 JavaScript 中,每种类型的值都有一个对应的*构造器*,原则上你可以使用构造器来构造一个值,构造器写成函数调用的形式,可以接受一些值,作为创建新值的所需信息,这种创建值的形式称为*创建实例*。如: 14 | 15 | ```javascript 16 | const a = new Number(); // a = 0 17 | const b = new Number(10); // b = 10 18 | const c = new String(); // c = "" 19 | const d = new String(100); // c = "100" 20 | ``` 21 | 22 | 当然,JavaScript 中提供了方便的*字面量*方式来让我们创建值,我们不需要为值一个个创建实例。 23 | 24 | 除了我们已经了解过的布尔值、数值、字符串之外,有一大类值被称为*对象*。对象是一个包含了一些值的结构。 25 | 26 | ```javascript 27 | const o = new Object(); 28 | o.name = "John"; 29 | o.age = 12; 30 | ``` 31 | 32 | 现在我们创建了一个对象,并将它赋给常量 `o` 。我们为 `o` 提供了两个信息,分别是名称和年龄。这个信息被称作*属性*,我们可以通过属性来访问对象中所存放的具体的值。 33 | 34 | ```javascript 35 | const cat = new Object(); 36 | cat.name = "Lily"; 37 | cat.age = 3; 38 | alert(cat.age); // 3 39 | ``` 40 | 41 | 我们赋予了这个“猫对象”两个属性,一个是它的名字,一个是年龄。每个属性都对应一个值。当我们需要改变或得到某个属性的值时,我们只需要写下 `<对象名>.<属性名>` 即可。你可以把它当做一个对象内部的变量。 42 | 43 | 如果访问了未设置值的属性,你会得到值 `undefined` ,——因为“未定义”啊! 44 | 45 | 和基本的值一样,对象也可以用简便的字面量方式创建,这种形式被称为*对象字面量*。 46 | 47 | 它的特征是一对大括号,标志着这个对象字面量的起始与结束。在大括号中你可以写下一个属性和一个值,二者用冒号分隔,值后面写一个逗号,表示这一项*成员*结束了。 48 | 49 | ```javascript 50 | const dog = {name: "Peter", age: 4}; 51 | alert(dog.name); // "Peter" 52 | ``` 53 | 54 | 现在我们拥有了一只小狗,并给它起了名字。我们可以利用合适的换行,让对象字面量看起来舒服一些: 55 | 56 | ```javascript 57 | const dog = { 58 | name: "Peter", 59 | age: 4, 60 | }; 61 | alert(dog.name); // "Peter" 62 | ``` 63 | 64 | 最后一项成员的逗号是可选的,你可以自由决定是否添加。 65 | 66 | 你可以重复定义对象中的一个属性,最后一次定义的值会覆盖掉先前的值。但是我们没必要这样做,如果要改变一个属性的值,随时可以通过访问它的方式来改变。 67 | 68 | ```javascript 69 | // 不要这样做 70 | const object = { 71 | a: 1, 72 | a: 2 73 | }; 74 | alert(object.a); // 2 75 | 76 | // 你可以像这样 77 | const object2 = { 78 | a: 1 79 | }; 80 | object2.a = 2; 81 | alert(object2.a); // 2 82 | ``` 83 | 84 | 85 | 86 | 对象字面量中所包含的信息构成了这个对象本身,自身也是值,因此你可以在对象字面量中将一个属性的值设置为另一个对象字面量。当一个对象成为属性的值时,你可以通过属性访问这个对象,进一步访问它的属性只需要在它后面接着写 `.<属性名>`即可。这种访问属性的方式被称为*点号访问法。* 87 | 88 | ```javascript 89 | const person = { 90 | name: "Venn", 91 | age: 18, 92 | foods: { 93 | apple: 5, 94 | pear: 3 95 | } 96 | }; 97 | alert(person.name); // Venn 98 | alert(person.foods.apple); // 5 99 | ``` 100 | 101 | 当然,你不能直接查看一个对象,否则你会得到一个看起来有些奇怪的字符串值: 102 | 103 | ```javascript 104 | alert(person); // "[object Object]" 105 | alert(person.foods); // "[object Object]" 106 | ``` 107 | 108 | 109 | 110 | **属性名** 111 | 112 | 如前文所说,对象的属性名可以看做是一个变量名,一个合法的标识符也可以直接用做属性名。但事实上,你可以用**任何字符**作为属性名,包括空格等。你只需要用双引号或单引号将属性名括起: 113 | 114 | ```javascript 115 | const person = { 116 | "first name": "John", 117 | "last name": "Doe", 118 | }; 119 | ``` 120 | 121 | 然后,可以这样访问属性值: 122 | 123 | ```javascript 124 | alert(person["first name"]); // John 125 | alert(person["last name"]); // Doe 126 | ``` 127 | 128 | 这种方法被称为*方括号访问法*。如果属性名是合法的标识符,你也可以写成完全等价的点号访问法的形式。 129 | 130 | ```javascript 131 | const o = { 132 | "aaa": "bbb" 133 | }; 134 | alert(o["aaa"]); // "bbb" 135 | alert(o.aaa); // "bbb" 136 | ``` 137 | 138 | 139 | 140 | --- 141 | 142 | 练习 3.4.1 143 | 144 | 1. 编写一个程序,提示用户输入一些个人信息,并将它存储到一个对象里。 145 | 2. 在 3.4.1.1 的基础上,从对象中访问某个信息,并告诉用户某个它的值。 146 | 147 | --- 148 | 149 | 150 | 151 | 152 | 153 | ### 成员操作 154 | 155 | JavaScript 提供了一些方式来操作对象中的属性和值。我们已经讨论了访问和修改成员值的方式,添加一个成员也很简单——就像修改它一样,直接赋值即可。 156 | 157 | ```javascript 158 | const cat = { 159 | name: "Kitty", 160 | age: 4, 161 | kind: "unknown" 162 | }; 163 | 164 | // 现在我知道它是波斯猫 165 | cat.kind = "Persian cat"; 166 | alert(cat.kind); // "Persian cat" 167 | ``` 168 | 169 | 你也可以删除对象中的属性,JavaScript 提供了 `delete` 操作符。 170 | 171 | ```javascript 172 | const cat = { 173 | name: "Kitty", 174 | age: 4, 175 | kind: "unknown" 176 | }; 177 | 178 | // 现在我不需要关心它的品种 179 | delete cat.kind; 180 | alert(cat.kind); // undefined 181 | ``` 182 | 183 | 这时候我们或许会有疑问:当一个属性被删除之后,再访问它就会得到 `undefined`。那么这跟直接把属性的值设为 `undefined` 有什么区别吗? 184 | 185 | 当然有!当属性值为 `undefined` 时,它只是一个值为 `undefined` 的属性,依然存在于对象中。但是,当你用 `delete` 删除一个属性的时候,这个对象中就不存在这个属性了,只不过是访问了不存在的属性会得到 `undefined` 而已。 186 | 187 | 你可以使用 `in` 操作符来查看对象中究竟是否存在某一个属性: 188 | 189 | ```javascript 190 | const cat = { 191 | name: "Kitty", 192 | age: 4, 193 | kind: "unknown" 194 | }; 195 | 196 | // 现在我不需要关心它的品种 197 | delete cat.kind; 198 | alert("kind" in cat); // false 199 | alert("name" in cat); // true 200 | ``` 201 | 202 | 为什么当我们查看某个属性是否存在时,这个属性名要写成字符串?这是因为在 JavaScript 的语法中,如果直接写成 `kind in cat` 这样,`kind` 会被理解为一个标识符,然而我们并没有定义这个标识符,因此会得到一个错误。 203 | 204 | 事实上,JavaScript 中的对象的属性名都是以字符串方式存储的,只不过在对象字面量中,如果是合法的标识符,就不需要写成字符串的形式,JavaScript 会理解它。如果是点号标记法,由于它**只能用于访问写成合法标识符的属性名称**,因此属性名也不需要写成字符串的形式。但是在中括号标记法中,就应该写成字符串的形式。因为 JavaScript 会**将中括号中的内容当做表达式进行求值**,如果是一个字符串,那么就是按这个字符串对应的属性名进行访问,而如果认为是一个标识符,就会查找这个标识符本身的值所对应的属性名。 205 | 206 | 下面用一个示例来说明。 207 | 208 | ```javascript 209 | let a = "123"; 210 | const object = { 211 | a: 456, 212 | "123": 123 213 | }; 214 | alert(object.a); // 456 215 | alert(object[a]); // 123(标识符 a 的值是 "123",那么访问了名为 "123" 的属性) 216 | alert(object["a"]); // 456(访问名为"a"的属性) 217 | ``` 218 | 219 | 220 | 221 | --- 222 | 223 | 练习 3.4.2 224 | 225 | 1. 在 3.4.1.1 的基础上,提示用户输入一个名称,告诉用户这个对象中是否能找到名称对应的值。 226 | 227 | (提示:使用前面学习的逻辑相关知识) 228 | 229 | --- 230 | 231 | 232 | 233 | 234 | 235 | ### 枚举 236 | 237 | 上文所提供的访问对象成员的方式,都是通过属性名进行的。假如我们不知道某个属性的名称,或者说想一次性访问到所有的值,JavaScript 也提供了一些方便的函数来进行这类操作。 238 | 239 | 第一个是 `Object.values` 函数。我们可以从它得到一个列表,列表中会依次存放它所有的值。由于我们可以直接显示数组中的内容,因此它的所有值也就一目了然。 240 | 241 | ```javascript 242 | const cat = { 243 | name: "Kitty", 244 | age: 4, 245 | kind: "Cheshire Cat" 246 | }; 247 | 248 | const values = Object.values(cat); 249 | alert(values); // Kitty,4,Cheshire Cat 250 | ``` 251 | 252 | 第二个是 `Object.keys` 函数,它得到一个对象中所有属性名称的列表。 253 | 254 | ```javascript 255 | const cat = { 256 | name: "Kitty", 257 | age: 4, 258 | kind: "Cheshire Cat" 259 | }; 260 | 261 | const keys = Object.keys(cat); 262 | alert(keys); // name,age,kind 263 | ``` 264 | 265 | 此外,我们还可以使用 `Object.entries` 函数,它同样是得到一个列表,列表中交替保存属性名和值。 266 | 267 | ```javascript 268 | const cat = { 269 | name: "Kitty", 270 | age: 4, 271 | kind: "Cheshire Cat" 272 | }; 273 | 274 | const entries = Object.entries(cat); 275 | alert(entries); // name,Kitty,age,4,kind,Cheshire Cat 276 | ``` 277 | 278 | 我们会在下一节中详细了解如何使用列表中的值。 279 | 280 | 281 | 282 | 283 | 284 | ### 全局对象 285 | 286 | 我们在这里需要明确一个之前没有提及的概念: 287 | 288 | > 在 JavaScript 中,所有变量和常量都是一个*全局对象*的属性。 289 | 290 | 这个全局对象叫 `window` 。它在语义上指浏览器的窗口对象,同时也是 JavaScript 运行环境的一个“兜底”对象。当我们访问 `window` 对象的属性的时候,我们实际上是在访问这样一个变量/常量。 291 | 292 | ```javascript 293 | let hello = "Hello world"; 294 | alert(window.hello); // "Hello world" 295 | alert(window.hello === hello); // true 296 | ``` 297 | 298 | 由于 `window` 自身也是一个变量,因此它也是它自己的属性。 299 | 300 | ```javascript 301 | alert(window === window.window); // true 302 | alert(window.window === window.window.window); // true 303 | ``` 304 | 305 | 一般情况下我们不需要直接使用 `window` 对象,不过我们可以使用它来判断一个标识符是否存在于当前环境中——换句话说,只要知道 `window` 对象是否有这个 A 属性,就可以是否声明过一个叫 A 的标识符。 306 | 307 | --- 308 | 309 | 练习 3.4.3 310 | 311 | 1. 编写一个程序,判断当前环境中是否存在一个变量或常量。 312 | 313 | 2. 编写一个程序,在 3.4.3.1 的基础上判断某个标识符是否为变量或常量。 314 | 315 | (提示:`window` 对象的属性值可改变) 316 | 317 | --- 318 | 319 | -------------------------------------------------------------------------------- /事件/事件初探.md: -------------------------------------------------------------------------------- 1 | ## 事件初探 2 | 3 | --- 4 | 5 | ### 事件的概念 6 | 7 | 我们已经在学习初期接触到了 HTML 的概念,如前文所述,HTML 是 Web 页面的基本组成,接下来我们的任务将变得新奇有趣:抛开运行器窗口的拘束吧!让我们在自己的 HTML 页面中展现出 JavaScript 的力量。 8 | 9 | 在前面的一些示例中,我们简单了解了温度转换的算法,现在可以结合 HTML 写出一个温度转换器的小程序。 10 | 11 |  12 | 13 | 还记得怎样使用 HTML 文件吗?我们在 HTML 文件中输入以下代码: 14 | 15 | ```html 16 | 17 | 18 |
19 | 20 |