JavaScript 高程三读书笔记;
1、
在使用 <script> 嵌入 JavaScript 代码时,记住不要在代码中的任何地方出现 "</script>" 字符串。 例如,浏览器在加载下面所示的代码时就会产生一个错误: <script type="text/javascript"> function sayScript(){ alert("</script>"); } </script>
2、
JavaScript 是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
ECMAScript,由 ECMA-262 定义,提供核心语言功能; 文档对象模型(DOM),提供访问和操作网页内容的方法和接口; 浏览器对象模型(BOM),提供与浏览器交互的方法和接口。 JavaScript 的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari 和 Opera)中 都得到了不同程度的支持。
3、
通过 <script> 元素的 src 属性还可以包含来自外部域的 JavaScript 文件。这一点既让 <script> 元素倍显强大,又让它备受争议。在这一点上, <script> 与 <img> 元素非常相似,即它的 src 属性可以是指向当前 HTML 页面所在域之外的某个域中的完整 URL,例如: <script type="text/javascript" src="http://www.somewhere.com/afile.js"></script> 这样,位于外部域中的代码也会被加载和解析,就像这些代码位于加载它们的页面中一样。利用这 一点就可以在必要时通过不同的域来提供 JavaScript 文件。不过,在访问自己不能控制的服务器上的 JavaScript 文件时则要多加小心。如果不幸遇到了怀有恶意的程序员,那他们随时都可能替换该文件中 的代码。因此,如果想包含来自不同域的代码,则要么你是那个域的所有者,要么那个域的所有者值得 信赖。 无论如何包含代码,只要不存在 defer 和 async 属性,浏览器都会按照 <script> 元素在页面中 出现的先后顺序对它们依次进行解析。换句话说,在第一个 <script> 元素包含的代码解析完成后,第 二个 <script> 包含的代码才会被解析,然后才是第三个、第四个……
4、 标签的位置
按照传统的做法,所有 <script> 元素都应该放在页面的 <head> 元素中,例如: <!DOCTYPE html> <html> <head> <title>Example HTML Page</title> <script type="text/javascript" src="example1.js"></script> <script type="text/javascript" src="example2.js"></script> </head> <body> <!-- 这里放内容 --> </body> </html> 这种做法的目的就是把所有外部文件(包括 CSS 文件和 JavaScript 文件)的引用都放在相同的地方。 可是,在文档的 <head> 元素中包含所有 JavaScript 文件,意味着必须等到全部 JavaScript 代码都被下载、 解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到 <body> 标签时才开始呈现内容)。对于 那些需要很多 JavaScript 代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,而延迟 期间的浏览器窗口中将是一片空白。
5、为了避免这个问题,现代 Web 应用程序一般都把全部 JavaScript 引用放在 <body> 元素中页面内容的后面;
!DOCTYPE html> <html> <head> <title>Example HTML Page</title> <script type="text/javascript" defer="defer" src="example1.js"></script> <script type="text/javascript" defer="defer" src="example2.js"></script> </head> <body> <!-- 这里放内容 --> </body> </html>
6、ECMAScript 的语法大量借鉴了 C 及其他类 C 语言(如 Java 和 Perl)的语法。因此,熟悉这些语言
的开发人员在接受 ECMAScript 更加宽松的语法时,一定会有一种轻松自在的感觉。
1.1 区分大小写 要理解的第一个概念就是 ECMAScript 中的一切(变量、函数名和操作符)都区分大小写。这也就 意味着,变量名 test 和变量名 Test 分别表示两个不同的变量,而函数名不能使用 typeof ,因为它 是一个关键字(3.2 节介绍关键字),但 typeOf 则完全可以是一个有效的函数名。
1.2 标识符
所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则
组合起来的一或多个字符:
1.2.1第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ );
1.2.2其他字符可以是字母、下划线、美元符号或数字。
标识符中的字母也可以包含扩展的 ASCII或 Unicode字母字符(如 À和 Æ),但我们不推荐这样做。
按照惯例,ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的
首字母大写
不能把关键字、保留字、 true 、 false 和 null 用作标识符。3.2节将介绍更多相
关内容。
7、
数据类型 ECMAScript 中有 5 种简单数据类型(也称为基本数据类型): Undefined 、 Null 、 Boolean 、 Number 和 String 。还有 1种复杂数据类型—— Object
typeof 操作符
鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型—— typeof 就
是负责提供这方面信息的操作符。对一个值使用 typeof 操作符可能返回下列某个字符串:
"undefined" ——如果这个值未定义;
"boolean" ——如果这个值是布尔值;
"string" ——如果这个值是字符串;
有些时候, typeof 操作符会返回一些令人迷惑但技术上却正确的值。比如,调用 typeof null 会返回 "object" ,因为特殊值 null 被认为是一个空的对象引用。Safari 5 及之前版本、Chrome 7 及之 前版本在对正则表达式调用 typeof 操作符时会返回 "function" ,而其他浏览器在这种情况下会返回 "object" 。
Null 类型 Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null 。从逻辑角度来看, null 值表 示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回 "object" 的原因,如下面 的例子所示: var car = null; alert(typeof car); // "object"
如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null 而不是其他值。这样 一来,只要直接检查 null 值就可以知道相应的变量是否已经保存了一个对象的引用,如下面的例子 所示: if (car != null){ // 对 car 对象执行某些操作 } 实际上, undefined 值是派生自 null 值的,因此 ECMA-262规定对它们的相等性测试要返回 true : alert(null == undefined); //true
这些转换规则对理解流控制语句(如 if 语句)自动执行相应的 Boolean 转换非常重要,请看下面 的代码: var message = "Hello world!"; if (message){ alert("Value is true"); } BooleanExample02.htm 运行这个示例,就会显示一个警告框,因为字符串 message 被自动转换成了对应的 Boolean 值 ( true )。由于存在这种自动执行的 Boolean 转换,因此确切地知道在流控制语句中使用的是什么变量 至关重要。错误地使用一个对象而不是一个 Boolean 值,就有可能彻底改变应用程序的流程
对于那些极大或极小的数值,可以用 e 表示法(即科学计数法)表示的浮点数值表示。用 e 表示法 表示的数值等于 e 前面的数值乘以 10 的指数次幂。ECMAScript 中 e 表示法的格式也是如此,即前面是 一个数值(可以是整数也可以是浮点数),中间是一个大写或小写的字母 E,后面是 10 的幂中的指数, 该幂值将用来与前面的数相乘。下面是一个使用 e 表示法表示数值的例子: var floatNum = 3.125e7; // 等于 31250000 在这个例子中,使用 e 表示法表示的变量 floatNum 的形式虽然简洁,但它的实际值则是 31250000。 在此,e 表示法的实际含义就是“3.125 乘以 10 7 ”。 也可以使用 e 表示法表示极小的数值,如 0.00000000000000003,这个数值可以使用更简洁的 3e17 表示。在默认情况下,ECMASctipt 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法 表示的数值(例如,0.0000003 会被转换成 3e7)。 浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1 加 0.2 的结果不是 0.3,而是 0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值。 例如: if (a + b == 0.3){ // 不要做这样的测试! alert("You got 0.3."); }
2. 数值范围 由于内存的限制,ECMAScript 并不能保存世界上所有的数值。ECMAScript 能够表示的最小数值保 存在 Number.MIN_VALUE 中——在大多数浏览器中,这个值是 5e-324;能够表示的最大数值保存在 Number.MAX_VALUE 中——在大多数浏览器中,这个值是 1.7976931348623157e+308。如果某次计算的 结果得到了一个超出 JavaScript 数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值。具 体来说,如果这个数值是负数,则会被转换成 -Infinity (负无穷),如果这个数值是正数,则会被转 换成 Infinity (正无穷)
访问 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以 得到负和正 Infinity 的值。可以想见,这两个属性中分别保存着 -Infinity 和 Infinity 。
3. NaN NaN ,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数 未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以 0都会导致错误, 从而停止代码执行。但在 ECMAScript中,任何数值除以 0会返回 NaN ① ,因此不会影响其他代码的执行。 NaN 本身有两个非同寻常的特点。首先,任何涉及 NaN 的操作(例如 NaN /10)都会返回 NaN ,这 个特点在多步计算中有可能导致问题。其次, NaN 与任何值都不相等,包括 NaN 本身。例如,下面的代 码会返回 false : alert(NaN == NaN); //false 针对 NaN 的这两个特点,ECMAScript 定义了 isNaN() 函数。这个函数接受一个参数,该参数可以 是任何类型,而函数会帮我们确定这个参数是否“不是数值”。 isNaN() 在接收到一个值之后,会尝试 将这个值转换为数值。某些不是数值的值会直接转换为数值,例如字符串 "10" 或 Boolean 值。而任何 不能被转换为数值的值都会导致这个函数返回 true 。请看下面的例子: alert(isNaN(NaN)); //true alert(isNaN(10)); //false(10 是一个数值) alert(isNaN("10")); //false(可以被转换成数值 10) alert(isNaN("blue")); //true(不能转换成数值) alert(isNaN(true)); //false(可以被转换成数值 1)
尽管有点儿不可思议,但 isNaN() 确实也适用于对象。在基于对象调用 isNaN()
函数时,会首先调用对象的 valueOf() 方法,然后确定该方法返回的值是否可以转
换为数值。如果不能,则基于这个返回值再调用 toString() 方法,再测试返回值。
而这个过程也是 ECMAScript中内置函数和操作符的一般执行流程,更详细的内容请
4. 数值转换
有 3 个函数可以把非数值转换为数值: Number() 、 parseInt() 和 parseFloat()
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 var num4 = Number(true); //1
由于 Number() 函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是 parseInt() 函数。 parseInt() 函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字 符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号, parseInt() 就会返回 NaN ;也就是说,用 parseInt() 转换空字符串会返回 NaN ( Number() 对空字符返回 0)。如 果第一个字符是数字字符, parseInt() 会继续解析第二个字符,直到解析完所有后续字符或者遇到了 一个非数字字符。例如, "1234blue" 会被转换为 1234,因为 "blue" 会被完全忽略。类似地, "22.5" 会被转换为 22,因为小数点并不是有效的数字字符。 如果字符串中的第一个字符是数字字符, parseInt() 也能够识别出各种整数格式(即前面讨论的 十进制、八进制和十六进制数)。也就是说,如果字符串以 "0x" 开头且后跟数字字符,就会将其当作一 个十六进制整数;如果字符串以 "0" 开头且后跟数字字符,则会将其当作一个八进制数来解析。 为了更好地理解 parseInt() 函数的转换规则,下面给出一些例子: var num1 = parseInt("1234blue"); // 1234 var num2 = parseInt(""); // NaN var num3 = parseInt("0xA"); // 10(十六进制数) var num4 = parseInt(22.5); // 22 var num5 = parseInt("070"); // 56(八进制数) var num6 = parseInt("70"); // 70(十进制数) var num7 = parseInt("0xf"); // 15(十六进制数)