出版社:电子工业出版社
年代:2011
定价:79.0
本书讲述JavaScript作为一种混合式语言的各方面特性,包括过程式、面向对象、函数式和动态语言特性等,在动态函数式语言特性方面有尤为细致的讲述。本书的主要努力之一是分解出这些语言原子,并重现将它们混合在一起的过程与方法。本书的著述目的是基于一种形式上简单的语言来讲述“语言的本质及其应用”。本书讲述了通过框架执行过程来构造一个JavaScript扩展框架的方法,并完整讲述了框架扩展中各种设计取舍,因此可以作为研究计算机程序设计语言时的参考,用以展示现实系统如何实现经典理论中的各种编程范型。
目 录
第1部分 语言基础
第1章 十年JavaScript 3
1.1 网页中的代码 3
1.1.1 新鲜的玩意儿 3
1.1.2 第一段在网页中的代码 4
1.1.3 最初的价值 5
1.2 用JavaScript来写浏览器上的应用 7
1.2.1 我要做一个聊天室 7
1.2.2 Flash的一席之地 9
1.2.3 RWC与RIA之争 10
1.3 没有框架与库的语言能怎样发展呢 12
1.3.1 做一个框架 12
1.3.2 重写框架的语言层 15
1.3.3 富浏览器端开发与AJAX 16
1.4 语言的进化 18
1.4.1 Qomo的重生 18
1.4.2 QoBean是对语言的重新组织 18
1.4.3 JavaScript作为一门语言的进化 19
1.5 为JavaScript正名 22
1.5.1 JavaScript 22
1.5.2 Core JavaScript 23
1.5.3 SpiderMonkey JavaScript 24
1.5.4 ECMAScript 24
1.5.5 JScript 25
1.5.6 总述 25
1.6 JavaScript的应用环境 26
1.6.1 宿主环境 27
1.6.2 外壳程序 28
1.6.3 运行期环境 29
第2章 JavaScript的语法 31
2.1 语法综述 31
2.1.1 标识符所绑定的语义 32
2.1.2 识别语法错误与运行错误 33
2.2 JavaScript的语法:变量声明 33
2.2.1 变量的数据类型 34
2.2.1.1 基本数据类型 34
2.2.1.2 值类型与引用类型 35
2.2.2 变量声明 36
2.2.3 变量与直接量 37
2.2.3.1 字符串直接量、转义符 38
2.2.3.2 数值直接量 40
2.2.4 函数声明 41
2.3 JavaScript的语法:表达式运算 42
2.3.1 一般表达式运算 43
2.3.2 逻辑运算 44
2.3.3 字符串运算 45
2.3.4 比较运算 46
2.3.4.1 等值检测 46
2.3.4.2 序列检测 48
2.3.5 赋值运算 50
2.3.6 函数调用 51
2.3.7 特殊作用的运算符 51
2.3.8 运算优先级 53
2.4 JavaScript的语法:语句 55
2.4.1 表达式语句 56
2.4.1.1 一般表达式语句 57
2.4.1.2 赋值语句与隐式的变量声明 59
2.4.1.3 (显式的)变量声明语句 59
2.4.1.4 函数调用语句 61
2.4.2 分支语句 65
2.4.2.1 条件分支语句(if语句) 65
2.4.2.2 多重分支语句(switch
语句) 66
2.4.3 循环语句 68
2.4.4 流程控制:一般子句 70
2.4.4.1 标签声明 70
2.4.4.2 break子句 71
2.4.4.3 continue子句 73
2.4.4.4 return子句 75
2.4.5 流程控制:异常 75
2.5 面向对象编程的语法概要 77
2.5.1 对象直接量声明与实例创建 78
2.5.1.1 使用构造器创建对象实例 78
2.5.1.2 对象直接量声明 81
2.5.1.3 数组直接量声明 82
2.5.1.4 正则表达式直接量声明 83
2.5.1.5 【ES5】在对象直接量中使用属性读写器 85
2.5.1.6 讨论:初始器与直接量的区别 86
2.5.2 对象成员 87
2.5.2.1 对象成员列举、存取和删除 87
2.5.2.2 属性存取与方法调用 91
2.5.2.3 对象及其成员的检查 92
2.5.2.4 可列举性 94
2.5.3 默认对象的指定 95
2.6 【ES5】严格模式下的语法限制 96
2.6.1 语法限制 97
2.6.2 严格模式的范围 99
2.7 运算符的二义性 100
2.7.1 加号“+”的二义性 102
2.7.2 括号“( )”的二义性 103
2.7.3 冒号“:”与标签的二义性 105
2.7.4 大括号“{ }”的二义性 106
2.7.5 逗号“,”的二义性 109
2.7.6 方括号“[ ]”的二义性 111
第2部分 语言特性及基本应用
第3章 JavaScript的非函数式语言特性 117
3.1 概述 117
3.1.1 命令式语言与结构化编程 118
3.1.2 结构化的疑难 120
3.1.3 “面向对象语言”是突破吗 122
3.1.4 更高层次的抽象:接口 125
3.1.5 再论语言的分类 127
3.1.6 JavaScript的语源 129
3.2 基本语法的结构化含义 131
3.2.1 基本逻辑与代码分块 131
3.2.2 模块化的层次:语法作用域 134
3.2.2.1 主要的语法作用域及其效果 135
3.2.2.2 语法作用域之间的相关性 138
3.2.3 执行流程及其变更 139
3.2.3.1 级别2:“break <label>”等语法 140
3.2.3.2 级别3:return子句 143
3.2.3.3 级别4:throw语句 144
3.2.3.4 执行流程变更的内涵 145
3.2.4 模块化的效果:变量作用域 147
3.2.4.1 级别1:表达式 148
3.2.4.2 级别2:语句 149
3.2.4.3 级别3:函数(局部) 150
3.2.4.4 级别4:全局 151
3.2.4.5 变量作用域中的次序问题 153
3.2.4.6 变量作用域与变量的生存周期 154
3.2.5 语句的副作用 155
3.3 JavaScript中的原型继承 157
3.3.1 空对象(null)与空的对象 158
3.3.2 原型继承的基本性质 159
3.3.3 空的对象是所有对象的基础 159
3.3.4 构造复制?写时复制?还是读遍历? 160
3.3.5 构造过程:从函数到构造器 162
3.3.6 预定义属性与方法 163
3.3.7 原型链的维护 165
3.3.7.1 两个原型链 165
3.3.7.2 constructor属性的维护 167
3.3.7.3 内部原型链的作用 170
3.3.7.4 【ES5】在SpiderMonkey与ES5中的原型链维护 170
3.3.8 原型继承的实质 172
3.3.8.1 原型修改 172
3.3.8.2 原型继承 173
3.3.8.3 原型继承的实质:从无到有 174
3.3.8.4 如何理解“继承来的成员” 175
3.4 JavaScript的对象系统 177
3.4.1 封装 177
3.4.2 多态 179
3.4.3 事件 181
3.4.4 类抄写?或原型继承? 182
3.4.4.1 类抄写 183
3.4.4.2 原型继承存在的问题 186
3.4.4.3 如何选择继承的方式 186
3.4.5 JavaScript中的对象(构造器) 187
3.4.6 不能通过继承得到的效果 190
3.5 【ES5】可定制的对象属性 192
3.5.1 属性描述符 192
3.5.1.1 (一般的)数据属性描述符 193
3.5.1.2 (带读写器的)存取属性描述符 193
3.5.1.3 直接量形式的初始器是语法格式,而非描述符 194
3.5.2 定制对象属性 195
3.5.2.1 属性声明以及获取属性描述符 195
3.5.2.2 新的对象创建方法:Object.create() 197
3.5.3 属性状态维护 198
3.5.3.1 取属性列表 198
3.5.3.2 使用defineProperty来维护属性的性质 199
3.5.3.3 对于继承自原型的属性,修改其值的效果 200
3.5.3.4 重写原型继承来的属性的描述符 201
第4章 JavaScript的函数式语言特性 203
4.1 概述 203
4.1.1 从代码风格说起 204
4.1.2 为什么常见的语言不赞同连续求值 204
4.1.3 函数式语言的渊源 206
4.2 函数式语言中的函数 208
4.2.1 函数是运算元 208
4.2.2 在函数内保存数据 209
4.2.3 函数内的运算对函数外无副作用 210
4.3 从运算式语言到函数式语言 211
4.3.1 JavaScript中的几种连续运算 212
4.3.1.1 连续赋值 212
4.3.1.2 三元表达式的连用 212
4.3.1.3 一些运算连用 214
4.3.1.4 函数与方法的调用 214
4.3.2 运算式语言 216
4.3.2.1 运算的实质是值运算 216
4.3.2.2 有趣的运算:在IE和J2EE中 218
4.3.3 如何消灭掉语句 220
4.3.3.1 通过表达式消灭分支语句 221
4.3.3.2 通过函数递归消灭循环语句 222
4.3.3.3 其他可以被消灭的语句 223
4.4 函数:对运算式语言的补充和组织 224
4.4.1 函数是必要的补充 224
4.4.2 函数是代码的组织形式 226
4.4.3 重新认识“函数” 227
4.4.3.1 “函数”==“lambda” 228
4.4.3.2 当运算符等义于某个函数时 228
4.4.4 JavaScript语言中的函数式编程 230
4.5 JavaScript中的函数 231
4.5.1 可变参数与值参数传递 231
4.5.2 非惰性求值 235
4.5.3 函数是第一型 237
4.5.4 函数是一个值 239
4.5.5 可遍历的调用栈 239
4.5.5.1 callee:我是谁 240
4.5.5.2 caller:谁呼(叫)我 242
4.6 闭包 244
4.6.1 闭包与函数实例 244
4.6.1.1 什么是闭包 245
4.6.1.2 什么是函数实例与函数引用 246
4.6.1.3 (在被调用时,)每个函数实例至少拥有一个闭包 248
4.6.2 闭包与调用对象 250
4.6.2.1 “调用对象”的局部变量维护规则 252
4.6.2.2 “全局对象”的变量维护规则 252
4.6.2.3 函数闭包与“调用对象”的生存周期 253
4.6.3 闭包相关的一些特性 255
4.6.3.1 引用与泄漏 256
4.6.3.2 函数实例拥有多个闭包的情况 258
4.6.3.3 语句或语句块中的闭包问题 260
4.6.3.4 闭包中的标识符(变量)特例 262
4.6.3.5 函数对象的闭包及其效果 265
4.6.4 闭包与可见性 266
4.6.4.1 函数闭包带来的可见性效果 266
4.6.4.2 对象闭包带来的可见性效果 269
4.6.4.3 匿名函数的闭包与可见性效果 273
4.7 【ES5】严格模式与闭包 274
4.7.1 严格模式下的执行限制 275
4.7.2 严格模式下的匿名函数递归问题 276
第5章 JavaScript的动态语言特性 279
5.1 概述 279
5.1.1 动态数据类型的起源 280
5.1.2 动态执行系统的起源 280
5.1.2.1 编译系统、解释系统与编码 280
5.1.2.2 动态执行 281
5.1.3 脚本系统的起源 282
5.1.4 脚本只是一种表面的表现形式 283
5.2 动态执行 285
5.2.1 动态执行与闭包 285
5.2.1.1 eval使用全局闭包 286
5.2.1.2 eval使用当前函数的闭包 287
5.2.2 动态执行过程中的语句、表达式与值 289
5.2.3 奇特的、甚至是负面的影响 291
5.3 动态方法调用(call、apply与bind) 293
5.3.1 动态方法调用中指定this对象 293
5.3.2 丢失的this引用 295
5.3.3 栈的可见与修改 296
5.3.4 兼容性:低版本中的call()与apply() 298
5.3.5 【ES5】兼容性:ES5中的call()、apply() 301
5.3.6 【ES5】bind()方法与函数的延迟调用 302
5.4 重写 303
5.4.1 原型重写 304
5.4.2 构造器重写 305
5.4.2.1 语法声明与语句含义不一致的问题 307
5.4.2.2 对象检测的麻烦 310
5.4.2.3 构造器的原型(prototype属性)不受重写影响 311
5.4.2.4 “内部对象系统”不受影响 312
5.4.2.5 让用户对象系统影响内部对象系统 313
5.4.2.6 构造器重写对直接量声明的影响 314
5.4.2.7 构造绑定 315
5.4.2.8 内置构造器重写的概述 317
5.4.3 对象成员的重写 318
5.4.3.1 成员重写的检测 318
5.4.3.2 成员重写的删除 319
5.4.4 宿主对重写的限制 321
5.4.5 引擎对重写的限制 323
5.4.5.1 this的重写 323
5.4.5.2 语句语法中的重写 324
5.4.5.3 结构化异常处理中的重写 326
5.5 包装类:面向对象的妥协 327
5.5.1 显式包装元数据 328
5.5.2 隐式包装的过程与检测方法 329
5.5.3 包装值类型数据的必要性与问题 332
5.5.4 其他直接量与相应的构造器 333
5.5.4.1 函数特例 333
5.5.4.2 正则表达式特例 334
5.6 关联数组:对象与数组的动态特性 335
5.6.1 关联数组是对象系统的基础 336
5.6.2 用关联数组实现的索引数组 336
5.6.3 干净的对象 339
5.7 类型转换 342
5.7.1 宿主环境下的特殊类型系统 343
5.7.2 值运算:类型转换的基础 345
5.7.3 隐式转换 346
5.7.3.1 运算导致的类型转换 346
5.7.3.2 语句(语义)导致的类型转换 348
5.7.4 值类型之间的转换 348
5.7.4.1 undefined的转换 349
5.7.4.2 number的转换 349
5.7.4.3 boolean的转换 350
5.7.4.4 string的转换 351
5.7.4.5 值类型数据的显式转换 351
5.7.5 从引用到值:深入探究valueOf()方法 353
5.7.6 到字符串类型的显式转换 355
5.7.6.1 重写toString()方法 356
5.7.6.2 从数值到字符串的显式转换 357
5.7.6.3 其他类型的显式转换 358
5.7.6.4 序列化 358
第3部分 编程实践
第6章 元语言:QoBean核心技术与实现 363
6.1 QoBean语言层的基本特性 363
6.1.1 QoBean语言层概要 363
6.1.1.1 如何使用QoBean 364
6.1.1.2 QoBean中的面向对象(OOP) 365
6.1.1.3 QoBean中的接口(Interface) 367
6.1.1.4 QoBean中的切面(Aspect) 369
6.1.2 Qomo的体系结构及其与QoBean的关系 373
6.2 QoBean的元语言特性 374
6.2.1 QoBean如何理解元语言 374
6.2.2 算法与数据结构 375
6.2.2.1 引用类型与值类型的数据 376
6.2.2.2 函数调用 376
6.2.2.3 源起 377
6.2.2.4 小结 377
6.2.3 代码组织形式 379
6.2.3.1 块,以及基于块的编织 379
6.2.3.2 更强的编织 381
6.2.3.3 逻辑代码块:局部、全局,以及闭包 382
6.2.3.4 逻辑的属主 384
6.2.4 对“如何组织对象”的补充 385
6.2.4.1 原子,与原子联结的友类、友函数 386
6.2.4.2 对象唯一化 387
6.2.5 综述 390
6.3 基于元语言实现的语言特性 391
6.3.1 基于元语言的类继承框架 391
6.3.1.1 类注册过程 392
6.3.1.2 示例:实现MetaClass与MetaObject的约定 393
6.3.1.3 完整的Qomo语法实现 396
6.3.1.4 类类型树的建立 400
6.3.2 多投事件 401
6.3.3 其他语言特性的实现 403
6.4 基于元语言实现的DSL 405
6.4.1 DSL的基本设计 405
6.4.2 DSL的基本实现 406
6.4.3 DSL的基本应用 409
6.4.4 一些修补 410
6.4.5 基于严格模式的一些修补 412
第7章 一般性的动态函数式
语言技巧 415
7.1 消除代码的全局变量名占用 415
7.2 一次性的构造器 417
7.3 对象充当识别器 418
7.4 识别new运算进行的构造器调用 420
7.5 使用直接量及其包装类快速调用对象方法 421
7.6 三天前是星期几 422
7.7 使用对象的值含义来构造复杂对象 423
7.8 控制字符串替换过程的基本模式 426
7.9 实现二叉树 427
7.10 将函数封装为方法 429
7.11 使用with语句来替代函数参数传递 431
7.12 使用对象闭包来重置重写 432
7.13 构造函数参数 434
7.14 使用更复杂的表达式来消减if语句 437
7.15 利用钩子函数来扩展功能 439
7.16 安全的字符串 441
附录A 术语表 443
附录B 主要引擎的特性差异列表 447
附录C 附图 449
附录D 参考书目 453
附录E 本书各版次主要修改 455
本书详细讲述JavaScript 作为一种混合式语言的各方面特性,包括过程式、面向对象、函数式和动态语言特性等,在动态函数式语言特性方面有着尤为细致的讲述。本书的主要努力之一,就是分解出这些语言原子,并重现将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,读者可了解到语言的本质,以及“层出不穷的语言特性”背后的真相。本书主要的著述目的是基于一种形式上简单的语言来讲述“语言的本质及其应用”。本书详细讲述了通过框架执行过程来构造一个JavaScript 扩展框架的方法,并完整地讲述了框架扩展中各种设计取舍,因此可以作为研究计算机程序设计语言时的参考,用以展示现实系统如何实现经典理论中的各种编程范型。【前言/序】 第2版 代序要有光—《世界需要一种什么样的语言》节选—什么才是决定语言的未来的思想呢?或者我们也可以换个角度来提出这个问题:世界需要一种什么样的语言? 特性众多、适应性强,就是将来语言的特点吗?我们知道现在的C#与Java都在这条道路上前进。与特定的系统相关,就是语言的出路吗?例如曾经的VC++,以及它面向不同平台的版本。当然,与此类似的语言,还有C,以及汇编语言等。这些例举其实都是在特定环境下的特定语言,所不同的无非是此处的环境的大小。这其实也是程序员的心病:我们到底选Windows平台,还是Java平台,或者Linux系统,再或者是……我们总是在不同的厂商及其支持的平台中选择,而最终这种选择又决定了我们所使用的语言。这与喜好无关,也与语言的好坏无关,不过是一种趋利的选择罢了。所以你在使用着的也许只是一种“并不那么‘好’”,以及并不能令你那么开心地编程的语言。你越发辛勤地工作,越发地为这些语言摇旗鼓噪,你也就离语言的真相越来越远。当然,这不过是一种假设。但是,真相不都是从假设开始的吗?语言有些很纯粹,有些则以混杂著称。如果编程世界只有一种语言,无论它何等复杂,也必因毫无比较而显得足够纯粹。所以只有在多种语言之间比较,才会有纯粹或混杂的差异:纯粹与混杂总是以一种或多种分类法为背景来描述的。因此我们了解这些类属概念的标准、原则,也就回溯到了种种语言的本质:它是什么、怎么样,以及如何工作。这本书,将这些分类回溯到两种极端的对立:命令式与说明式、动态与静态。我讲述除了静态语言(一般是指类似C、C++、Delphi等的强类型、静态、编译型语言)之外的其他三种类型。正是从根底里具有这三种类型的特性,所以JavaScript具有令人相当困扰的混合语言特性。分离它们,并揭示将它们混沌一物的方法与过程,如历经涅磐。在这一经历中,这本书就是我的所得。多年以来,我在我所看不见的黑暗与看得见的梦境中追寻着答案。这本书是我最终的结论,或者结论面前的最后一层表象:我们需要从纯化的语言中领悟到编程的本质,并以混杂的语言来创造我们的世界。我看到:局部的、纯化的语言可能带来独特的性质,而从全局来看,世界是因为混杂而变得有声有色。如果上帝不说“要有光”,那么我们将不能了解世象之表;而世象有了表面,便有了混杂的色彩,我们便看不见光之外的一切事物。我们依赖于光明,而事实是光明遮住了黑暗。如同你现在正在使用的那一种、两种或更多种语言,阻碍了你看到你的未来。周爱民2009年1月于本书精简版序 第1版 代序学两种语言—《我的程序语言实践》节选—《程序设计语言——实践之路》一书对“语言”有一个分类法,将语言分类为“说明式”与“命令式”两种。Delphi以及C、C++、Java、C#等都被分在“命令式”语言范型的范畴,“函数式”语言则是“说明式”范型中的一种。如今我回顾自己对语言的学习,其实十年也就学会了两种语言:一种是命令式的Pascal/Delphi,另一种则是说明式的JavaScript。当然,从语言的实现方式来看,一种是静态的,一种是动态的。这便是我程序员生涯的全部了。我毕竟不是计算机科学的研究者,而只是其应用的实践者,因此我从一开始就缺乏对“程序”的某些科学的或学术层面上的认识是很正常的。也许有些人一开始就认识到程序便是如此,或者一种语言就应当是这样构成和实现的,那么他可能是从计算机科学走向应用,故而比我了解得多些。而我,大概在十年前学习编程以及在后来很多年的实践中,仅被要求“写出代码”而从未被要求了解“什么是语言”。所以我才会后知后觉,才会在很长的时间里迷失于那些精细的、沟壑纵横的语言表面而不自知。然而一如我现在所见到的,与我曾相同地行进于那些沟壑的朋友,仍然在持续地迷惑着、盲目着,全然无觉于沟壑之外的瑰丽与宏伟。前些天写过一篇博客,是推荐那篇“十年学会编程”的。那篇文章道出了我在十年编程实践之后,对程序语言的最深刻的感悟。我们学习语言其实不必太多,深入一两种就可以了。如果在一种类型的语言上翻来覆去,例如不断地学C、Delphi、Java、C#……无非是求生存、讨生活,或者用以装点个人简历,于编程能力的提高用处是不大的。更多的人,因为面临太多的语言选择而浅尝辄止,多年之后仍远离程序根本,成为书写代码的机器,把书写代码的行数、程序个数或编程年限作为简历中最显要的成果。这在明眼人看来,不过是熟练的砌砖工而已。我在《大道至简》中说“如今我已经不再专注于语言”。其实在说完这句话之后,我就已经开始了对JavaScript的深入研究。在如此深入地研究一种语言,进而与另一种全然有别的语言比较之后,我对“程序=算法+结构”有了更深刻的理解与认识。尽管这句名言从来未因我的认识而变化过,从来未因说明与命令的编程方式而变化过,也从来未因动态与静态的实现方法而变化过。动静之间,不变的是本质。我之所以写这篇文章,并非想说明这种本质是什么抑或如何得到,只是期望读者能在匆忙的行走中,时而停下脚步,远远地观望一下目标罢了。而我此刻,正在做一个驻足观望的路人。周爱民2007年11月于个人博客前 言语言语言是一种交流的工具,这约定了语言的“工具”本质,以及“交流”的功用。“工具”的选择只在于“功用”是否能达到,而不在于工具是什么。在数千年之前,远古祭师手中的神杖就是他们与神交流的工具。祭师让世人相信他们敬畏的是神,而世人只需要相信那柄神杖。于是,假如祭师不小心丢掉了神杖,就可以堂而皇之地再做一根。甚至,他们可以随时将旧的换成更新或更旧的神杖,只要他们宣称这是一根更有利于通神的杖。对此,世人往往做出迷惑的表情,或者呈现欢欣鼓舞的情状。今天,这种表情或情状一样地出现在大多数程序员的脸上,出现在他们听闻到新计算机语言被创生的时刻。神杖换了,祭师还是祭师,世人还是会把头叩得山响。祭师掌握了与神交流的方法(如果真如同他们自己说的那样),而世人只看见了神杖。所以,泛义的工具是文明的基础,而确指的工具却是愚人的器物。计算机语言有很多种分类方法,例如高级语言或者低级语言。其中一种分类方法,就是将计算机语言分为“静态语言”和“动态语言”——事物就是如此,如果用一对绝对反义的词来分类,就相当于涵盖了事物的全体。当然,按照中国人中庸平和的观点,以及保守人士对未知可能性的假设,我们还可以设定一种中间态:半动态语言。你当然也可以叫它半静态语言。所以,我们现在是在讨论一种很泛义的计算机语言工具。至少在眼下,它(在分类概念中)涵盖了计算机语言的二分之一。当然,限于我自身的能力,我只能讨论一种确指的工具,例如JavaScript。但我希望你由此看到的是计算机编程方法的基础,而不是某种愚人的器物。JavaScript的生命力可能足够顽强,我假定它比C语言还顽强,甚至比你我的生命都顽强。但它只是愚人的器物,因此反过来说:它能不能长久地存在并不重要,重要的是它能不能作为这“二分之一的泛义”来供我们讨论。分类法打开一副新扑克牌,我们总看到它被整齐地排在那里,从A到K及大小王。接下来,我们将它一分为二,然后交叉在一起;再分开,再交叉……但是在重新开局之前,你是否注意到:在上述过程中,牌局的复杂性其实不是由“分开”这个动作导致的,而是由“交叉”这个动作导致的。所以分类法本身并不会导致复杂性。就如同一副新牌只有4套A~K,我们可以按13种牌面来分类,也可以按4种花色来分类。当你从牌盒里把它们拿出来的时候,无论它们是以哪种方式分类的,这副牌都不混乱。混乱的起因,在于你交叉了这些分类。同样的道理,如果世界上只有动态、静态两种语言,或者真有半动态语言而你又有明确的“分类法”,那么开发人员将会迎来清醒、明朗的每一天:我们再也不需要花更多的时间去学习更多的古怪语言了。然而,第一个问题便来自于分类本身。因为“非此即彼”的分类必然导致特性的缺失——如果没有这样“非此即彼”的标准就不可能形成分类,但特性的缺失又正是开发人员所不能容忍的。我们一方面吃着碗里的,一方面念着锅里的。即使锅里漂起来的那片菜叶未见得有碗里的肉好吃,我们也一定要捞起来尝尝。而且大多数时候,由于我们吃肉吃腻了嘴,因此会觉得那片菜叶味道更好。所以,是我们的个性决定了我们做不成绝对的素食者或肉食者。当然,更有一些人说我们的确需要一个新的东西来使我们更加强健。但不幸的是,大多数提出这种需求的人,都在寻求纯质银弹 或混合毒剂 。无论如何,他们要么相信总有一种事物是完美武器,要么相信更多的特性放在一起就变成了魔力的来源。我不偏向两种方法之任一。但是我显然看到了这样的结果,前者是我们在不断地创造并特化某种特性,后者是我们在不断地混合种种特性。更进一步地说,前者在产生新的分类法以试图让武器变得完美,后者则通过混淆不同的分类法,以期望通过突变而产生奇迹。二者相同之处,在于都需要更多的分类法。函数式语言就是来源于另外的一种分类法。不过要说明的是,这种分类法是计算机语言的原理之一。基本上来说,这种分类法在电子计算机的实体出现以前就已经诞生了。这种分类法的基础是“运算产生结果,还是运算影响结果”。前一种思想产生了函数式语言(如LISP)所在的“说明式语言”这一分类,后者则产生了我们现在常见的C、C++等语言所在的“命令式语言”这一分类。然而我们已经说过,人们需要更多的分类的目的,是要么找到类似银弹的完美武器,要么找到混合毒剂。所以一方面很多人宣称“函数式是语言的未来”,另一方面也有很多人把这种分类法与其他分类法混在一起,于是变成了我们这本书所要讲述的“动态函数式语言”。毋庸置疑的是:还会有更多的混合法产生。因为保罗 格雷厄姆(Paul Graham) 已经做过这样的总结:“二十年来,开发新编程语言的一个流行的秘诀是:取C语言的计算模式,逐渐地往上加LISP模式的特性,例如运行时类型和无用单元收集。”然而,这毕竟只是“创生一种新语言”的魔法。那么,到底有没有让我们在这浩如烟海的语言家族中,找到学习方法的魔法呢?我的答案是:看清语言的本质,而不是试图学会一门语言。当然,这看起来非常概念化。甚至有人说我可能是从某本教材中抄来的,另外一些人又说我试图在这本书里宣讲类似于我那本《大道至简》里的老庄学说 。其实这很冤枉。我想表达的意思不过是:如果你想把一副牌理顺,最好的法子,是回到它的分类法上,要么从A到K整理,要么按4个花色整理 。毕竟,两种或更多种分类法作用于同一事物,只会使事物混淆而不是弄得更清楚。因此,本书从语言特性出发,把动态与静态、函数式与非函数式的语言特性分列出来。先讲述每种特性,然后再讨论如何去使用(例如交叉)它们。特性无论哪种语言(或其他工具)都有其独特的特性,以及借鉴自其他语言的特性。有些语言通体没有“独特特性”,只是另外一种语言的副本,这更多的时候是为了“满足一些人使用语言的习惯”。还有一些语言则基本上全是独特的特性,这可能导致语言本身不实用,但却是其他语言的思想库。我们已经讨论过这一切的来源。对于JavaScript来说,除了动态语言的基本特性之外,它还有着与其创生时代背景密切相关的一些语言特性。直到昨天 ,JavaScript的创建者还在小心翼翼地增补着它的语言特性。JavaScript轻量的、简洁的、直指语言本质的特性集设计,使它成为解剖动态语言的有效工具。这个特性集包括: 一套参考过程式语言惯例的语法。 一套以原型继承为基础的对象系统。 一套支持自动转换的弱类型系统。 动态语言与函数式语言的基本特性。需要强调的是,JavaScript 1.x非常苛刻地保证这些特性是相应语言领域中的最小特性集(或称之为“语言原子”),这些特性在JavaScript中相互混合,通过交错与补充而构成了丰富的、属于JavaScript自身的语言特性。本书的主要目的之一,就是分解出这些语言原子,并探究重新将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,让读者了解到语言的本质,以及“层出不穷的语言特性”背后的真相。技巧技巧是“技术的取巧之处”,所以根本上来说,技巧也是技术的一部分。很多人(也包括我)反对技巧的使用,是因为难以控制,并且容易破坏代码的可读性。哪种情况下代码是需要“易于控制”和“可读性强”呢?通常,我们认为在较大型的工程下需要“更好地控制代码”;在更多人共同开发的项目代码上要求“更好的可读性”。然而,反过来说,在一些更小型的、不需要更多人参与的项目中,“适度地”使用技巧是否就可以接受呢?这取决于“需要、能够”维护这个代码的人对技巧的理解。这包括: 技巧是一种语言特性,还是仅特定版本所支持或根本就是BUG? 技巧是不是唯一可行的选择,有没有不需要技巧的实现? 技巧是为了实现功能,还是为了表现技巧而出现在代码中的?即使知晓问题的答案,我仍然希望每一个技巧的使用都有说明,甚至示例。如果维护代码的人不能理解该技巧,那么连代码本身都失去了价值,更何论技巧存在于这份代码中的意义呢?所以,虽然本书中的例子的确要用到许多“技巧”,但我一方面希望读者能明白,这是语言内核或框架内核实现过程中必需的,另一方面也希望读者能从这些技巧中学习到它原本的技术和理论,以及活用的方法。然而对于很多人来说,本书在讲述一个完全不同的语言类型。在这种类型的语言中,本书所讲述的一切,都只不过是“正常的方法”;在其他类型的一些语言中,这些方法看起来就成了技巧。例如,在JavaScript中要改变一个对象方法指向的代码非常容易,并且是语言本身赋予的能力;而在Delphi/C++中,却成了“破坏面向对象设计”的非正常手段。所以你最好能换一个角度来看待本书中讲述的“方法”。无论它对你产生多大的冲击,你应该先想到的是这些方法的价值,而不是它对于“你所认为的传统”的挑战。事实上,这些方法,在另一些“同样传统”的语言类型中,已经存在了足够长的时间——如同“方法”之于“对象”一样,原本就是那样“(至少看起来)自然而然”地存在于它所在的语言体系之中。语言特性的价值依赖于环境而得以彰显。横行的螃蟹看起来古怪,但据说那是为了适应一次地磁反转。螃蟹的成功在于适应了一次反转,失败(我们是说导致它这样难看)之处,也在于未能又一次反转回来。这本书你当然可以置疑:为什么要有这样的一本书?是的,这的确是一个很好的问题。首先,这本书并不讲Web浏览器(Web Browser,例如Internet Explorer)。这可能令人沮丧,但的确如此。尽管在很多人看来,JavaScript就是为浏览器而准备的一种轻量的语言,并认为它离开了DOM、HTML、CSS就没有意义。在同样的“看法”之下,国内外的书籍在谈及JavaScript时,大多会从“如何在Web页面上验证一个输入框值的有效性”讲起。是的,最初我也是这样认为的。因为本书原来就是出自我在写《B端开发》一书的过程之中。《B端开发》是一本讲述“在浏览器(Browser)上如何用JavaScript开发”的书。然而,《B端开发》写到近百页就放下了,因为我觉得应该写一本专门讲JavaScript的书,这更重要。所以,现在你将要看到的这本书就与浏览器无关。在本书中我会把JavaScript提升到与Java、C#或Delphi一样的高度,来讲述它的语言实现与扩展。作为实践,本书还在最后一部分内容中,借助名为“QoBean”的元语言框架讨论了语言扩展的方法 。但是,总的来说,本书不讲浏览器,不讲Web,也并不讲“通常概念下的”AJAX。JavaScript是一门语言,有思想的、有内涵的、有灵魂的语言。如果你没意识到这一点,那么你可能永远都只能拿它来做那个“验证一个输入框值的有效性”的代码。本书讲述JavaScript的这些思想、核心、灵魂,以及如何去丰富它的血肉。最为核心的内容是在第2章至第6章,包括: 以命令式为主的一般化的JavaScript语言特性,以及其对象系统。 动态、函数式语言,以及其他语言特性在JavaScript中的表现与应用。 使用动态函数式特性来扩展JavaScript的特性与框架。在撰述这些内容的整个过程中,我一直在试图给这本书找到一个适合的读者群体,但我发现很难。因为通常的定义是低级、中级与高级,然而不同的用户对自己的“等级”的定义标准并不一样。在这其中,有“十年学会编程”的谦谨者,也有“三天学会某某语言”的速成家。所以,我认为这样定位读者的方式是徒劳的。如果你想知道自己是否适合读这本书,建议你先看一下目录,然后试读一些章节。你可以先选读一些在你的知识库中看来很新鲜的,以及一些你原本已经非常了解的内容。通过对比,你应该知道这本书会给你带来什么。不过我需要强调一些东西。这本书不是一本让你“学会某某语言”的书,也不是一本让初学者“学会编程”的书。阅读本书,你至少应该有一点编程经验(例如半年至一年),而且要摈弃某些偏见(例如C语言天下无敌或JavaScript是新手玩具)。最后,你至少要有一点耐心与时间。
书籍详细信息 | |||
书名 | JavaScript语言精髓与编程实践站内查询相似图书 | ||
9787121156403 如需购买下载《JavaScript语言精髓与编程实践》pdf扫描版电子书或查询更多相关信息,请直接复制isbn,搜索即可全网搜索该ISBN | |||
出版地 | 北京 | 出版单位 | 电子工业出版社 |
版次 | 2版 | 印次 | 1 |
定价(元) | 79.0 | 语种 | 简体中文 |
尺寸 | 23 × 18 | 装帧 | 平装 |
页数 | 476 | 印数 |
JavaScript语言精髓与编程实践是电子工业出版社于2012.3出版的中图分类号为 TP312 的主题关于 JAVA语言-程序设计 的书籍。
周爱民, 著
周爱民, 著
(美) 伯纳姆 (Burnham,T.) , 著
(美) 达格特 (Daggett,M.) , 著
袁建洲, 编著
陈争航, 编著
(美) 拉希 (Raasch,J.) , 著
(美) 克罗克福德 (Crockford,D.) , 著
(美) 道格拉斯, (美) 克罗克福德, 著