第一章 精华
Nothing :)
第二章 语法
- JavaScript中,块注释
/*...*/
是不太安全的,因为正则表达中可能出现块注释的字符,下面代码会出现一个语法错误,所以建议使用行注释//
/* var a=/a*/; console.log(a.test("aaa")); */
- JavaScript中没有字符类型,表示字符是通过只包含一个字符的字符串来表示的。
- 被当做是假(falsy)的:
null
、undefined
、空字符串""
、数字0、NaN
除上面几个之外的所有值所有对象 - 被当做是真的:
throw
语句在一个try
代码块中抛出一个异常,控制流会跳转到catch
从句中;如果在throw
语句在函数中,则控制流跳转到调用该函数的try
语句的catch
从句中。
第三章 对象
- 广义的对象有对象、数组、正则表达式、函数。
- 属性的名字(key)是字符串,如果是合法标识符(JavaScript中合法标识符数字字母下划线$)且不是保留字那么不必非要在key两边加双引号
- 对象的传递是按引用传递(即通过复制引用来传递,不违背JavaScript中函数的参数都是按值传递)
- 每个对象都有原型,字面量创建的对象原型为
Object.prototype
,即var a={} a.__proto__===Object.prototype// true
- 获取对象的某个属性值,没有的话会沿着原型链寻找,最终找到
Object.prototype
还找不到会返回undefined
-
for in
遍历的顺序是不确定的 -
delete
不会触及原型链中的对象 - 最好把全局性的资源都纳入一个统一的全局变量的命名空间之下
第四章 函数
- 函数也是对象,函数对象的原型为
Function.prototype
,该原型也不算普通的对象,也是一个函数,typeof Function.prototype
为function
。
下面来看看面向对象(类)的代码风格中的实体与实体之间的关系:function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return "I am " + this.me; }; function Bar(who) { Foo.call( this, who ); } Bar.prototype = Object.create( Foo.prototype ); Bar.prototype.speak = function() { console.log( "Hello, " + this.identify() + "." ); }; var b1 = new Bar( "b1" ); var b2 = new Bar( "b2" ); b1.speak(); b2.speak();
- JavaScript中的函数参数不会进行类型检查,任何类型的值都可以传进任何参数中。
- this的绑定
- this的隐式绑定也称为方法调用模式,就是函数以一个对象的方法的形式来调用(虽然并不是真正意义上的方法,与java中的不同),绑定到调用方法的对象上。
- this的默认绑定也称为函数调用模式,就是直接调用,这时绑定到全局对象(非严格模式)或
undefined
上(严格模式)。这是一个语言设计上的错误,不过可以很容易解决,就是将this赋值给that(或者其他任何合法标识符)。 - this的new绑定也称为构造器调用模式,就是通过new关键字来调用构造函数。
-
apply
/call
调用模式,也就是this的硬绑定,apply
的第二个参数为数组,call
的第二个参数为列表。
- 可以给
Function.prototype
增加一个方法:Function.prototype.method=function(name,func){ if(!this.prototype[name]){ this.prototype[name]=func; } return this; }
这样以后给对象增加方法的时候可以直接调用,不用再写prototype这几个字符。
其实上面的最后返回一个this,是为了级联调用(级联见下面)。
- 作用域和闭包参见《你不知道的JavaScript上卷》。
- 如果在一个方法里返回this,就可以启用级联,在一个级联中,我们可以在单独一条语句中依次调用同一个对象的很多方法。例如,在一个启用级联的Ajax类库中可能允许我们以下面这样的形式去编码:
getElement('myBoxDiv') .move(350,150) .width(100) .height(100);
- 柯里化
Function.method('curry',function(){ var outterArgs=Array.prototype.slice.call(arguments), that=this; return function(){ var innerArgs=Array.prototype.slice.call(arguments); return that.apply(null,outterArgs.concat(innerArgs)); }; }); function add(a,b){ return a+b; } var addCurry=add.curry(2); console.log(addCurry(3));//5
- 记忆
有时间重新看一下,语言精粹p.43
第五章 继承
-
伪类模式(面向对象的模式)
function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return "I am " + this.me; }; function Bar(who) { Foo.call( this, who ); } Bar.prototype = Object.create( Foo.prototype ); Bar.prototype.speak = function() { console.log( "Hello, " + this.identify() + "." ); }; var b1 = new Bar( "b1" ); var b2 = new Bar( "b2" ); b1.speak(); b2.speak();
-
委托模式(也称为差异化继承)
var Foo = { init: function(who) { this.me = who; }, identify: function() { return "I am " + this.me; } }; var Bar = Object.create( Foo ); Bar.speak = function() { console.log( "Hello, " + this.identify() + "." ); }; var b1 = Object.create( Bar ); b1.init( "b1" ); var b2 = Object.create( Bar ); b2.init( "b2" ); b1.speak(); b2.speak();
-
函数化模式:(为了解决伪类和委托模式中没有办法保存私有变量的问题),我们从构造一个生成对象的函数开始,(语言精粹建议以小写字母开头,因为不需要使用new前缀,但是为了和上面保持一致,感觉还是用首字母大写比较合适,这里我首字母大写,如果以后需要小写,改过来)。包括4个步骤:
- 创建一个新对象。
- 有选择地定义私有变量和方法
- 给这个新对象添加一些特权方法
- 返回这个对象
说实话感觉和模块化差不多。
function Foo(spec){ var obj={}; obj.identify=function(){ return "I am "+spec.name; }; return obj; } var foo1=Foo({name:"foo1"}); function Bar(spec){ var obj=Foo(spec); obj.speak=function(){ console.log("Hello, "+obj.identify()+"."); }; return obj; } var bar1=Bar({name:"bar1"}); var bar2=Bar({name:"bar2"}); bar1.speak(); bar2.speak();
其中,spec对象包含构造器构造一个实例所需要的所有信息。
部件
没有看懂,语言精粹p.55
第六章 数组
- 数组的length属性是没有上界的,设置更大的length不会分配更多的空间给数组,但是将length设小将导致所有下标大于length的值被删除。
- 判断是否是数组时,最好用
Object.toString.call(a)==="[object Array]"
- 指定初始值
可以很容易地自己实现一个函数来初始化:Array.dim=function(dimention,initial){ var a=[],i; for(i=0;i<dimention;i++){ a[i]=initial; } return a; } var myArr=Array.dim(10,0);//创建一个包含10个0的数组。
第七章 正则表达式
在JavaScript中,正则表达式必需写在一行中,无论多长
一个正则表达式序列由正则表达式因子和(可选的)量词组成,每个因子可以选择是否跟随一个量词,这个量词决定了这个因子被允许出现的次数。
-
正则表达式因子
正则表达式可以是一个字符、一个组(由圆括号包围的组)、一个字符类(由方括号包围)或者一个转义序列(如\n
、\d
等)。-
字符:
除了控制字符(
\ / [ ] ( ) { } ? + * | . ^ $
),其他所有字符均会按照字面处理。 -
正则表达式分组:
正则表达式分组有四种:
- 捕获型分组
一个正则表达式分组是一个包含在圆括号里的正则表达式分支,任何匹配这个分组的字符都会被捕获,第一个分组是1,第二个分组是2,以此类推。 - 非捕获型分组
非捕获型分组就是(?: )
包围的分组,只会对字符进行简单的匹配,但是不会捕获所匹配的文本,不会干扰捕获型分组的编号,有微弱的性能优势。 - 向前正向匹配
包围在(?= )
中的分组,类似于非捕获型分组,在在这个组匹配后,文本会倒回到它开始的地方,实际上并不匹配任何东西,不是一个好特性。 - 向后负向匹配
包围在(?! )
中的分组,类似于向前正向匹配,但只有在它匹配失败时才会继续向前进行匹配,不是一个好特性。
- 捕获型分组
-
正则表达式字符类(字符集):
正则表达式字符类是一种指定一组字符的便利方式,用
[
和]
包围起来,内部可以包含任意字符(除了/ \ [ ] - ^
这几个字符),如果要包含上述几个字符,需要转义(此处的转义为字符转义)之所以排除这几个字符是因为,
/
会被当做正则表达式结束标志,需要转义;\
本身用作转义字符标志,需要转义;[
和]
是包围字符类的符号,需要转义;-
表示一个范围,比如[a-z]
表示小写字母a到z,所以需要转义;^
表示取反,即如果[
之后的第一个字符是^
,那么这个类就会排除这些特殊字符,如[^abc]
会匹配除了a,b,c之外的所有字符。 -
正则表达式转义序列:
正则表达式因子的转义和字符串或者字符类中的转义稍有不同。正则转义序列由:
-
\n
换行符 -
\r
回车符 -
\f
换页符 -
\t
制表(tab)符 -
\d
等同于[0-9]
,匹配一个数字,/D
表示与其相反的[^0-9]
-
\w
等同于[0-9A-Z_a-z]
,\W
表示与其相反的[^0-9A-Z_a-z]
-
\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v] -
\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v] -
\1
是指向分组1所捕获到的文本的一个引用,所以它能够被再次匹配,\2
是指向分组的2的引用,以此类推
-
-
-
正则表达式量词
正则表达式量词可以跟在正则表达式因子后面表示这个因子被匹配的次数。- 包围在一对花括号中的一个数字表示这个因子应该被匹配的次数,如
/www/
等同于/w{3}/
,{3,6}
会匹配3到6次(3、4、5或者6次),{3,}
会匹配3次或更多。 -
?
表示0或1次,等同于{0,1}
-
*
表示0或多次,等同于{0,}
-
+
表示1或多次,等同于{1,}
如果只有一个量词,表示趋向于进行贪婪性匹配,即匹配尽可能多的副本直到达到上限;如果这个量词后面附加一个后缀
?
则表示趋向于进行非贪婪性匹配,即只匹
配必要的副本就好。一般情况下最好坚持使用贪婪性匹配下面来看一个实例,匹配URL的正则表达式。
- 包围在一对花括号中的一个数字表示这个因子应该被匹配的次数,如
以上便是正则表达式parse_url
的所有因子。
第八章 方法
-
Array
-
concat
不修改原数组,产生一个新数组,返回生成后的新数组。 -
join
join
方法用一个seperator分隔符将数字元素连接起成一个字符串,默认的seperator是,
,join
连接字符串没有+
运算符快。返回字符串。 -
push
改变原数组,返回新数组长度。 -
pop
改变原数组,返回被移除的元素。 -
shift
改变原数组,返回被移除的元素。 -
unshift
改变原数组,返回新数组的长度。 -
reverse
改变数组,将数组反向,返回反向后的数组。 -
slice
不改变原数组,返回切割后的数组(或者说是原数组的一段浅复制)。 -
splice
改变原数组,返回包含被移除元素的数组。从第一个参数的位置,删除第二个参数个数的元素,插入第三个元素(以及第四个第五个元素...)。 -
sort
改变原数组,将原数组进行排序。
注意,sort
方法是不稳定的,排序的稳定性指的是排序后数组中的相等值的相对位置没有发生变化,而不稳定性排序则会改变相等值的相对位置
-
-
Number
-
toString
转换为字符串。 -
toFixed
保留指定小数位数的小数。 -
toPrecision
保留指定整个数字位数的小数。
-
- Object
-
RegExp
-
exec
正则表达式最强大(和最慢)的方法,详见语言精粹p.86 -
test
正则表达式最简单(和最快)的方法,详见语言精粹p.88
-
-
String
-
charAt
返回指定位置的单个字符的字符串。 charCodeAt
-
concat
连接,很少被使用,因为+
更方便 indexOf
lastIndexOf
match
replace
-
slice
复制字符串的一部分,substring
也具有这种功能,但不要使用substring
,使用slice
就行。 split
toLowerCase
toUpperCase
fromCharCode
-
第九章 代码风格
- 缩进4个空格
-
if
和(
之间加个空格,让if
看起来不会像一个函数调用 - 在除了
.
和[
之外的所有中置运算符两边加个空格 - 每个逗号和冒号后面加一个空格
- 在诸如
if
和while
这样的结构化语句中,始终使用代码块{}
- 把
{
放在一行的结尾而不是下一行的开头 - 写有用的注释
- 在其他语言中,变量在它们第一次被使用时声明是个好习惯,在JavaScript中却不是个好建议,因为JavaScript没有块作用域,最好在每个函数最好是就声明所有用到的变量。
第十章 优美的特性
emmm,没啥好像