0%

高程笔记1

高程笔记一

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

JavaScript 的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari 和 Opera)中都得到了不同程度的支持。其中,所有浏览器对 ECMAScript 第 3 版的支持大体上都还不错,而对ECMAScript 5 的支持程度越来越高,但对 DOM 的支持则彼此相差比较多。对已经正式纳入 HTML5 标准的 BOM 来说,尽管各浏览器都实现了某些众所周知的共同特性,但其他特性还是会因浏览器而异。

<script>定义了下列 6 个属性。

 async:可选。表示应该立即下载脚本,但不应妨碍页面中的其他操作, 比如下载其他资源或等待加载其他脚本。只对外部脚本文件有效。
 charset:可选。表示通过src属性指定的代码的字符集。由于大多数浏览器会忽略它的值,因此这个属性很少有人用。
 defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。 只对外部脚本文件有效。IE7 及更早版本对嵌入脚本也支持这个属性。
 language:已废弃。原来用于表示编写代码使用的脚本语言(如JavaScript、JavaScript1.2或VBScript)。大多数浏览器会忽略这个属性,因此也没有必要再用了。
 src:可选。表示包含要执行代码的外部文件。
 type:可选。可以看成是language的替代属性;表示编写代码使用的脚本语言的内容类型(也称为 MIME 类型)。虽然 text/javascript 和 text/ecmascript 都已经不被推荐使用,但人们一直以来使用的都还是text/javascript。实际上,服务器在传送JavaScript文件时使用的MIME类型通常是application/x–javascript,但在type中设置这个值却可能导致脚本被忽略。另外,在非IE浏览器中还可以使用以下值:application/javascript和application/ecmascript。考虑到约定俗成和最大限度的浏览器兼容性,目前type属性的值依旧还是text/javascript。不过,这个属性并不是必需的,如果没有指定这个属性,则其默认值仍为text/javascript

XHTML运行script

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript"><![CDATA[
function compare(a, b) {
if (a < b) {
alert("A is less than B");
} else if (a > b) {
alert("A is greater than B");
} else {
alert("A is equal to B");
}
}
]]></script>

html文档模式

标准模式

1
2
3
4
5
6
7
8
9
10
<!-- HTML 4.01 严格型 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- XHTML 1.0 严格型 -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- HTML 5 -->
<!DOCTYPE html>

非标准模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- HTML 4.01 过渡型 -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!-- HTML 4.01 框架集型 -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<!-- XHTML 1.0 过渡型 -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- XHTML 1.0 框架集型 -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

ECMAScript 中有 5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number
和 String。

3 个函数可以把非数值转换为数值:Number()、parseInt()和parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这 3 个函数对于同样的输入会有返回不同的结果。
Number()函数的转换规则如下。
 如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
 如果是数字值,只是简单的传入和返回。
 如果是 null 值,返回 0。
 如果是 undefined,返回 NaN。

数值转换

有 3 个函数可以把非数值转换为数值:Number()、parseInt()和 parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这3个函数对于同样的输入会有返回不同的结果。Number()函数的转换规则如下。
 如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
 如果是数字值,只是简单的传入和返回。
 如果是 null 值,返回 0。
 如果是 undefined,返回 NaN。
 如果是字符串,遵循下列规则:

 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即”1”会变成1,”123”会变成123,而”011”会变成11(注意:前导的零被忽略了);
 如果字符串中包含有效的浮点格式,如”1.1”,则将其转换为对应的浮点数值 同样,也会忽略前导零);
 如果字符串中包含有效的十六进制格式,例如”0xf”,则将其转换为相同大小的 十进制整数值;
 如果字符串是空的(不包含任何字符),则将其转换为 0;
 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
 如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。根据这么多的规则使用Number()把各种数据类型转换为数值确实有点复杂。下面还是给出几个具体的例子吧。
var num1 = Number(“Hello world!”); //NaN
var num2 = Number(“”); //0
var num3 = Number(“000011”); //11

parseInt

1
2
3
4
var num1 = parseInt("10", 2); //2 (按二进制解析)
var num2 = parseInt("10", 8); //8 (按八进制解析)
var num3 = parseInt("10", 10); //10 (按十进制解析)
var num4 = parseInt("10", 16); //16 (按十六进制解析

parseFloat

1
2
3
4
5
6
var num1 = parseFloat("1234blue"); //1234 (整数)
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.125e7"); //31250000

字符String

1
2
3
4
5
6
7
8
9
10
\n 换行
\t 制表
\b 空格
\r 回车
\f 进纸
\\ 斜杠
\' 单引号('),在用单引号表示的字符串中使用。例如:'He said, \'hey.\''
\" 双引号("),在用双引号表示的字符串中使用。例如:"He said, \"hey.\""
\xnn 以十六进制代码nn表示的一个字符(其中n为0~F)。例如,\x41表示"A"
\unnnn 以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)。例如,\u03a3表示希腊字符Σ

求模运算

求模(余数)操作符由一个百分号(%)表示,用法如下:
var result = 26 % 5; // 等于 1
与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
 如果操作数都是数值,执行常规的除法计算,返回除得的余数;
 如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
 如果被除数是有限大的数值而除数是零,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
 如果被除数是零,则结果是零;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

减法

1
2
3
4
5
6
var result1 = 5 - true; // 4,因为 true 被转换成了 1
var result2 = NaN - 1; // NaN
var result3 = 5 - 3; // 2
var result4 = 5 - ""; // 5,因为"" 被转换成了 0
var result5 = 5 - "2"; // 3,因为"2"被转换成了 2
var result6 = 5 - null; // 5,因为 null 被转换成了 0

全等和不全等

记住:null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值

每个主要算术操作符(以及个别的其他操作符)都有对应的复合赋值操作符。这些操作符如下所示:

1
2
3
4
5
6
7
 乘/赋值(*=);
 除/赋值(/=);
 模/赋值(%=);
 加/赋值(+=);
 减/赋值(=);
 左移/赋值(<<=);
 有符号右移/赋值(>>=);

for-in语句

1
2
3
4
5
6
for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。以下是 for-in 语句的语法:
for (property in expression) statement
下面是一个示例:
for (var propName in window) {
document.write(propName);
}

ECMAScript 对象的属性没有顺序。因此,通过 for-in 循环输出的属性名的顺序是不可预测的。
具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。

js没有重载

ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。

基本类型和引用类型的值

ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。第 3 章讨论了 5 种基本数据类型:Undefined、Null、Boolean、Number 和 String。这 5 种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的①。

在 Web 浏览器中,全局执行环境被认为是 window 对象

数组的栈方法

1
2
3
4
5
6
7
8
var colors = new Array(); // 创建一个数组
var count = colors.push("red", "green"); // 推入两项
alert(count); //2
count = colors.push("black"); // 推入另一项
alert(count); //3
var item = colors.pop(); // 取得最后一项
alert(item); //"black"
alert(colors.length); //2

数组的重排序方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
数组中已经存在两个可以直接用来重排序的方法:reverse()和 sort()。有读者可能猜到了,
reverse()方法会反转数组项的顺序。请看下面这个例子。
var values = [1, 2, 3, 4, 5];
values.reverse();
alert(values); //5,4,3,2,1


//自定义排序
function compare(value1, value2) {
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values); // 15,10,5,1,0

数组的splice

1
2
3
4
5
6
7
8
9
10
var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
alert(colors); // green,yellow,orange,blue
alert(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
alert(colors); // green,red,purple,orange,blue
alert(removed); // yellow,返回的数组中只包含一项

数组迭代方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。
 filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
 forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
 map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
 some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。

var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){
return (item > 2);
});
alert(everyResult); //false
var someResult = numbers.some(function(item, index, array){
return (item > 2);
});
alert(someResult); //true

数组的归并方法

这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值。传给reduce()和 reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。

1
2
3
4
5
6
使用 reduce()方法可以执行求数组中所有值之和的操作,比如:
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15

js没有重载(深入理解)

将函数名想象为指针,也有助于理解为什么 ECMAScript 中没有函数重载的概念。以下是曾在第 3
章使用过的例子。

函数声明与函数表达式

本节到目前为止,我们一直没有对函数声明和函数表达式加以区别。而实际上,解析器在向执行环
境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行
任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真
正被解释执行。

1
2
3
4
5
6
7
8
9
10
alert(sum(10,10));
function sum(num1, num2){
return num1 + num2;
}

下面这个报错
alert(sum(10,10));
var sum = function(num1, num2){
return num1 + num2;
};

作为值的函数

1
2
3
4
5
6
7
8
9
10
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
这个函数接受两个参数。第一个参数应该是一个函数,第二个参数应该是要传递给该函数的一个值。
然后,就可以像下面的例子一样传递函数了。
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10);
alert(result1); //20

递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}

为了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee。
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1)
}
}

函数的apply和bind

每个函数都包含两个非继承而来的方法:apply()和 call()。这两个方法的用途都是在特定的作
用域中调用函数,实际上等于设置函数体内 this 对象的值。首先,apply()方法接收两个参数:一个
是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是
arguments 对象。例如:

1
2
3
4
5
6
7
8
9
10
11
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, arguments); // 传入 arguments 对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // 传入数组
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20

call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call()
方法而言,第一个参数是 this 值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用
call()方法时,传递给函数的参数必须逐个列举出来,如下面的例子所示。

1
2
3
4
5
6
7
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2);
}
alert(callSum(10,10)); //20

能够扩充函数赖以运行的作用域

1
2
3
4
5
6
7
8
9
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue

ECMAScript 5 还定义了一个方法:bind()。这个方法会创建一个函数的实例,其 this 值会被绑
定到传给 bind()函数的值。例如:

1
2
3
4
5
6
7
8
9
10
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue

在这里,sayColor()调用 bind()并传入对象 o,创建了 objectSayColor()函数。objectSayColor()函数的
this 值等于 o,因此即使是在全局作用域中调用这个函数,也会看到"blue"。

基本包装类型

ECMAScript 还提供了 3 个特殊的引用类型:Boolean、Number 和String。
Object 构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。例如:
var obj = new Object(“some text”);
alert(obj instanceof String); //true

Number 类型还提供了一些用于将数值格式化为字符串的方法。
其中,toFixed()方法会按照指定的小数位返回数值的字符串表示,例如:
var num = 10;
alert(num.toFixed(2)); //“10.00”
toFixed()方法可以表示带有 0 到 20 个小数位的数值。但这只是标准实现的范
围,有些浏览器也可能支持更多位数

var num = 10;
alert(num.toExponential(1)); //“1.0e+1”
以上代码输出了”1.0e+1”;不过,这么小的数值一般不必使用 e 表示法。如果你想得到表示某个
数值的最合适的格式,就应该使用 toPrecision()方法。
var num = 99;
alert(num.toPrecision(1)); //“1e+2”
alert(num.toPrecision(2)); //“99”
alert(num.toPrecision(3)); //“99.0”

string截取

1
2
3
4
5
6
7
var stringValue = "hello world";
alert(stringValue.slice(3)); //"lo world"
alert(stringValue.substring(3)); //"lo world"
alert(stringValue.substr(3)); //"lo world"
alert(stringValue.slice(3, 7)); //"lo w"
alert(stringValue.substring(3,7)); //"lo w"
alert(stringValue.substr(3, 7)); //"lo worl"

在传递给这些方法的参数是负值的情况下,它们的行为就不尽相同了。其中,slice()方法会将传入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0。最后,substring()方法会把所有负值参数都转换为 0。下

1
2
3
4
5
6
7
var stringValue = "hello world";
alert(stringValue.slice(-3)); //"rld"
alert(stringValue.substring(-3)); //"hello world"
alert(stringValue.substr(-3)); //"rld"
alert(stringValue.slice(3, -4)); //"lo w"
alert(stringValue.substring(3, -4)); //"hel"
alert(stringValue.substr(3, -4)); //""(空字符串)

字符串位置方法
var stringValue = “hello world”;
alert(stringValue.indexOf(“o”, 6)); //7
alert(stringValue.lastIndexOf(“o”, 6)); //4

Global对象

诸如 isNaN()、isFinite()、parseInt()以及 parseFloat(),实际上全都是 Global对象的方法。除此之外,Global 对象还包含其他一些方法。
Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource
Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如
空格。而这两个 URI 编码方法就可以对 URI 进行编码,它们用特殊的 UTF-8 编码替换所有无效的字符,
从而让浏览器能够接受和理解。

encodeURI()主要用于整个URI(例如,http://www.wrox.com/illegalvalue.htm),而encodeURIComponent()主要用于对URI 中的某一段(例如前面URI中的illegal value.htm)进行编码。它们的主要区别在于,encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。

1
2
3
4
5
6
7
8
9
10
var uri = "http://www.wrox.com/illegal value.htm#start";
//"http://www.wrox.com/illegal%20value.htm#start"
alert(encodeURI(uri));
//"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
alert(encodeURIComponent(uri));

使用 encodeURI()编码后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了
%20。而 encodeURIComponent()方法则会使用对应的编码替换所有非字母数字字符。这也正是可以
对整个 URI 使用 encodeURI(),而只能对附加在现有 URI 后面的字符串使用 encodeURIComponent()
的原因所在。

与 encodeURI()和 encodeURIComponent()方法对应的两个方法分别是 decodeURI()和
decodeURIComponent()。

eval()方法

在 eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字
符串中;它们只在 eval()执行的时候创建

window 对象

另一种取得 Global 对象的方法是使用以下代码:
var global = function(){
return this;
}();

Math对象

1
2
3
要找到数组中的最大或最小值,可以像下面这样使用 apply()方法。
var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);

Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课
上学到的舍入规则)

1
2
3
4
5
6
7
8
9
10
11
function selectFrom(lowerValue, upperValue) {
var choices = upperValue - lowerValue + 1;
return Math.floor(Math.random() * choices + lowerValue);
}
var num = selectFrom(2, 10);
alert(num); // 介于 2 和 10 之间(包括 2 和 10)的一个数值

//通过调用 selectFrom(2,10)就可以得到一个介于 2 和 10 之间(包括 2 和 10)的数值了。利用这个函数,可以方便地从数组中随机取出一项
var colors = ["red", "green", "blue", "yellow", "black", "purple", "brown"];
var color = colors[selectFrom(0, colors.length-1)];
alert(color); // 可能是数组中包含的任何一个字符串

js引用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
对象在 JavaScript 中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,
现简要总结如下:
 引用类型与传统面向对象程序设计中的类相似,但实现不同;
 Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为;
 Array 类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;
 Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
 RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表
达式功能。
函数实际上是 Function 类型的实例,因此函数也是对象;而这一点正是 JavaScript 最有特色的地
方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。
因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当作对象来访问。三种基本包装类
型分别是:Boolean、Number 和 String。以下是它们共同的特征:
 每个包装类型都映射到同名的基本类型;
 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据
操作;
 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。
在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和 Math。在大多数 ECMAScript
实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变
量和函数都是 Global 对象的属性。Math 对象提供了很多属性和方法,用于辅助完成复杂的数学计算
任务。