第一章
一个完整的JavaScript应该由下列三个不同部分组成:
- ECMAScript:规定了语法、类型、语句、关键字、保留字、操作符、对象
- DOM:针对XML但经过扩展用于HTML的应用程序编程接口。DOM把整个页面映射为一个多层节点结构。通过DOM创建的这个表示文档的树形图,开发人员获得了控制页面内容和结构的主动权。借助DOM提供的API,开发人员可以轻松自如的进行删除、添加、替换或者修改任何节点。
- DOM1级:映射文档的结构。
- DOM2级:扩充了鼠标和用户界面事件、范围、迭代DOM文档,通过对象接口增加了对CSS的支持。
DOM3级:引入了以统一方式加载和保存文档的方法,验证文档的方法。
- BOM:开发人员使用BOM能够控制浏览器显示的页面以外的部分。只处理浏览器窗口和框架;扩展:
弹出新浏览器窗口功能
- 移动缩放和关闭浏览器功能
- 提供浏览器详细信息的navigator对象
- 提供浏览器加载页面详细信息的location对象
- 提供用户显示器分辨率详细信息的screen对象
- 对cookies的支持
- 像XMLHttpRequest和IE的ActiveXObject这样的自定义对象
第二章
<script>
标签定义了以下6个属性:
- async:表示应该立即下载脚本,但不应妨碍页面中其他操作。只对外部脚本文件有效。
- charset:表示通过src属性指定的代码的字符集。大多数浏览器会忽略他的值,所以很少有人用。 defer:表示脚本可以延迟到文档完全被解析和显示后再执行。只对外部脚本文件有效。
- language:已废弃。
- src:表示包含要执行代码的外部文件。
- type:可以看成是language的代替属性;表示编写代码使用的脚本语言内容类型。type=“text/javascript”这个属性并不是必须的,如果没有指定这个属性,则其默认值仍然为text/javascript。
使用JavaScript的方式有两种:直接在页面中嵌入JavaScript代码和包含外部JavaScript文件。
<script>
标签的位置:
按照传统的做法,所有的<script>
元素都应该放在页面的<head>
元素中,这种做法的目的是把所有外部文件的引用都放在相同的地方。意味着包含的所有JS文件必须等到全部JS代码被下载、解析和执行完成后们才能开始呈现的页面内容买这无疑会导致浏览器在呈现页面时出现明显的延迟,延迟期间的浏览器窗口中将是一片空白。
为了避免这个问题,现代WEB应用程序一般都把全部的JS引用放在<body>
元素中页面内容的后面,如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!--这里放内容-->
<script type="text/javascript" src=""></script>
<script type="text/javascript" src=""></script>
</body>
</html>
这样在解析包含的JS代码之前,页面的内容将完全呈现在浏览器中,而用户也会因为浏览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。
第三章 基本概念
3.1 语法
3.1.1 区分大小写
ECMAscript中的一切都区分大小写,test和Test表示两个不同的变量,而typeof(关键字)不能被使用为函数名,但typeOf是一个有效的函数名。
3.1.2 标识符
- 第一个字符必须是字母、下划线、或者是$
- 其他字符可以是字母、下划线、$或者是数字。
- 不能把关键字、保留字、true、false和null用作标识符。
3.1.4 注释
//单行注释
/*多
*行
*注
*释
*/
3.1.5 语句
语句以一个分号结尾;如果省略分号,则由解析器确定语句的结尾。加上这个分号可以避免很多错误。
加上分好也会在某些情况下增进代码的性能,因为这样解析器就不必再花时间推测应该在哪里加入分号了。
在控制语句中,使用代码块可以让编码意图更加清晰,而且降低修改代码时的出错几率。
3.2 关键字和保留字
3.3 变量
ECMAScript的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。每个变量仅仅是一个勇于保存值的占位符而已。
定义变量时要用var操作符,后跟变量名。
var message;//像这样未经过初始化的变量会保存一个特殊的值undefined
var message = "hi";
message = 100;//可以在修改变量值的同时修改值的类型
var操作符定义的变量将成为定义该变量的作用域中的局部变量。也就是说,如果函数中使用var定义的一个变量,那么这个变量在函数退出后就会被销毁。
function test(){
var message = "hi";//局部变量
}
test();
alert(message);//错误!
这里,变量message是在函数中使用var定义的,当函数被调用时,就会创建该变量并为其赋值。而在此之后,这个变量又会被立刻销毁,因此例子中的下一行代码就会导致错误。不过可以像下面这样省略var操作符,从而创建一个全局变量。
function test(){
message = "hi";//全局变量
}
test();
alert(message);//"hi"
虽然省略var操作符可以定义全局变量,但这也不是推荐的做法。因为在局部作用域中定义的全局变量很难维护,而且如果有意地忽略了var操作符,也会由于相应变量不会马上就有定义而导致不必要的混乱。给未经声明变量赋值,在严格模式下会导致跑出RefrenceError错误
可以使用一条语句定义多个变量,只要把每个变量用逗号分开即可:
var message = "hi",
found = false,
age = 29;
虽然代码中的换行和缩进不是必须的,但是能够提高代码的可读性。
3.4 数据类型
ECMAScript中有5种简单数据类型:Undefined、Null、Boolean、Number和String。还有一种复杂数据类型——Object。
ECMAScript数据类型具有动态性。
3.4.1 typeof操作符
检测给定变量的数据类型
返回字符串:
- undefined
- boolean
- string
- number
- object
- function
3.4.2 Undefined类型
3.4.3 Null类型
var car = null;
alert(typeof car); //"object"
如果定义的变量准备在将来保存对象,那么最好将该变量初始化为null而不是其他值。这样一来只要直接检查null值就可以知道相应变量是否已经存了一个对象的引用。
if(car != null){
//对car对象执行某些操作
}
实际上undefined的值是派生自null值的
alert(null == undefined);//true
只要意在保存对象的变量还没有真正保存对象,就应该明确的让该变量保存null值。
3.4.4 Boolean类型
Boolean类型时ECMAScript中使用得最多的一种类型,只有两个字面值true和false。
这两个值和数字值不是一回事。
true不一定等于1,false也不一定等于0。
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “”(空字符串) |
Number | 任何非零数字值 | 0和NaN |
Object | 任何对象 | null |
Undefined | n/a(不适用) | undefined |
var message = "Hello World!";
if(message){
alert("Value is true");
}
message字符被自动转换成了相对应的Boolean值true。
3.4.5 Number类型
var octalNum1 = 070;//八进制的56,八进制第一位必须是0,否则会被当做10进制解析
var octalNum2 = 079;//无效的八进制,解析为79
var octalNum3 = 08;//无效的八进制,解析为8
八进制在严格模式下是无效的
十六进制字面值前面必须是0x,字母A-F可以大写也可以小写
浮点数在进行算术运算的时候精确度远远不如整数。0.1+0.2的结果不是0.3而是0.300000000000000004 舍入误差
Number.MIN_VALUE 5e-324
Number.MAX_VALUE 1.7976931348623157e+308
如果JS计算中得到一个值超出数值范围的值,那么结果会自动被转换成特殊的Infinity的值。负数转换成-Infinity。
NaN和任何值都不相等,包括NaN本身
alert(NaN == NaN); //false
isNaN()可以适用于对象,在基于对象调用isNaN()函数时,会首先调用valueof()方法,然后确定该方法返回值是否可以转换为数值。如果不能再调用toString()方法,再测试返回值。
Number()
var num1 = Number("Hello World!"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); //11
var num4 = Number(true); //1
parseInt()更常用
var num1 = parseInt("1234blue"); //1234
var num2 = parseInt(" "); //NaN
var num3 = parseInt("0xA"); //10(16进制)
var num4 = parseInt("22.5"); //22
var num5 = parseInt("070"); //56(8进制)
var num6 = parseInt("70"); //70
var num7 = parseInt("0xf"); //15(16进制)
var num = parseInt("0xA",16); //10
parseFloat()忽略前导的0,只能解析10进制
3.4.6 String
字符串可以用单引号也可以双引号
转换为字符串
var age = 11;
var ageAsString = age.toString(); //字符串“11”
var found = true;
var foundAsString = found.toString(); //字符串“true”
var num = 10;
alter(num.toString()); //"10"
alter(num.toString(2)); //"1010"
alter(num.toString(16)); //"a"
如果不知道要转换的值是不是null或者undefined的情况下,可以使用转型函数String();
转换规则:
- 如果值有toString()方法,则调用该方法并返回相应结果
- 如果值是null,返回“null”
- 如果是undefined,返回“undefined”
3.4.7 Object类型
var o = new Object(); //创建一个对象
属性 | 方法 |
---|---|
constructor | 保存用于创建当前对象的函数 |
hasOwenProperty | 用于检查给定的属性在当前对象实例中是否存在 |
isPrototypeOf | 用于检查传入的对象是否是传入对象的原型 |
toLocaleString() | 返回对象的字符串表示,该字符串与执行环境地区对应 |
toString() | 返回对象的字符串表示 |
valueOf() | 返回对象的字符串、数值或布尔值表示。通常与toString方法返回值相同 |
3.5 操作符
3.5.1 一元操作符
1.递增和递减操作符
后置递增和递减与前置递增和递减有一个非常重要的区别,即递增和递减操作是在包含他们的语句被求值之后才执行的。
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; //num3 = 22
var num4 = num1 + num2; //num4 = 21
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o ={
valueOf: function(){
return -1;
}
}
s1++; //3
s2++; //NaN
b++; //1
f--; //0.10000000000000009(由于浮点舍入错误所致)
o--; //-2
2.一元加和减操作符
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o ={
valueOf:function(){
return -1;
}
}
s1 =+ s1; //1
s2 =+ s2; //1.1
s3 =+ s3; //NaN
b =+ b; //0
f =+ f; //1.1
o =+ o; //-1
s1 =- s1; //-1
s2 =- s2; //-1.1
s3 =- s3; //NaN
b =- b; //0
f =- f; //-1.1
o =- o; //1
3.5.2 位操作符
1.NOT ~
2.AND &
3.OR |
4.XOR ^
5.左移 <<
6.有符号的右移 >>
3.5.3 布尔操作符
1.逻辑非 !
2.逻辑与 &&
var found = true;
var result = (found && someUndefinedVariable);//发生错误
alert(result);//不会执行
var found = false;
var result =(found && someUndefinedVariable);//不会发生错误
alert(result);//会执行("false")
3.逻辑或 ||
利用或这一行为来避免为变量赋值null或者undefined值
3.5.4 乘性操作符
1.乘法
2.除法
3.求模
3.5.5 加性操作符
1.加法
- 如果两个操作数都是数值,执行常规的加法计算
- 如果有一个操作数是字符串,则将操作数转换成字符串,然后将两个字符串拼接
- 如果有一个操作数是对象数值或者布尔值,则调用他们的toString()得到相应的字符串值,然后再应用前面关于字符串的规则。对于null和undefined则分别调用String()函数并获取字符串“null”和“undefined”。
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is "+ num1 + num2;
var messsage = "The sum of 5 and 10 is"+( num1 + num2);
2.减法
var result1 = 5 - true; //4
var result2 = NaN - 1; //NaN
var result3 = 5 - 3; //2
var result4 = 5 - ""; //5
var result5 = 5 - "2"; //3
var result5 = 5 - null; //5
3.5.6 关系操作符
var result = "Brick" < "alphabet"; //true
var result = "Brick".toLowerCase()<"alphabet".toLowerCase(); //false
var result = "23" < "3"; //true
var result = "23" < 3; //false
var result = "a" < 3; //false 因为a被转换成了NaN
表达式 | 值 |
---|---|
null == undefined | true |
“NaN” == NaN | false |
5 == NaN | false |
NaN == NaN | false |
NaN != NaN | true |
false == 0 | true |
true == 1 | true |
true == 2 | false |
undefined == 0 | false |
null == 0 | false |
“5” == 5 | true |
3.5.8 条件操作符
variable = boolean_expression?true_value:false_value;
3.6 语句
- if
- while
- do-while
- for
- for-in
- label
- break continue
- with
- switch
3.7 函数
第4章 变量、作用域和内存的问题
4.1 基本类型和引用类型的值
基本类型的值指的是简单的数据段,引用类型的值指的是哪些可能由多个值构成的对象
引用类型的值是保存在内存中的对象。JS不允许直接访问内存中的位置。在操作对象时,实际上是在操作对象的引用而不是实际的对象。
4.1.1 动态的属性
var person = new Object();
person.name = "Fred";
alert(person.name); //"Fred"
var name ="Rose";
name.age = 27;
alert(name.age); //undefined
4.1.2 复制变量的值
var num1 = 5;
var num2 = num1;
num1中保存的值是5,当使用num1的值来初始化num2时,num2中也保存了值5。但num2中的5与num1中的5是完全独立的,该值只是num1中的5的一个副本。此后两个变量可以参与任何操作而不相互影响。
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Fred";
alert(obj2.name); //Fred
当一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到位新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上引用的是同一个对象。因此,改变其中一个变量,就会影响另一个变量。
4.1.3 传递参数
访问变量有按值和按引用
而参数只能按值传递
function addTen(num){
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20
alert(result); //30
function setName(obj){
obj.name = "Fred";
}
ver person = new Object();
setName(person);
alert(person.name); //Fred
有很多开发人员错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。
function setName(obj){
obj.Name = "Fred"
obj = new Object();
obj.name = "Greg";
}
var person =new Object();
setName(person);
alert(person.name); //Fred
如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为”Greg“的新对象。但是事实并非如此。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。
4.1.4 检测类型
var s ="Fred";
var b =true;
var i =22;
var u ;
var n = null;
var o =new Object();
alert(typeof s); //String
alert(typeof b); //Boolean
alert(typeof i); //Number
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object
alert(person instanceof Object); //变量person是Object吗
alert(colors instanceof Array); //变量color是array吗
alert(pattern instanceof RegExp); //变量pattern是RegExp吗
4.2 执行环境和作用域
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//这里可以访问color anotherColor tempColor
}
//这里可以访问color和anotherColor但不能访问tempColor
swapColors();
}
//这里只能访问color
changeColor();
4.2.1 延长作用域链
with和try-catch中的catch
4.2.2 没有块级作用于
if(true){
var color = "blue";
}
alert(color); //"blue"
在C、C++或Java中,由花括号封闭的代码块都有自己的作用于,color会在if语句执行完毕后被销毁,但在JS中,if语句中的变量声明会将变量添加到当前的执行环境中。
var color = "blue";
function getcolor(){
var color = "red";
return color;
}
alter(getcolor()); //red
4.3 垃圾收集
垃圾收集机制是自动的
4.3.1 标记清除
JS中最常用的垃圾收集方式是标记清除
4.3.2 引用计数
4.3.3 性能问题
IE:window.CollectGarbage()
Opera7:window.opera.collect()