《JavaScript: The Good Parts》

JavaScript 曾是“世界上最被误解的语言”,因为它担负太多的特性,包括糟糕的交互和失败的设计。

本书拨开了 JavaScript 沾污的外衣,抽离出一个具有更好可靠性、可读性和可维护性的 JavaScript 子集,让你看到一门优雅的、轻量级的和非常富有表现力的语言。


第一章 精华 - Good Parts

第二章 语法 - Grammar

1、注释

注释应该被优先用来提高程序的可读性。但是没有用的注释比没有注释更糟糕。

块注释 /* */ 的字符也有可能同时出现在正则表达式中,所以块注释对于被注释的代码块来说是不安全的。应尽量使用 行注释 // 来代替 块注释 /* */

2、数字

JavaScript 中只有一个数字类型,它在内部被表示为64位的浮点数。

NaN 是一个数值,表示一个不能产生正常结果的运算结果。它不等于任何值,包括它自己。

Infinity 表示所有大于 1.79769...e+308 的值。

3、语句

以下值被当做假 false

  • false
  • null
  • undefined
  • 空字符串 ' '
  • 数字 0
  • 数字 NaN

其他所有的值被当做真,包括 true、字符串 "false",以及其他的对象。

第三章 对象 - Objects

JavaScript 的简单数据类型包括:数字、字符串、布尔值、null值和undefined值,其他所有值都是对象。

数组是对象,函数是对象,正则表达式是对象,当然,对象也是对象。

1、检索对象中的值

可以采用 [] 后缀中包含一个字符串表达式的方式,比如 stooge["first-name"]

JavaScript 的标识符中包含连接符 - 是不合法的,但是允许包含下划线 _

如果字符串表达式是一个字符串字面量,而且是一个合法的 JS 标识符且不是保留字,可以用 . 表示法代替,比如 stooge.firstName。优先考虑此种表示法,因为它更紧凑且可读性更好。

2、枚举

for in 语句可用来遍历一个对象中的所有属性名,包括函数和原型中的属性。最常用的过滤器是 hasOwnProperty 方法获取对象自身属性,以及使用 typeof 来排除函数。

1
2
3
4
5
6
var name;
for (name in stoogeObj) {
if(stoogeObj.hasOwnProperty(name) && typeof stoogeObj.name !== 'function') {
dosomething();
}
}

3、减少全局变量污染

最小化使用全局变量的方法之一是为应用创建一个唯一的全局变量,将全局性的资源纳入一个名称空间之下。

使用闭包来进行信息隐藏的方式,也是另一种有效减少全局变量的方法。

第四章 函数 - Functions

1、函数对象

一个内部函数除了可以访问自己的参数和变量,同时它也能自由访问把它嵌套在其中的父函数的参数和变量。

通过函数字面量创建的函数对象包含一个连到外部上下文的连接。这被称为闭包。它是 JavaScript 强大表现力的来源。

2、调用

JavaScript 是一门基于原型继承的语言。

3、模块

模块模式的一般形式是:一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可以访问到的地方。

使用模块模式就可以摒弃全局变量的使用。它促进了信息隐藏和其他优秀的设计模式实践。

4、级联

有一些方法没有返回值。如果让这些方法返回this,而不是undefined,就可以启用级联。

5、柯里化

柯里化,也常译为“局部套用”,是把多参数函数转换为一系列单参数函数并进行调用的技术。

第五章 继承 - Inheritance

在基于类的语言中,对象是类的实例,并且类可以从另一个类继承。JavaScript 是一门基于原型的语言,这意味着对象直接从其他对象继承。

1、伪类

通过构造器函数产生对象:采用构造器调用模式,即用 new 前缀去调用一个函数时,函数执行的方式会被修改。

伪类原本设计用于向面向对象靠拢,然而怪异的设计增加了污染全局变量的风险,以及没有私有环境等,所以需要慎重选择。

2、对象说明符

通过给构造器传递一个 JSON 对象,让代码更易阅读,而且不用顾虑多个参数的顺序。

3、原型

一个新对象可以继承一个旧对象的属性。

Object.create() 方法规范化了原型式继承。

1
2
3
4
5
6
7
8
9
10
var person = {
name: "Nice",
friends: ["A", "B"]
};

var anotherPerson = Object.create(person);
anotherPerson.name = "Linda";
anotherPerson.friends.push("C");

console.log(anotherPerson.friends); // ["A", "B", "C"]

4、函数化

从构造一个可以生成对象的函数开始,在这个对象A内部拥有一些变量(可以看做私有),同时内部还拥有一个对象B,对象B可以通过自己内部的特权方法访问对象A内的私有变量和方法,最后我们返回对象B。

  1. 创建一个新对象。方法可以是任意的:对象字面量、new 构造器函数、Object.create() 构造一个已经存在的对象的新实例、其他任何可以返回一个对象的函数。
  2. 有选择地定义私有实例变量和方法。var 语句定义的普通变量。
  3. 给这个新对象扩充方法。这些方法拥有特权去访问参数,以及上一步中定义的变量。
  4. 返回那个新对象。

函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。

5、部件

没懂这个是干啥的。

第六章 数组

JavaScript 提供了一种类数组特性的对象,它的属性的检索和更新的方式与对象一模一样,只不过多一个可以用整数作为属性名的特性。数组有自己的字面量格式。数组也有一套非常有用的内置方法。

1、长度 Length

length 属性的值是这个数组的最大整数属性名加上 1,它不一定等于数组里的属性的个数。

1
2
3
4
5
var myArray = [];
myArray.length; // 0

myArray[10000] = true;
myArray.length; // 10001

可以设置 length 的值。设置更大的 length 不会给数组分配更多的空间,而把 length 设小,将导致所有下标大于等于新的 length 的属性被删除。

2、枚举

因为 JavaScript 的数组其实就是对象,所以 for in 语句可以用来遍历一个数组的全部属性。然而 for in 无法保证属性的顺序。此外,还有可能从原型链中得到意外的属性错误。

因此,推荐使用常规的 for 循环语句可以有效避免这些问题。

3、判断数组和对象

1
2
3
4
5
6
7
8
9
// 不同浏览器兼容性不好
var is_array = function(value) {
return value && typeof value === 'object' && value.constructor === Array;
}

// 一种更好的方法
var is_array = function(value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};

第七章 正则表达式

1、结构

有两种方法来创建一个 RegExp 对象。优先考虑正则表达式字面量方法。

1
var my_regexp = /^([0-9]{0-3})$/;