《JavaScript语言精粹》
第1章 精华
第2章 语法
2.1 空白
空白可能表现为格式化字符或注释的形式。空白通常没有意义,但是偶尔需用来分隔字符序列,否则会被合并成一个单一的字符
2.2 标识符
标识符由一个字字母开头,其后可选择性的加上一个或多个字母、数字或下划线。标识符不能使用下面这些保留字
abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false
final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with
标识符被用于语句、变量、参数、属性名、运算符和标记
2.3 数字
2.4 字符串
字符串字面量可以背包围在单引号或双引号中,它可以是0个或多个字符。\(反斜杠符号)是转义字符。
字符串是不可变的,一旦创建,永远无法改变。但是通过 + 运算符去连接其他的字符串从而得到一个新字符串。
2.5 语句
语句往往从上到下的顺序被执行。JavaScript可以通过条件语句(if 和 switch)、循环语句(while、for和do)、强制跳转语句(break、return和throw)和函数用来改变执行顺序
JavaScript中的代码块不会创建一个新的作用域
object.hasOwnProperty(variable):确定这个属性名就是该对象的成员,还是从其原型链里面找到的
try语句执行一个代码块,并捕获改代码块抛出的任何异常。catch从句定义了一个新的变量,它将接收该异常对象
throw语句抛出一个异常,如果throw语句在一个try代码块中,那么控制权会跳到catch从句中。如果throw语句在函数中,则该函数调用被放弃,且控制权会跳到调用该函数的try语句的catch从句中。
return语句会使一个函数提前返回。也可以指定要返回的值,如果没有指定返回表达式,那么其返回值是undefined。JavaScript不允许在return关键字和表达式之间换行
break语句会使用程序退出一个循环语句或switch语句,它可以知道一个可选的标签,那会使程序退出带该标签的语句,JavaScript不允许在break关键字和表达式之间换行
2.6 表达式
最简单的表达式是字面量值(字符串或数字)、变量、内置的值(true、false、null、undefined、NaN和infinity)、以new前导的调用表达式,以delete前导的属性存取表达式、包在圆括号中的表达式、以一个前缀运算符作为前导的表达式、或者表达式后面跟着:
- 一个插入运算符与另一个表达式
- 三元运算符 ? 表达式 : 表达式
- 一个函数调用
- 一个属性存取表达式
2.7 字面量
对象字面量是一种方便指定新对象的表达式,属性名可以是标识符或字符串。这些名字被当作字面量名而不是变量名来对待。所以对象的属性名在编译时才能知道。属性的值就是表达式
2.8 函数
函数字面量定义了函数值。它可以有一个可选的名字,用于递归的调用自己。可以指定一个参数列表,这些参数将作为变量由调用时传递的实际参数(arguments)初始化。函数的主题包括变量定义和语句
第3章 对象
JavaScript的简单类型包括数字、字符串、布尔值(true和false)、null值和undefined值。其他所有的值都是对象。JavaScript中的对象是可变的键空集合。
JavaScript中的对象是无类别(class-free)的。它对新属性的名字和值没有约束。对象适合用于收集和管理数据。对象可以包含其他对象,所以可以简单地表示成树形或图形结构
3.1 对象字面量
一个对象字面量包围在一对花括号中的零或多个“名/值”。对象可以嵌套
var empty_object={}
var stooge = {
'first-name':'jerome',
'last-name':'howard'
}
3.2 检索
检索对象中包含的值
- 采用[ ]后缀中括住一个字符串表达方式
stooge['first-name']
- 可以用 . 表示法代替
flight.departure.IATA
3.3 更新
对象中的值通过赋值语句来更新,如果对象中存在该属性名,则这个属性的值被替换,如果对象中没有那个属性名,那么该属性就被扩充到该对象中
3.4 引用
对象通过引用来传递,它们永远不会被拷贝
var x = stooge
x.nickname = 'Curly'
var nick = stooge.nickname
// 因为x和stooge是指向同一个对象的引用,所以nick为’Curly‘
3.5 原型
每个对象都连接到一个原型对象,并且它可以从中继承属性。所有通过对象字面量创建的对象都连接到Object.prototype这个JavaScript中标准的对象
原型连接只有在检索值的时候才被用到。如果我们尝试去获取对象的某个属性值,且该对象没有此属性名,那么JavaScript会试着从原型对象中获取属性值。如果原型对象也没有该属性,那么再从它的原型中寻找,依次类推,知道该过程最后到达终点Object.prototype。如果想要的属性完全不存在与原型链中,那么结果就是undefined值,这个过程称为委托
prototype
prototype属性,是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数所创建的实例的原型对象。这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法
_proto_
_proto_是原型链查询中实际用到的,它总是指向prototype,换句话说就是指向构造函数的原型对象,它是对象独有的。
3.6 反射
两种方法处理不需要的属性
- 让程序检查并剔除函数值。
- 使用
hasOwnProperty
方法,如果对象拥有独有的属性,它将返回hasOwnProperty方法不会检查原型链
3.7 枚举
3.8 删除
delete运算符可以用来删除对象的属性。它将会移除对象中确定包含的属性。它不会触及原型链中的任何对象
3.9 减少全局变量污染
- 减少使用全局变量,只创建唯一一个全局变量,将多个全局变量都整理在一个名称空间下。减少与其他应用程序,组件或类库之间产生相互影响的可能性
- 使用闭包来进行信息隐蔽的方式
第4章 函数
函数包含一组语句,它们是JavaScript的基础模块单元,用于代码复用、信息隐藏和组合调用。函数用于指定对象的行为。
4.1 函数对象
在JavaScript中函数就是对象。对象是“名/值’对的集合并拥有一个连到原型对象的隐藏连接。
4.2 函数字面量
4.3 调用
调用一个函数将暂停当前函数的执行,传递控制权和参数给新函数。
除了声明时定义的形式参数,每个函数接受两个附加的参数:this和arguments
this的值去决定于调用的模式,JavaScript中一共有四种调用模式:方法调用模式、函数调用模式、构造器调用模式和apply调用模式
-
方法调用模式
当一个函数被保存为对象的一个属性时,称之为方法。当一个方法被调用时,this被绑定到该对象。
-
函数调用模式
当一个函数并非一个对象的属性时,那么它被当作一个函数来调用。当函数以此模式调用时,this被绑定到全局对象
-
构造器调用模式
如果在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上
-
Apply调用模式
apply方法构建一个参数数组并用其去调用函数。它允许选择this的值。apply方法接收两个参数。第一个是被绑定给this的值,第二个是参数数组
4.4 参数
arguments数组,通过它函数可以访问所有被它调用时传递给它的参数列表,包含那些没有被分配给函数声明时定义的形式参数的多余参数
4.5 返回
4.6 异常
JavaScript提供了一套异常处理机制。异常是干扰程序的正常流程的非正常(但并非完全是出乎意料)的事故。当查出事故时,程序抛出异常
throw{ }
try{ }catch(){ }
4.7 给类型增加方法
JavaScript允许给语言的基本类型增加方法。例如: 通过给Object.prototype增加方法来使用的该方法对所有对象可用。这样的方式对函数,数组,字符串,数字,正则表达式和布尔值同样适用
例:
// 通过给Function.prototype增加方法来使得该方法对所有函数可用:
Function.prototype.method = function(name, func) {
this.prototype[name] = func
return this
}
4.8 递归
递归函数会直接或间接的调用自身的一种函数。
“汉诺塔”
var hanoi = function (disc, src, aux, dst){
if(disc > 0) {
hanoi(disc-1, src, dst, aux)
document.writeln('Move disc ' + disc + ' from ' + src + ' to ' + dst)
hanoi(disc-1, aux, src, dst)
}
}
hanoi(3, 'Src', 'Aux', 'Dst')
尾递归
是一种在函数的最后执行递归调用语句的特殊形式的递归
// 构建一个带尾递归的函数,它会返回自身调用的结果,所以是尾递归
function factorial(i, a) {
a = a || 1;
if (i < 2) {
return a;
}
return factorial(i-1, a*i)
}
document.writeln(factorial(4))
4.9 作用域
作用域控制这变量与参数的可见性及生命周期。减少了名称冲突,提供了自动内存管理
4.10 闭包
作用域的好处是内部函数可以访问定义它们的外部函数的参数和变量
某函数可以访问它被创建时所处的上下文环境,称之为闭包
4.11 回调
网络上的同步请求将会导致客户端进入假死状态。如果网络传输或服务器慢,响应性的降低将是不可接受的
更好的方式是发起异步请求,提供一个当服务器的响应到达时将被调用的回调函数。异步的函数立即返回,这个客户端就不会被阻塞
4.12 模块
可以用函数和闭包来构造模块,模块是一个提供接口却隐藏状态与实现的函数或对象。通过使用函数去产生模块,完全摒弃全局变量的使用
模块模式的一般形式: 一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可访问到的地方
使用模块模式就可以摒弃全局变量的使用。促进了信息隐藏和其他优秀的设计实践。对于应用程序的封装,或者构造其他单例兑现个,模块模式非常有效
4.13 级联
有些地方没有返回值,例如: 一个设置或修改对象的某个状态却不返回任何值的方法就是典型的例子。如果让这些方法返回this而不是undefined,就可以启用连级。在一个连级中,可以在单独的语句中依次调用同一个对象的很多方法。
连级可以产生具有很强表现力的接口。也能控制那种构造试图一次做太多事情的接口的趋势
4.14 套用
套用允许将函数与传递给它的参数相结合产生出一个新的函数
var add = function (a,b) {
if(typeof a !== 'number' || typeof b !== 'number' ) {
throw {
name: 'TypeError',
message: 'add needs numbers'
}
}
return a + b
}
Function.prototype.method = function(name, func) {
this.prototype[name] = func;
return this
}
Function.method('curry', function() {
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
return function() {
return that.apply(null, args.concat(slice.apply(arguments)))
}
});
var add1 = add.curry(1)
document.writeln(add1(6))
4.15 记忆
记忆:函数可以用对象去记住先前操作的结果,从而能避免无谓的运算。
// 一般形式的记忆函数
var memoizer = function(memo, fundamental) {
var shell = function(n) {
var result = memo[n]
if (typeof result !== 'number') {
result = fundamental(shell, n)
memo[n] = result
}
return result
}
return shell
}
var fibonacci = memoizer([0,1], function(shell, n){
return shell(n-1) + shell(n-2) //Fibonacci数列
// return n*shell(n-1) // 阶乘公式
})
for (var i = 0; i <= 10; i++) {
document.writeln( i + ':' + fibonacci(i) + '<br>')
}
第5章 继承
5.1 伪类
当一个函数对象被创建时,Function构造器产生的函数对象会运行类似于这样的一些代码:
this.prototype = { constructor: this }
新函数对象被赋予一个prototype属性,其值包含一个constructor属性且属性值为该新函数对象。该prototype对象是存放继承特征的地方。因为JavaScript语言没有提供一种方法去确定哪个函数是打算用来作构造器的,所以每个函数都会得到一个prototype对象。
// 伪类模式隐藏丑陋细节
Function.prototype.method = function(name, func) {
this.prototype[name] = func;
return this
}
Function.method('inherits', function(Parent) {
// 替换函数原型为一个新的函数实例
this.prototype = new Parent()
return this
})
// 定义构造器扩充原型
var Mammal = function (name) {
this.name = name
}
Mammal.prototype.get_names = function () {
return this.name
}
Mammal.prototype.says = function() {
return this.saying || ''
}
// inherits 和 method方法都返回this,则可以级联的样式编程。
// 构造Cat
var Cat = function (name) {
this.name = name;
this.saying = 'meow'
}.inherits(Mammal).method('purr', function(n) {
var i, s = '';
for (i = 0; i < n; i++) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
}).method('get_name', function() {
return this.says() + ' ' + this.name + ' ' + this.says()
})
缺点:没有私有环境;所有的属性都是公开的。无法访问super(父类)的方法。更严重的是,如果在调用构造函数时忘记在前面加new前缀,那么this将不会被绑定到一个新对象上。this将被绑定到全局对象上,这样不但没有扩充新对象,反而将破坏全局变量。
注意:
原型连接只有在检索值的时候才会被用到。如果要获取对象的某个属性值,且该对象没有属性名,那么JavaScript会从原型对象中获取属性值。如果那个原型对象也没有该属性值,那么再从它的原型中寻找,以此类推,直到该过程最后到达终点Object.prototype,如果想要的属性完全不存在于原型链中,那么结果就是undefined值。这个过程称为委托
原型关系是一种动态的关系。如果我们添加一个新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见
5.2 对象说明符
编写构造器时使其接受一个简单的对象说明符更加友好。那个对象包含了将要构建的对象的规格说明
// 与其这样写:
var myObject = maker(f,l,m,c,s)
// 不如这样写:
var myObject = maker({
first: f,
last: l,
state: s,
city: c
})
5.3 原型
5.4 函数化
目前所看到的继承模式的一个弱点是没法保护隐私。对象的所有属性都是可见的。我们没法得到私有变量和私有函数。处理办法: 模块模式的应用
构造一个将产生对象的函数的四个步骤:
- 它创建一个新对象。有很多的方式去构造一个对象。对象字面量,和new前缀连用去调用一个构造器函数,使用Object.beget方法构造一个已经存在的对象的新实例,调用任意一个会返回一个对象的函数
- 选择性的定义私有实例变量和方法。这些就是函数中通过var语句定义的普通变量
- 给这个新对象扩充方法。那些方法将拥有特权去访问参数,以及在第二步中通过var语句定义的变量
- 返回这个新对象
// 函数化构造器伪代码模板
var constructor = function (spec,my) {
var that, 其他的私有实例变量;
my = my || {};
// 把共享的变量和函数添加到my中
that = 一个新对象
// 添加给that的特权方法
var func = function() {}
that.func = func
return that
}
// spec对象包含构造器需要构造一个新实例的所有信息。spec的内容可能会被复制到私有变量中,或者被其他函数改变。或者方法可以在需要的时候访问spec的信息。(一个简化的方法是替换spec为一个单一的值。当构造对象时并不需要整个spec对象的时候,这是有用的)
// my对象是一个为继承链中的构造器提供秘密共享的容器。my对象可以选择性的使用。如果没有传入一个my对象,那么会创建一个my对象
// 分两步定义func的好处是,如果其他方法想要调用func,可以直接调用func而不是that.func()。如果该实例被破坏或篡改,甚至that.func被替换掉了,调用func的方法将会继续工作,因为私有的func不受改实例修改的影响
5.5 部件
(不是很懂)
第6章 数组
数组是一段线性分配的内存,它通过整数去计算偏移并访问其中的元素。数组可以是很快的数据结构。JavaScript没有像这种数组一样的数据结构
6.1 数组字面量
一个数组字面量是在一对方括号中包围零个或多个用逗号分隔的值的表达式。
6.2 长度
每个数组都有一个length属性。JavaScript数组的length是没有上界的。如果用大于或等于当前length的数字作为下标来保存一个元素,那么length将增大来容纳新元素。不会发生数组边界错误
6.3 删除
JavaScript的数组就是对象,所以delete运算符可以用来从数组中移除元素
使用delete删除会给数组遗留一个漏洞。
JavaScript数组的splice方法,可以删除数据,然后将后面的数据往前移动
6.4 枚举
使用for in语句可以遍历数组的所有属性,但是不能保证属性的顺序。使用for进行循环可以保证顺序
6.5 混淆的地方
注意:
常见错误,在须使用数组时使用了对象,或者在须使用对象时使用了数组
规则: 当属性名是小而连续的整数时,使用数组。否则使用对象
// javaScript在区分数组和对象上没有一个好的机制。可以通过定义is_array函数来避开缺陷
var is_array = function(value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'))
}
6.6 方法
JavaScript提供了一套作用于数组的方法。这些方法是被储存在Array.prototype中的函数,同时Array.prototype可以背扩充
6.7 维度
第7章 正则表达式
7.1 例子
正则表达式是一门简单的语言的语法规范。它以方法的形式被用于对字符串中的信息进行查找、替换和提取操作。可以处理正则表达式的方法有regexp.exec、regexp.test、string.match、string.replace、string.search和string.split。
-
^
字符表示字符串的开始 -
(?:...)
表示非捕获型分组 -
(...)
捕获型分组 -
A-Z
26个大写字母 -
a-z
26个小写字母 -
$
表示字符串的结束 -
i
忽略大小写 -
\d , [0-9]
匹配一个数字
7.2 结构
正则表达式选择:一个正则表达式选择包含1个或多个正则表达式序列
正则表达式序列:一个正则表达式序列包含1个或多个正则表达式因子
正则表达式因子:一个正则表达式因子可以是一个字符、一个由圆括号包围的组、一个字符类,或者是一个转义序列
正则表达式转义
正则表达式分组
- 捕获型:是一个被包围在圆括号中的正则表达式选择。任何匹配这个分组的字符将被捕获。每个捕获型分组都被指定了一个数字。在正则表达式中第一个捕获(的分组1,第二个捕获(的分组2
-
非捕获型:非捕获型分组有一个
(?:
前缀。非捕获型分组仅做简单的匹配;并不会捕获所匹配的文本。这会有微弱的性能优势。非捕获型分组不会干扰捕获型分组的编号 -
向前正向匹配:向前正向匹配组有一个
(?=
前缀。但是这个组匹配后,文本将倒回到它开始的地方,实际上并不匹配任何东西。这不是一个好的特性 -
向前负向匹配:向前负向匹配分组有一个
(?!
前缀。它类似于向前正向匹配分组,但只有当它匹配失败时它才进行匹配。这不是一个好的特性
正则表达式类
第8章 方法
Array
array.concat(item...)
concat方法返回一个新数组,它包含array的浅复制(shallow copy)并将1个或多个参数item附加在其后。如果参数item是一个数组,那么它的每个元素会被分别添加。
array.join(separator)
join方法把一个array构造成一个字符串。它将array中的每个元素构造成一个字符串,并用一个separator为分隔符把它们连接在一起。默认的separator是' , '。为了实现无间隔的链接,可以使用空字符串作为separator
array.pop()
pop和push方法使数组array像堆栈(stack)一样工作。pop方法移除array中的最后一个元素并返回该元素。如果该array是空的,返回undefined
Array.method('pop', function(){
return this.splice(this.length-1, 1)[0]
})
array.push(item...)
push方法将一个或多个参数item附加到一个数组的尾部。不想concat方法那样,它会修改该数组array,如果参数item是一个数组,它会将参数数组作为单个元素整个添加到数组中。它返回这个数组array的新长度值
Array.method('push',function(){
this.splice.apply(this,[this.length,0].concat(Array.prototype.slice.apply(arguments)))
return this.length
})
array.reverse()
reverse方法反转array中的元素的顺序。返回当前的array
array.shift()
shift方法移除数组array中的第一个元素并返回该元素。如果这个数组array是空的,它会返回undefined。shift通常比pop慢的多
Array.method('shift', function(){
return this.splice(0,1)[0]
})
array.slice(start,end)
slice方法对array中的一段做浅复制。第一个被复制的元素是array[start]。它将复制到array[end]为止。end参数是可选的,并且默认值是该数组的长度array.length。如果两个参数中的任何一个是负数,array.length将和他们相加来试图使它们成为非负数。如果start大于等于array.length,得到的结果将是一个新的空数组。千万别把slice和splice混淆了。
array.sort(comparefn)
sort方法对array中的内容进行适当的排序
// 给任何简单数值组排序
var m = ['aa', 'bb', 'a', 4, 5, 15, 16, 23, 42]
m.sort(function(a, b) {
if( a === b ){
return 0
}
if (typeof a === typeof b) {
return a < b ? -1 : 1
}
return typeof a < typeof b ? -1 : 1
})
console.log(m)
// 基于多个键值进行排序
var by = function (name, minor) {
return function (o, p) {
var a, b;
if (o && p && typeof o === 'object' && typeof p === 'object') {
a = o[name];
b = p[name];
if(a === b) {
return typeof minor === 'function' ? minor(o, p) : 0
}
if (typeof a === typeof b) {
return a < b ? -1 : 1
}
return typeof a < typeof b ? -1 : 1
} else {
throw {
name: 'Error',
message: 'Expected an object when sorting by' + name
}
}
}
}
var s = [
{first: '张三', last: '李四'},
{first: '王五', last: '赵六'},
{first: '赵钱', last: '孙李'}
]
s.sort(by('last', by('first')))
console.log(s)
array.splice(start, deleteCount, item...)
splice方法从array中移除1个或多个元素,并用新的item替换它们。
start是从数组array中移除元素的开始位置
deleteCount是要移除的元素个数。
-
如果有额外的参数,那些item都将插入到所移除元素的位置上。它返回一个包含被移除元素的数组
// 实现原理 Array.method('splice1', function(start, deleteCount) { var max = Math.max, min = Math.min, delta, element, insertCount = max(arguments.length - 2, 0), k = 0, len = this.length, new_len, result = [], shift_count; start = start || 0 if (start < 0) { start += len } start = max(min(start,len), 0) deleteCount = max(min(typeof deleteCount === 'number' ? deleteCount : len, len - start), 0) delta = insertCount - deleteCount new_len = len + delta // 获取被删除元素的数组 while (k < deleteCount) { element = this[start + k] if(element !== undefined) { result[k] = element } k += 1 } shift_count = len - start - deleteCount // 删除后剩余的数值 // 添加进入的数值 if (delta < 0) { k = start + insertCount while(shift_count) { this[k] = this[k - delta] k += 1 shift_count -= 1 } this.length = new_len }else if (delta > 0) { k = 1 while (shift_count) { this[new_len - k] = this[len - k] k += 1 shift_count -= 1 } } for(k=0; k<insertCount; k++) { this[start + k] = arguments[k + 2] } return result })
array.unshift(item...)
unshift方法像push方法一样用于将元素添加到数组中,但它是把item插入到array的开始部分而不是尾部。返回array的新的长度值
Array.method('unshift', function(){
this.splice.apply(this,[0,0].concat(Array.prototype.slice.apply(arguments)))
return this.length
})
Function
function.apply(thisArg, argArray)
apply方法调用函数function,传递一个将被绑定到this上的对象和一个可选的参数数组。apply方法被调用在apply调用模式(apply invocation pattern)
// 实现原理
Function.method('bind', function(that) {
// 返回一个函数,调用这个函数就像它是那个对象的方法一样
var method = this, slice = Array.prototype.slice, args = slice.apply(arguments, [1]);
return function() {
return method.apply(that, args.concat(slice.apply(arguments, [0])))
}
})
var x = function() {
return this.value
}.bind({value: 666})
console.log(x())
Number
number.toExponential(fractionDigits)
toExponential方法把这个number转换成一个指数形式的字符串。可选参数fractionDigits控制起小数点后的数字位数,它的值必须在0到20之间
number.toFixed(fractionDigits)
toFixed方法把这个number转换成为一个十进制数形式的字符串。参数可以控制其数字位数。它的值必须在0和20之间。默认0
number.toPrecision(precision)
toPrecision方法将number转成十进制数形式的字符串。参数可以控制有效数字的位数。值必须在0到21之间
number.toString(radix)
toString方法把这个number转换成为一个字符串。参数radix控制基数。它的值必须在2和36之间。默认radix是以10为基数。radix最常用的是整数,但是也可以用任意数字
Object
object.hasOwnProperty(name)
如果这个object包含了一个名为name的属性,那么hasOwnProperty方法返回true。原型链中的同名属性是不会被检查的。这个方法对name就是hasOwnProperty时不起作用,此时返回false
RegExp
regexp.exec(string)
如果它成功地匹配regexp和字符串string,它会返回一个数组。
regexp.test(string)
test方法是使用正则表达式的最简单(最快)的方法。如果该regexp匹配string,它返回true,否则,返回false。不要对这个方法使用g标识
RegExp.method('test', function(string){
return this.exec(string) !== null
})
String
string.charAt(pos)
charAt方法返回在string中pos位置处的字符。如果pos小于0或大于等于字符串的长度string.length,它会返回空字符串。JavaScript没有字符类型(character type)。这个方法返回的结果是一个字符串
String.method('charAt', function() {
return this.slice(0,1)
})
string.charCodeAt(pos)
charCodeAt以整数形式表示在string中的pos位置处的字符的字符码位。如果pos小于0或大于等于字符串的长度string.length。返回NaN
sting.concat(string...)
concat方法通过将其他的字符串连接在一起来构造一个新的字符串。它很少被使用,因为+运算符更为方便
string.indexOf(searchString,position)
indexOf方法在string内查找另一个字符串searchString。如果它被找到,则返回第一个匹配字符的位置,否则返回-1。可选参数position可设置从string的某个指定的位置开始查找
string.lastIndexOf(searchString,position)
lastIndexOf方法和indexOf方法类似,只不过它是从该字符串的末尾开始查找而不是从开头
string.localeCompare(that)
localeCompare方法比较两个字符串。如果string比字符串that小,那么结果为负数。如果它们是相等的,那么结果为0。这类似与array.sort比较函数的约定
string.match(regexp)
match匹配一个字符串和一个正则表达式。它依据g标识来决定如何进行匹配。如果没有g标识,那么调用string.match(regexp)的结果与调用regexp.exec(string)的结果相同。
string.replace(searchValue,replaceValue)
replace方法对string进行查找和替换的操作,并返回一个新的字符串。参数searchValue可以是一个字符串或一个正则表达式对象。如果他是一个字符串,那么searchValue只会在第一次出现的地方被替换,如果searchValue是一个正则表达式并带有g标志,那么它将替换所有匹配之处。如果没有带有g标志,仅替换第一个匹配之处
replaceValue可以是一个字符串或一个函数,如果replaceValue是一个字符串,字符$拥有特别含义
string.search(regexp)
search方法和indexOf类似,只是它接受一个正则表达式对象作为参数而不是一个字符串。如果找到匹配,它返回第一个匹配的首字符位置,如果没有找到匹配,则返回-1
string.slice(start,end)
slice方法复制string的一部分来构造一个新的字符串。如果start/end参数是负数,它们将于string.length相加。end参数是可选的,并且它的默认值是string.length。end参数上一个比最末一个字符的位置值还大的数
string.split(separator,limit)
split方法把这个string分割成片段来创建一个字符串数组。可选参数limit可以限制被分割的片段数量。separator参数可以是一个字符串或一个正则表达式
string.substring(start,end)
substring的用法和slice方法一样,只是它不能处理负数参数。没有任何理由去使用substring方法
string.toLocaleLowerCase()
toLocaleLowerCase方法返回一个新字符串,将字母转换为小写格式。该方法主要用在土耳其语上
string.toLowerCase()
toLowerCase方法返回一个新的字符串,这个string中的所有字母都被转化成小写格式
string.toUpperCase()
toUpperCase方法返回一个新的字符串,这个string中的所有字母都被转化为大写格式
string.formCharCode(char...)
函数从一串数字中返回一个字符串
第9章 代码风格
第10章 优美的特性
函数是头等对象
函数是有词法作用域的闭包
基于原型继承的动态对象
对象是无类别的。我们可以通过普通的赋值给任何对象增加一个新成员元素。一个对象可以从另一个对象继承成员元素
对象字面量和数组字面量
这对创建的对象和数组来说是一种非常方便的表示法。JavaScript字面量是数据交换格式JSON的灵感之源
附录A 糟粕
A.1 全局变量
全局变量就是在所有作用域中都可见的变量。
A.2 NaN
isNaN可以辨别数字与NaN;判断一个值是否可用做数字的最佳方法是使用isFinite函数,不幸的是,isFinite会试图把它的运算数转换为一个数字
附录B 鸡肋
B.1 ==
==只有在两者类型相同时,返回的结果才是正确的,如果类型不同的话,会强制将其值的类型。所以尽量避免使用==
B.2 with语句
JavaScript提供了一个with语句,本意是想用来快捷地访问对象的属性。不幸的是,它的结果可能有时是不可预料的,所以应该避免
B.3 eval
eval函数传递一个字符串给JavaScript编辑器,并且执行其结果。
B.4 continue
continue语句跳到循环的顶部。减少使用有利于性能优化
B.5 switch贯穿
B.6 缺少块的语句
B.7 ++ --
递增和递减。使用++,--时,代码过于紧密、复杂、隐晦
B.8 new
JavaScript的new运算符创建一个继承于其运算数的原型的新对象,然后调用该运算数,把新创建的对象绑定给this。
如果忘记使用new运算符。所得到的就是普通函数,this被绑定到了全局对象,而不是新创建的对象。这意味着当函数尝试去初始化新成员元素时它将会污染全局
附录C JSLint
C.1 未定义的变量和函数
全局声明注释
/*global getElementByAttribute, breakCycles, hanoi */
JSON
JavaScript对象表示法(JavaScript Object Notation, 简称JSON) 是一种轻量级的数据交换格式。它基于JavaScript的对象字面量表示法,那是JavaScript最精华的部分之一。尽管只是JavaScript的一个子集,但它与语言无关。它可以被用于在所有以现代编程语言编写的程序之间交换数据。是一种文本格式。
JSON有6种类型的值: 对象、数组、字符串、数字、布尔值(true和false)和特殊值null。空白(空格符、制表符、回车符和换行符)可被插到任何值的前后。这可以使得JSON文本更容易被人阅读。为了减少传输和存储的成本,空白可以被省略
JSON对象是一个容纳“名/值”对的无序集合。名字可以是任何字符串。值可以是任何类型的json值,包括数组和对象
JSON数组是一个值的有序序列。