《JavaScipt 语言精粹》 作者: Douglas Crockford
拿到这本书的时候就读错了名字。悲剧啊。内容写的挺详细的,就是书中用得铁路图实在看着有点费劲。
养分
1. beget
创建一个使用原对象作为其原型的新的对象。1
2
3
4
5
6
7if (typeof Object.beget !== 'function') {
Object.beget = function(obj) {
var F = function() {};
F.prototype = obj;
return new F();
}
}
2. 使用 hasOwnProperty
方法来判断对象是否拥有独有的属性。这个方法不会检查原型链的属性。
3. 减少全局变量污染:
- 可以把所有的全局变量放在一个全局对象里面。 把多个全局变量都整理在一个名称空间下。
- 也可以使用闭包来实现。
4. 模块,可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象。几乎可以完全摒弃全局变量的使用。通过特权函数(可以理解为接口)访问外部函数的局部变量。
1 | var moduleDemo = function() { |
5. 级联, 就是有点像函数式编程的样子。通过不断‘点’来调用,如 jquery对某个元素操作:1
2
3
4
5
6
7
8
9$('#demoId')
.removeClass('yellow')
.addClass('blue')
.on('mousedown', function(event) {
})
.on('mousemove', function(event) {
})
//这里调用的方法都是同一个对象的,然后每个方法返回的变量是 this 。
6. 套用,使用闭包实现 curry 化。调用一个函数,将传入的参数,作为闭包使用的变量。
1 | function curry(x) { |
7. 记忆,使用对象缓存(记忆)先前操作的结果,从而避免无用功操作。
1 | var fibonacci = function(n) { |
8. 函数化。解决继承模式无法设置保护隐私问题。实现更好的风筝和信息隐藏。用函数化的样式创建一个对象,并且该对象的所有方法都不使用 this 或 that,那么该对象就是持久性的。一个持久性对象就是一个简单功能函数集合。
函数化构造器的伪代码模板:
1 | var constructor = function(spec, my) { |
9. 部件。就是通过调用一个函数返回一个对象。而被调用的函数就像是一个中间者,函数的外部不需要知道内部发生什么。把传入的参数,经过函数内部的加工后,而具有了某些或某类的功能和属性。这些功能和属性就像部件一样。
构造一个能添加简单事件处理特性到任何对象上的函数。它会给对象添加一个 on 方法、一个 fire 方法和一个私有的事件注册表对象(可以把这个函数理解为一个小车间,一个对象经过这个小车间加工后,就组装了部件 on 方法、fire 方法、和事件注册表)。
1 | var eventuality = function(that) { |
eventuality(that); 用这种方式,一个构造函数可以从一套部件中组装处对象来。
10. 正则表达式,嵌套的正则表达式也能导致极恶劣的性能问题,因此简单是最好的策略。使用非捕获型分组来代替少量不优美的捕获型分组是很好的方法,因为捕获会有性能上的损失。
解析 url 例子
1 | var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/; |
^
表示这个字符串的开始。(?:([A-Za-z]+):)?
用于匹配一个协议名,当仅当它之后跟随一个:
的时候才匹配。(?: ... )
表示一个非捕获型分组。后缀?
表示这个分组是可选的,他表示重复 0或1次。(...)
表示一个捕获型分组,一个捕获型分组将复制它所匹配的文本,并将其放入 result 数组中,每个捕获型分组都将被指定一个编号。第一个捕获型分组的编号是 1, 所以该分组所匹配的文本拷贝将出现在 result[1] 中。[...]
表示一个字符类,这个字符类A-Za-z
包含26个大写字母和26个小写字母。连字符-
表示范围从 A 到 Z。后缀+
表示这个字符类将被匹配 1 次或多次。这组后面跟着字符:
表示按字面进行匹配。(\/{0,3})
是捕获型分组 2。\/
表示一个应该被匹配的 /(斜杠)。(反斜杠)表示转义。{0,3}
表示 / 将被匹配0次,或者1到3次之间。([0-9.\-A-Za-z]+)
是捕获型分组 3。它将匹配一个主机名,由1个或多个数字、字母或 . 或 - 组成。因为 - 将被转义为 \- 以防止与表示范围的连字符相混淆。(?::(\d+))?
可选的匹配端口号的分组。它由一个前置 : 加上1一个或着多个数字而组成的序列。(?::)
表示不会捕获:
,只会捕获:
后的数字。\d
表示一个数字字符,(\d+)
表示捕获型分组4, 1个或多个数字串将被捕获。(?:\/([^?#]*))?
可选的分组。[^?#]
以一个^
开始,表示这个字符类包含除了?
和#
之外的所有字符。*
表示这个字符类将被匹配0次或多次。(?:\?([^#]*))?
是一个?
开始的可选分组。([^#]*)
是捕获型分组,包含0个或多个非#
字符。(?:#(.*))?
以#
开始,.
将匹配除行结束符以外的所有字符。$
表示这个字非常的结束。
判断是否为数字
1 | var parse_number = /^-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i; |
(?:e[+\-]?\d+)?
可选的非捕获型分组。它将匹配一个 e(或 E),[+\-]?
表示一个可选的正负号。\d+
表示一个或多个数字。
11. 方法
array.concat(item…) 可以对数组进行浅拷贝,并将一个或多个参数item附加到新数组最后。1
2
3
4
5var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
var c = a.concat(b, true);
// c 是 ['a', 'b', 'c', 'x', 'y', 'z', true];
array.slice(start, end) 对 array 中的一段做浅拷贝。1
2
3
4
5var a = ['a', 'b', 'c'];
var b = a.slice(0, 1); // ['a']
var c = a.slice(1); // ['b', 'c']
var d = a.slice(1, 2); // ['b'];
var e = a.slice(4); // [];
array.splice(start, deleteCount, item…) 从 array 中移除一个或多个元素,并用新的 item 替换它们。item 是可选参数。1
2
3
4
5var a = ['a', 'b', 'c'];
var b = a.splice(1, 1, 'ache', 'bug');
// a 是 ['a', 'ache', 'bug', 'c'];
// b 是 ['b'];
string.charAt(pos)
string.chartCodeAt(pos)1
2
3
4var name = 'Curly';
var initial = name.chatAt(0); // 'C'
var otherInitial = name.chatACodet(0); // 67
string.slice(start, end)
string.substring(start, end)
这个两个方法相似,都是复制字符串的指定部分。但是 substring 不能 start 参数不能为负数。1
2
3
4var text = 'and in it he says "Any damn fool could';
var a = text.slice(18); // '"Any damn fool could'
var b = text.slice(0, 3); // 'and'
var c = text.slice(-5); // 'could'
string.split(separator, limit)
将字符串分割成数组。separator 可以是个字符串或正则表达式,limit是可选参数。1
2
3
4
5
6var digits = '0123456789';
var a = digits.split('', 5); // ['0', '1', '2', '3', '456789']
var text = 'last, first, middle';
var d = text.split(/\s*,\s*/); // ["last", "first", "middle"]
var e = text.split(/\s*(,)\s*/) // ["last", ",", "first", ",", "middle"]