JavaScript高级程序设计读书笔记

关于JavaScript和ECMAScript的关系

核心:ECMAScript
文档对象模型:DOM
浏览器对象模型:BOM
ECMA-262:定义的ECMAScript和web浏览器没有依赖关系。

ECMAScript兼容:
1.支持ECMA-262描述的所有“类型、值、对象、属性、函数以及程序句法和语义”。
2.支持Unicode字符标准。
3.添加ECMA-262没有描述的“更多类型、值、对象、属性和函数”。ECMA-262所说的这些新增特性,主要是指该标准中没有规定的新对象和对象的新属性。
4.支持ECMA-262没有定义的“程序和正则表达式语法”。(也就是说,开源修改和扩展内置的正则表达式语法)

文档对象模型(DOM):
是针对XML但经过扩展用于HTML的应用程序编程接口(API)。
DOM把整个页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。

DOM 1级由两个模块组成:
DOM核心(DOM Code)和 DOM HTML

DOM 2级在DOM的基础上又扩充了鼠标和用户界面事件、范围、遍历(迭代DOM文档的方法)等细分模块,而且通过对象接口增加了对CSS的支持。

DOM 2级引入的新模块:
1.DOM试图(DOM Views)
2.DOM事件(DOM Events)
3.DOM样式(DOM Style)
4.DOM遍历和范围

DOM 3级:
1.引入了以统一方式加载和保存文档的方法(在DOM加载和保存模块中定义)
2.新增了验证文档的方法(在DOM验证模块中定义)

BOM:从根本上讲,BOM只处理浏览器窗口和框架,但习惯上也把所有针对浏览器的JS扩展算作BOM的一部分。
1.弹出新浏览器窗口的功能
2.移动、缩放和关闭浏览器窗口的功能
3.提供浏览器详细信息的navigator对象
4.提供浏览器所加载页面的详细信息的location对象
5.提供用户显示器分辨率详细信息的srceen对象
6.对cookies的支持
7.像XMLHttpRequest和IE的ActiveXObject的自定义对象

小结:
JS是一种专为与网页交互而设计的脚本语言。
由下列三个不同的部分组成:
1.ECMAScript,由ECMA-262定义,提供核心语言功能
2.文档对象模型,提供访问和操作网页内容的方法和接口
3.浏览器对象模型,提供与浏览器交互的方式

1
<script>元素6个属性

1.async:可选。表示应该立即下载脚本,但不应妨碍页面中的其他操作。只对外部脚本文件有效。
2.charset:可选。表示通过src属性指定的代码的字符集。
3.defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。
4.language:已废弃。
5.src:可选。表示包含要执行代码的外部文件
6.type:可选。开源看成language的替代属性。

1
<script>
标签中加入defer属性相当于告诉浏览器立即下载但是延迟执行。
1
2
在现实中,延迟脚本并不一定会按照顺序执行,
也不一定会在DOMContentLoader事件触发前执行,因此最好只包含一个延迟脚本

如果HTML中包含了两个都加了async属性的script标签,第二个脚本文件可能会在第一个脚本文件之前执行,因此两者之间互不依赖非常重要。指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。为此,异步脚本不要在加载期间修改DOM。
异步脚本一定会在页面的load事件前执行,但可能会在DOMContentLoaded事件触发之前或之后执行。

外部文件的优点:
1.可维护性:遍及不同HTML页面的JavaScript会造成维护问题。
2.可缓存:浏览器能够根据具体的设置缓存连接的所有外部JavaScript文件。
3.适应未来:通过外部文件来包含JavaScript无须使用XHTML或注释hach。

文档类型(doctype)的两种文档模式:
1.混杂模式(quirks mode):会让IE的行为与(包含非标准特性的)IE5相同。
2.标准模式(standards mode):让IE的行为更接近标准行为。

虽然这两种模式主要影响CSS内容的呈现,但在某些情况下也会影响到JavaScript的解释执行。

如果在文档开始处没有发现文档类型声明,则所有浏览器都会默认开启混杂模式。但混杂模式不是什么值得推荐的做法,因为不同浏览器在这种模式下的行为差异非常大,如果不使用某些hack技术,跨浏览器的行为根本就没有一致性可言。
对于IE提出的标准模式,可以通过使用过渡型(transitional)或框架集型(frameset)文档类型来触发。

标识符
1.第一个字符必须是一个字母、下划线、一个美元符号
2.其他字符可以是字母、下划线、美元等或者数字

严格模式(”use strict”;<-编译指示)
要在整个脚本中启用严格模式,可以在顶部添加上述编译指示。

关键字:

1
2
3
4
break do instanceof typeof case else 
new var catch finally return void continue
for switch while debugger function this with
default if throw delete in try

保留字:

1
2
3
4
5
6
abstract enum int short boolean export 
interface static byte extends long super
char final native synchronized class float
package throws const goto private
transient debugger implements protected
volatile double import public

严格模式下保留字缩减为:

1
class enum extends super const export import

严格模式下,第五版对以下保留字施加了限制

1
implements package public interface private static let protected yield

1
第5版对eval和arguments还施加了限制,在严格模式下,这两个名字也不能作为标识符或属性名,否则会抛出错误。

用var操作符定义变量将成为该变量的作用域中的局部变量。也就是说,如果在函数中使用var定义一个变量,那么这个变量在函数退出后就会被销毁。

ECMAScript有五种简单数据类型:
1.Undefined
2.Null
3.boolean
4.Number
5.String
还有一种复杂数据类型(object)。
object本质上是由一组无序的名值对组成的。

typeof操作符:
返回下列某个字符串
“undefined” —–如果这个值未定义
“boolean” —–如果这个值是布尔值
“string” —–如果这个值是字符串
“number” —–如果这个值是数组
“object” —–如果这个值是对象或null
“function” —–如果这个值是函数

1
2
从技术角度讲,函数在ECMAScript中是对象,不是一种数据类型。
然而,函数也确实有一些特殊属性,因此通过typeof操作符来区分函数和其他对象是必要的。

1.Undefined类型
ECMA-262第三版引入undefined是为了正式区分空对象指针与未经初始化的变量。
对未初始化和未声明的变量执行typeof操作符都返回了undefined值;这个结果有其逻辑上的合理性。因为虽然这两种变量从技术角度看有本质区别,但实际上无论对哪一种变量也不可能执行真正的操作。

2.Null类型
Null类型是第二个只有一个值的数据类型,这个特殊的值是null。从逻辑角度来看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null值时会返回“object”的原因

1
如果在null和undefined之间相等操作符(==)总是返回true。但是单独初始化变量,使变量是undefined,此时变量的布尔值是false。定义一个变量,使变量值为null,此时变量的布尔值也是false。

只要意在保存对象为变量,而且还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且有助进一步区分null和undefined。

3.Boolean类型
该类型只有两个字面值:true和false。
这两个值与数字值不是一回事,因此true不一定等于1,而false也不一定等于0。
可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值。
例:

1
2
var message = 'hello word!';
var messageB = Boolean(message);

数据类型 转换为true的值 转换为false的值
Boolean true false
String 任何非空字符串 空字符串
Number 任何非零数字值(包括无穷大) 0和NaN
Object 任何对象 null
Undefined 不适用 Undefined

4.Number类型
整数和浮点数值
十进制,可以直接定义

1
2
var Ocal = 070;  //八进制
var hex = 0xA; //十六进制

1).浮点数

1
var floatN = 3.125e7;(科学记数法)//3.125*10^7

浮点数值的最高精度是17位小数。
*不要测试某个特定的浮点数值,例如:
1
2
3
if(a+b == 0.3){
alert("u got 0.3 ");
}

不要这样测试,因为0.2+0.1的结果是0.3000000000000004。这个因为ECMA-262是使用基于IEEEE754数值的浮点计算的通病。

2).数值范围
由于内存的限制,ECMAScript能够表示的最小数值保存在Number.MIN_VALUE中,大多数浏览器这个值是5e-324,最大数值保存在Number.MAX_VALUE,大多数浏览器这个值是1.7976931348623157e+308。如果在某次计算的结果超过了JavaScript的数值范围的值,那么这个数值将被自动转换或特殊的Infinity值。具体来说,如果这个数为负数,则会被转换成-Infinity,如果这个值是整数,则会被转换成Infinity。
Infinity不能参与计算,要确定一个数值是不是有穷的,可以用isFinite()函数,在最大与最小之间时会返回true。
尽管在计算中很少出现某些值超出表示范围的情况,但在执行极小或极大数值的计算时,检测监控这些值时可能的,也是必须的。

3).NaN(not a number)
是一个特殊的数值。这个数值用于表示一个本来要返回数值的操作数未返回的情况(这样就不会抛出错误了)。
NaN的特点:
(1).任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。
(2).NaN与任何值都不相等,包括NaN本身针对NaN,ECMAScript定义了isNaN()函数,这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否“不是数值”。
*isNaN()确实也适用于对象。在基于对象调用isNaN()函数时,会首先调用对象的valueOf()方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用toString()方法,再测试返回值。而这个过程也是ECMAScript中内置函数和操作符的一般执行流程

4).数值转换

1.Number()函数

a.如果是Boolean值,true和false将分别转换为1和0
b.如果是数值,只是简单的传入和返回
c.如果是null值,返回0
d.如果是undefined,返回NaN
e.如果是字符串,返回NaN
f.如果是字符串,遵循下列规则:

(1).如果字符串只包含数字,将其转化为十进制
(2).如果字符串中包含有效的浮点格式,将其转换为对应的浮点数值
(3).如果字符串中包含有效的十六进制格式,如“0xf”,则将其转换为相同大小的十进制整数值
(4).如果字符串中是空的(不包含任何字符),则将其转换为0
(5).如果字符串中包含除上述格式之外的字符,则将其转换为NaN
(6).如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的字符串值

2.parseInt()函数
从第一个非空字符开始,如果第一个不是数字字符或者负号,parseInt()返回NaN。如果第一个是数字字符或者负号就会继续解析,知道解析完所有后续字符或者遇到了一个非数字字符。因为ECMAScript3和5在解析八进制时有分歧,于是可以给parseInt()函数添加参数。
如:

1
var num = parseInt("0xAF",16);//175

3.parseFloat()函数
与parseInt()解析类似,但第一个小数点是有效的,从第二个小数点开始无效。
parseFloat与parseInt不同的一个地方是parseFloat会始终忽略前面的0,且只解析十进制值,因此它没有用第二个参数指定基数的用法。
最后,如果用parseFloat可解析为整数的数,parseFloat()会返回整数。

5.string类型
String类型用于表示由零或多个16位Unicode字符组成的字符序列,即字符串。
(1).字符字面量

字面量 含义
\n 换行
\t 制表
\b 退格
\r 回车
\f 进纸
\ 斜杠
\’’ 单引号,用单引号表示的字符串中使用
\”” 双引号,用双引号表示的字符串中使用
\xnn 以十六进制代码nn表示一个字符(n为0~F)
\unnnn 以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)

例如:

1
var text = "this is the letter sigma:\u03a3 .";//Σ

这个text有28个字符,且text.length = 28。length这个属性返回的字符数包括16位字符的数目。如果字符串中包含双字节字符(汉字及中文标点),那么length属性可能不会精确的返回字符串中的字符数目

(2).字符串的特点
ECMAScript中的字符串是不可变的,也就是说,字符串一旦创建,他们的值就不能改变。

(3).转换为字符串
a.使用toString()方法。这个方法唯一要做的就是返回相应值的字符串表现。
数值、布尔值、对象和字符串值都有toString()方法。但null和undefined没有这个方法。
多数情况下,调用toString()方法不必传递参数,但是在调用数值的toString()方法时,可以传递一个参数:输出数值的基数
例如:

1
2
3
4
var num = 10;
alert(num.toString(10));//"10"
alert(num.toString(2));//"1010"
alert(num.toString(8));//"12"

b.在不知道要转换的值是不是null和undefined的情况下,还可以使用转型函数String(),这个函数能够将任何类型的值转换为字符串。
规则:
1.如果值有toString()方法,则调用该方法(没有参数)并返回相应的结果
2.如果值是null,则返回“null”
3.如果值是undefined,则返回“undefined”
例如:

1
2
3
4
5
6
7
8
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1));//"10"
alert(String(value2));//"true"
alert(String(value3));//"null"
alert(String(value4));//"undefined"

6.object类型
ECMAScript中的对象其实就是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型的名称来创建。
object的每个实例都具有下列属性和方法:

(1).cnstructor:保存着用于创建当前对象的函数,构造函数(constructor)就是object()。
(2).hasOwnProperty(propertyName):用于检查给定的属性在当前对象示例中(而不是实力原型中)是否存在。其中,作为参数的属性名必须以字符串形式指定(例如:o.hasOwnProperty(“name”))
(3).isPrototypeOf(object):用于检查传入的对象是否传入对象模型。
(4).propertyIsEnumerable(propertyName):用于检查给的属性是否能够使用for-in语句来枚举。与hsaOwnProperty()方法一样,作为参数的属性名必须以字符串形式指定
(5).toLocaleString():反对对象的字符串表示,该字符串与执行环境的地区对应
(6).toString():返回对象的字符串表示
(7).valueOf():返回对象的字符串、数值或布尔值表示。通常与toString()方法的返回值相同。object是所有对象的基础,因此所有对象都具有这些基本的属性和方法。

操作符
ECMA-262描述了一组用于操作数据值的操作符。算术操作符(+
、-),位操作符、关系操作符和相等操作符

1.一元操作符
(1).递增和递减操作符
1).前置型(++a)(–a)
执行前置递增和递减操作时,变量的值都是在语句被值以前改变的(在计算机科学领域,这种情况通常被称为副效应)

2).后置型(a++)(a–)
递增和递减操作符时在包含他们的语句被求值之后才执行的。

前置加减和后置加减这4个操作符对任何值都适用。(整数、字符串、布尔值、浮点数值和对象)
规则:
a.在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减1的操作。字符串变量成数值变量。
b.不包含有效数字字符的字符串时,将变量的值设置为NaN。字符串变量变成数值变量。
c.false时,现将其转换为0再执行加减1的操作,布尔值变量变成数值变量。
d.true时,先将其转换为0再执行加减1的操作,布尔值变量变成数值变量。
e.在应用于浮点数值时,执行加减1的操作
f.应用于对象时,先调用对象的valueOf()方法以取得一个可供操作的值,然后对该值应用前述规则。如果结果时NaN,则在调用toString()方法后再应用前述规则。对象变量变成数值变量。

2.一元加和减操作符(+、-)
+放在数值前面,对数值不会产生任何影响,但在非数值应用一元加操作时,操作符会像Number()转型函数一样对这个值执行转换。如:false/true -> 0/1
-放在数值前面主要是用于表示附属,应用于非数值的其他类型,也会先转换再变为负数

3.位操作符
位操作符用于再在最基本的层次上,即按内存中表示数值的位来操作数值。
ECMAScript中所有数值都以IEEE-754 64位格式存储,但操作符并不直接操作64位的值,而是先将其转换位32位的整数然后执行操作,最后再将结果转换回64位。
对于有符号的整数,32位中的前31位用于表示整数的数值。第32位用于表示数值的符号:0表示正数,1表示负数。表示符号的位叫符号位,符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,3位中的每一位都表示2的幂
如:18的二进制

负数同样以二进制存储,但使用的格式是二进制补码。
计算二进制补码:
(1).求这个数值绝对值的二进制码(如:-18,要先求18)
(2).求二进制反码,即将0替换成1,将1替换成0
(3).得到的二进制反码加1

ECMAScript会尽力向我们隐藏所有计算过程
如:

1
2
var num = -18;
alert(num.toString(2));//"-10010"

*Bug:转换过程(64-> 32 -> 64)导致了一个严重的副效应。

在对特殊NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。

(1).按位非(NOT)
按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。按位非是ECMAScript操作符中少数几个与二进制计算有关的操作符之一
例如:

1
2
var num1 = 25;
var num2 = ~num1;//-26

1
2
var num1 = 25;
var num2 = -num1-1;//-26

总结:
按位非操作的本质:操作数的负值减1。
虽然第二个方式也可以实现和第一个一样的结果,但按位非是在数值表示的最底层执行操作,因此速度更快。

(2).按位与(AND)
&表示按位与,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行AND操作

第1个数值的位 第2个数值的位 结果
1 1 1
1 0 0
0 1 0
0 0 0

简单来说,按位与操作只在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0
例如:

1
2
var result = 25 & 3 ;
alert(result);//1

原因:

(3).按位或(OR)
按位或操作符由一个竖线符号(|)表示,同样也有两个操作数。按位或操作遵循下表

第1个数值的位 第2个数值的位 结果
1 1 1
1 0 1
0 1 1
0 0 0

由此可见,按位或操作是有一个位是1就返回1,只有2个位同为0时才返回0
例如:

1
2
var result = 25 | 3 ;
alert(result);//27

原因:

二进制11011等于27

(4).按位异或(XOR)
按位异或操作符是由一个(^)表示,也有两个操作数。以下是按位异或的真值表

第1个数值的位 第2个数值的位 结果
1 1 0
1 0 1
0 1 1
0 0 0

这个操作在两个数对应位上只有1个1时才返回1
例如:

1
2
var result = 25 ^ 3 ;
alert(result);//26

原因:

二进制11010等于26

(5).左移
左移操作符由2个小于号(<<)表示。这个操作符会将数值的所有位向左移动指定的位数。
例如:

1
2
var oldValue = 2 ;
var newValue = oldValue << 5;//64

原因:

红色的0代表符号位
左移过后1后面都是用0填充
*左移不会影响操作数的符号位

(6).有符号的右移
有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位
例如:

1
2
var oldValue = 64 ;
var newValue = oldValue >> 5;//2

原因:

红色的0代表符号位
右移过后符号位后面用0填充,符号位不动
*有符号的右移不会影响操作数的符号位

(7).无符号右移
无符号右移操作由3个大于号(>>>)表示,这个操作符会将数值的所有32位都向右移动。对正数来说,无符号右移的结果与有符号右移相同
例如:

1
2
var oldValue = 64 ;
var newValue = oldValue >>> 5;//2

但对于负数来说,情况就不一样了。首先,无符号右移是以0来填充空位,而不是像有符号右移那样以符号位的值来填充空位。所以,对正数的无符号右移与有符号右移结果相同,但对负数的结果就不一样了。无符号右移操作符会把负数的二进制码当成正数的二进制码。因为负数以其绝对值的二进制补码形式表示,因此会导致无符号右移后的结果非常之大。