JavaScript 学习笔记一 (入门篇)
最近正在看《JavaScript高级程序设计》,一直没来得及总结一下,顺便对之前看的《JavaScript DOM编程艺术》进行一些简单的总结,如有一些不正确的地方还请多指出讨论。
第1章 基本概念
1.1 区分大小写
在学习 JavaScript 之前要理解的第一个概念就是在 ECMAScript 中所有的一切(变量、函数名和操作符)都是区分大小写的。比如变量 test 和 Test 是两个不同的变量,typeof 不能用在函数名上,因为它是一个关键字,但 typeOf 完全可以是一个函数名,因为在 ECMAScript 中变量、函数名和操作符等等都是区分大小写的。
1.2 标识符
在学习之前还需要了解的第二个概念就是「标识符」,所谓标识符就是指变量、函数、函数的参数和属性的名字,标识符可以下列格式规则组合起来的一个或多个字符:
- 第一个字符必须是是字母、下划线(_)或者美元符号($)。
- 其他字符可以是字母、下划线、美元符号或者数字。
按照惯例,ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的首字母大写,例如:
- firstSecond
- myCar
- doSomethingImportant
第2章 数据类型
ECMAScript 中有 5 种基本数据类型:Undefined、 Null、 Boolean、 String 和 Number。还有 1 种复杂数据类型:Obect,Object 本质上是由一组无序的名值对组成。ECMAScript 不支持任何创建自定义类型的机制,而所有值最终都将是上述 6 种数据类型之一。
2.1 typeof 操作符
由于 ECMAScript 是松散类型的,所以需要有一种方法来检测给定变量的数据类型,typeof 就是负责提供这方面信息的操作符。对一个值使用 typeof 操作符可能返回下列某个字符串:
- "undefined",如果这个值未定义;
- "boolean",如果这个值是布尔值;
- "string",如果这个值是字符串;
- "number",如果这个值是数值;
- "object",如果这个值是对象或 null;
- "function",如果这个值是函数。
例如:
var message = "Some Message!"
alert(typeof message); // "string"
alert(typeof(message)); // "string"
alert(typeof 95); // "number"
由此可以看出 typeof 操作符的操作数可以是变量(message),也可以是数值字面量。注意,typeof 是一个操作符而不是函数,所以例子中的圆括号尽管可以使用,但不是必需的。
这里需要注意一下的是,如果对 null 进行 typeof 操作的话,会返回 "object",因为 null 会被认为是一个空的对象引用。还有一些比较奇怪的返回值,比如 Safari 5 及之前的版本、 Chrome 7 及之前的版本在对正则表达式调用 typeof 操作符时会返回 "function",而在其他浏览器下则会返回 "object"。
2.2 Undefined 类型
Undefined 类型的值只有一个,即特殊的 undefined。当用 var 关键字声明一个变量但未对它进行初始化时,这个变量的值就是 undefined,例如:
var message;
alert(message == undefined); // true
这个例子只对 message 进行了声明,但未对其进行赋值操作,此时 message 的值就是 undefined,这个例子和下面这个例子是等价的:
var message = undefined;
alert(message == undefined); // true
这个例子使用 undefined 值显式初始化了变量 message。但我们没有必要这么做,因为未经初始化的值默认就会取得 undefined 值。
对于 Undefined 类型还有一点需要注意的就是,声明了变量但是未对其进行初始化赋值操作和根本就没有声明变量是不同的:
var message; // 声明变量后默认取得 undefined
// 下面这个变量根本没有声明
// var age;
alert(message); // undefined
alert(age);// Uncaught ReferenceError: age is not defined
对于第一个警告框大家肯定没疑问,弹出的应该是 "undefined",由于传递给第二个警告框的是一个未申明的变量,所以在这里会导致一个错误。
对于尚未申明的变量,只能对其进行一项操作,即使用 typeof 对其进行数据类型的判断。不过有一点比较奇怪的就是,对未进行初始化赋值操作的变量和未申明的变量使用 typeof 操作符,都会返回 "undefined":
var message; // 声明变量后默认取得 undefined
// 下面这个变量根本没有声明
// var age;
alert(typeof message); // "undefined"
alert(typeof age); // "undefined"
结果表明对未进行初始化赋值操作的变量和未申明的变量使用 typeof 操作符,都会返回 "undefined"。
2.3 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
这里有一点也要注意的是,这里的相等操作符(==)出于比较的目的,会对比较的两个类型进行类型转换(后面会对这个知识点进行一些详细的总结)。
尽管 undefined 派生自 null,但它们的用途却不相同,无论在什么情况下都没有必要对一个变量的值显示的赋值为 undefined,而同样的道理对 null 却不适用,换句话说,只要意在保存对象的变量还没有真正的保存对象,就应该明确地地让该变量保存 null 值。这样做不仅可以体现 null 作为空对象指针的惯例,也有助于进一步的区分 undefined 和 null。
2.4 Boolean 类型
Boolean 类型的值有两个,分别是 true 和 false,这两个值和数字值不是一回事,也就是说 true 不一定等于 1,false 不一定等于 0,还有一点值得注意的是文章一开始就强调的一个概念,在 ECMAScript 中所有的一切都是区分大小写的,所以 True 和 False (以及其他混合大小写的形式)并不是 Boolean 类型的两个值,只是标识符。以下是为变量赋 Boolean 类型值的例子:
var found = true;
var lost = false;
尽管 Boolean 类型的值只有两个,但是在 ECMAScript 中,所有类型的值都有与这两个 Boolean 值等价的值,将任意一种类型的值转换为对应的 Boolean 值,可以调用转型函数 Boolean(),例如:
var message = "Hello World!";
var messageAsBoolean = Boolean(message);
上面这个例子中,message 字符串被转换成了 Boolean 值,转换后的 Boolean 值被储存在变量 messageAsBoolean 中。可以对任何数据类型的值调用 Boolean() 函数,而且总会返回一个 Boolean 值。至于具体返回是 true 还是 false 则要要具体的情况而定,下面给出了转换的规则:
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | ture | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN(参见本章后面有关NaN的内容) |
Object | 任何对象 | null |
Undefined | n/a① | undefined |
2.5 Number 类型
Number 类型应该算是几种基本数据类型中比较复杂的类型吧。
在 Number 类型中,最简单的应该算是十进制整数吧,十进制整数可以直接像下面这样在代码中输入:
var intNum = 9; // 整数 9
除了十进制以外,整数还可以用二进制、八进制和十六进制来表示。
其中八进制必须以 0 开头,然后是八进制数字序列(0-7),如果字面中的值超出了范围,则第一个 0 将被忽略,后面的数值将被当成十进制数值解析。
var num1 = 070; // 八进制 56
var num2 = 079 // 无效的八进制数,被解析成十进制数 79
var num3 = 08; // 无效的八进制数,被解析成十进制数 8
八进制字面量在严格模式下是无效的,会导致支持的 JavaScript 引擎抛出错误。
十六进制必须以 0x 开头,然后是十六进制数字序列(0-9 及 A-F),其中字母可以大写也可以小写,例如:
var num1 = 0xA; // 十六进制的 10
var num2 = 0x1f; // 十六进制的 31
在进行算数计算时,所有的八进制和十六进制表示的数值最终都将被转换成十进制数值。
2.5.1 浮点数值
浮点数值必须包含一个小数点,且小数点后面必须要有一位**非 0 **数字才算是浮点数值,如果小数点后没有数字,则 ECMAScript 会自动忽略这个小数点,小数点前面则不一定要有数字,但不推荐这种写法:
var num1 = 1.1;
var num2 = 0.1;
var num3 = .1; // 有效但不推荐
var num4 = 1.; // 小数点后面没有数字,被解析为 1
var num5 = 1.0; // 被解析成整数 1
由于浮点数值所需的内存是整数数值所需要的内存的两倍,所以 ECMAScript 会不失时机的将浮点数值转化为整数。
还有一点需要注意的是,浮点数值的最高精度是 17 位小数,在进行算术计算的时候其精度远远不如整数数值。比如,0.1 加上 0.2 的结果并不是 0.3,而是 0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值,例如:
var a = 0.1;
var b = 0.2;
if (a + b = 0.3) { // 不要这么测试
alert("You got 0.3.");
}
2.5.2 数值范围
由于内存的限制,ECMAScript 并不能保存所有的数值,ECMAScript 能够表示的最小数值保存在 Number.MIN_VALUE 中,能够表示的最大数值保存在 Number.MAX_VALUE 中,具体的来说,如果一个数值超出了 ECMAScript 所能保存的数值范围,并且如果这个值是负数,则会被转换成 -Infinity(负无穷),如果这个值是正数,则会被转换成 +Infinity(正无穷)。
如果一个数被转换成了无穷大(Infinity),则不能进行下一次运算,因为 Infinity 是不能被运算的数值。要想确定一个数值是不是有穷的(是不是最大值和最小值之间),可以使用 isFinite() 函数来确定,如果处于最大值和最小值之间,则会返回 true,例如:
var result = Number.MAX_VALUE + Number.MAX_VALUE;
var min = Number.MIN_VALUE;
var max = Number.MAX_VALUE;
alert(isFinite(result)); // false
alert(isFinite(min)); // true
alert(isFinite(max)); // true
由上可知,最大值和最小值也算是有穷的。
2.5.3 NaN
NaN 即非数值(Not a Number)是一个特殊的数值,NaN 是用来表示本来应该返回一个数值却没有返回数值的情况(这样就不会抛出异常了),例如在 ECMAScript 中,0 除以 0 并不会报错,而是会返回 NaN,因此不会影响其他代码的执行。在这里有一点需要注意的是,并不是任意数值除以 0 都会返回 NaN 的,例如:
alert(0 / 0); // "NaN"
alert(1 / 0); // "Infinity"
alert(-1 / 0); // "-Infinity"
alert(NaN / NaN); //"NaN"
由上可知,当正数除以 0 的时候,返回的是 Infinity,当负数除以 0 的时候,返回的是 -Infinity,只有 NaN 或者 0 初除以 0 的时候返回的才是 NaN。
NaN 有两个特点,首先,任何涉及 NaN 的操作都会返回 NaN;其次,NaN 与任何值都不相等,包括 NaN 本身。例如下面代码会返回 false:
alert(NaN = NaN); // false
为了判断某个数值是否是「非数值」,ECMAScript 定义了 isNaN() 函数,该函数接受一个任意类型的参数,如果这个参数是 NaN,则返回 true,如果不是 NaN,则返回 false,例如:
alert(isNaN(NaN)); // true
alert(isNaN(10)); // false(10 是一个数值)
alert(isNaN("10")); // false(可以被转换成数值 10)
alert(isNaN("blue")); // true(不能转换成数值)
alert(isNaN(true)); // false(可以被转换成数值 1)
由上可知,如果一个参数不能被转换成数值,则 isNaN() 函数会返回 true。
值得一提的是,isNaN() 函数同样适用于对象,在对对象调用 isNaN() 时,会首先调用对象的 valueOf() 方法试图把对象转换为数值,如果不能转换为数值,则基于这个对象再调用 toString() 方法,在测试返回的值。
2.5.4 数值转换
可以把非数值转换成数值的函数有 3 个,分别是 Number()、 parseInt() 和 parseFloat()。其中 Number() 适用于任何数据类型,另外两个则专门用于把字符串转换成数值。
Number() 函数的转换规则如下:
如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
-
如果是字符串,遵循下列规则:
如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1"会变成 1,"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了);
如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽略前导零);
如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
如果字符串是空的(不包含任何字符),则将其转换为 0;
如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString() 方法,然后再次依照前面的规则转换返回的字符串值。
下面则是一些具体的例子:
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(十六进制数)
var num4 = parseInt(22.5); // 22
var num5 = parseInt("070"); // 56(八进制数)
var num6 = parseInt("70"); // 70(十进制数)
var num7 = parseInt("0xf"); // 15(十六进制数)
parseInt() 在转换字符串的时候会忽略字符串前面的空格,直到找到第一个非空格字符,如果第一个字符不是数字字符或者负号,parseInt() 就会返回 NaN;如果第一个字符是数字字符,parseInt() 会继续解析第二个字符,知道解析完所有后足字符或遇到了一个非数字字符。有一点应该注意的是 parseInt() 转换空字符串时会返回一个 NaN,而 Number() 转换一个空字符串则会返回数字 0。
parseInt() 默认解析的是十进制数,但也可以解析指定的进制,例如:
var num1 = parseInt("10", 2); //2 (按二进制解析)
var num2 = parseInt("10", 8); //8 (按八进制解析)
var num3 = parseInt("10", 10); //10 (按十进制解析)
var num4 = parseInt("10", 16); //16 (按十六进制解析)
parseInt() 可以接受第二个参数,第二个参数只能是 2、 8、 10 和 16,分别对应相应的进制。为了避免错误,当我们用 parseInt() 转换数值时指定相应的进制是非常有必要的。
parseFloat() 的转换规则如下:
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
与 parseInt() 类似,parseFloat() 也是从第一个字符开始解析每个字符,一直解析到字符串的末尾,或者解析到一个无效浮点数字字符为止。与 parseInt() 不同的是,parseFloat() 解析到的第一个小数点是有效的,而第二个小数点则无效,因此它后面的字符串也将被忽略。与 parseInt() 第二个不同的是 parseFloat() 会始终忽略第一个 0。
还有一点需要注意的是,如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后都是零),parseFloat() 会返回整数:
var num1 = parseFloat("1234blue"); //1234 (整数)
var num2 = parseFloat("1234.000"); //1234 (整数)
parseFloat() 只解析十进制数,所以它不接受第二个参数,这也是为什么 parseFloat() 始终会把十六进制的数值转换成 0 的原因:
var num2 = parseFloat("0xA"); // 0
2.6 String 类型
String 类型表示字符串,可以由双引号("")或单引号('')表示,所以下面这两种字符串都是有效的:
var firstName = "Clear";
var lastName = 'Design';
但有一点需要注意的是,以什么引号开头就必须以什么引号结尾,比如下面这种写法就是错误的:
var name = "Clear Design';
2.6.1 字符字面量
String 数据类型包含一些特殊的字符字面量,也叫转义序列,如下:
字面量 | 含义 |
---|---|
\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表示希腊字符Σ |
2.6.2 字符串的特点
ECMAScript 中的字符串是不可变的,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量,例如:
var lang = "Java";
lang = lang + "Script";
上面的 lang 开始时包含 "Java",而第二行代码把 lang 重新定义为 "Java" 和 "Script" 的组合,即 "JavaScript"。第二行代码并不是把原来的 lang 的值改变了,而是首先创建一个能容纳 10 个字符的新字符串,然后在这个字符串中填充 "Java" 和 "Script",由于新的字符串拼接完成后,原来的字符串已经没有用了,所以原来的字符串 "Java" 和 "Script" 会被销毁,这些都是发生在后台的。
2.6.3 转换为字符串
前面提到 Number 数据类型的时候有提到 parseInt() 和 parseFloat() 两个函数,这两个函数的作用是将可转换成数值的字符串转换成数值,而 String 数据类型同样也提供了一个 toString() 函数,它的作用是把可转换为字符串的数据类型转换成字符串:
var age = 22;
var ageAsString = age.toString(); // "22"
var found = true;
var foundAsString = found.toString(); // "true"
Number、 Boolean、 Object 和 String(没错,String 本身也具有 toString() 方法,该方法返回该字符串的一个副本)都有 toString() 方法,但 Null 和 Undefined 没有这个方法。
toString() 方法接受一个参数,参数只能是 2、 8、 10 和 16,分别对应相应的进制。例如:
var num = 10;
alert(num.toString()); // "10"
alert(num.toString(2)); // "1010"
alert(num.toString(8)); // "12"
alert(num.toString(10)); // "10"
alert(num.toString(16)); // "a"
默认情况(没有传入参数)下 toString() 方法以十进制格式返回数值的字符串表示。在不知道传入的值是不是 Null 或 Undefined 的时候,可以使用 String() 转型函数,该函数支持把任意数据类型的值转换为字符串,String() 函数的转换规则如下:
- 如果值有 toString() 方法,则调用该方法(没有参数)并返回相应的结果;
- 如果值是 null,则返回 "null";
- 如果值是 undefined,则返回 "undefined"。
下面再看几个例子:
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"
2.7 Object 类型
Object 类型是 ECMAScript 中 6 种数据类型中唯一一种复杂数据类型,简单的说的话 ECMAScript 中对象就是一组数据和功能的集合。创建对象的方法有很多,这里说一下比较常用的一种方法,就是通过执行 new 操作符后跟要创建的对象类型的名称来创建:
var o = new Object();
在了解对象之前,首先要先理解一个重要的思想:在 ECMAScript 中,Object 类型是所有它的实例的基础。也就是说,Object 类型所具有的任何属性和方法也同样存在于更具体的对象中。
Object 的每个实例都具有下列属性和方法:
constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就是 Object()。
hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:o.hasOwnProperty("name"))。
isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原型)。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句
(本章后面将会讨论)来枚举。与 hasOwnProperty() 方法一样,作为参数的属性名必须以字符串形式指定。toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString() 方法的返回值相同。
在 ECMAScript 中,Object 是所有对象的基础,也是 ECMAScript 中需要掌握的重点,所以笔者将在后面的学习笔记中详细地对 Object 进行总结,这里就先了解一些 Object 类型的基本概念的方法。
2.8 总结
以上部分主要是笔者对 ECMAScript 中的一些基本概念的简单总结,本篇主要写的还是在进一步学习 ECMAScript 中需要了解的一些基本且重要的概念。
如有写的不好的地方还请多指出讨论。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。