最近正在看《JavaScript高级程序设计》,一直没来得及总结一下,顺便对以前看的《JavaScript DOM编程艺术》进行一些简单的总结,若有一些不正确的地方还请多指出讨论。javascript
在学习 JavaScript 以前要理解的第一个概念就是在 ECMAScript 中全部的一切(变量、函数名和操做符)都是区分大小写的。好比变量 test 和 Test 是两个不一样的变量,typeof 不能用在函数名上,由于它是一个关键字,但 typeOf 彻底能够是一个函数名,由于在 ECMAScript 中变量、函数名和操做符等等都是区分大小写的。java
在学习以前还须要了解的第二个概念就是「标识符」,所谓标识符就是指变量、函数、函数的参数和属性的名字,标识符能够下列格式规则组合起来的一个或多个字符:正则表达式
按照惯例,ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每一个单词的首字母大写,例如:编程
ECMAScript 中有 5 种基本数据类型:Undefined、 Null、 Boolean、 String 和 Number。还有 1 种复杂数据类型:Obect,Object 本质上是由一组无序的名值对组成。ECMAScript 不支持任何建立自定义类型的机制,而全部值最终都将是上述 6 种数据类型之一。浏览器
因为 ECMAScript 是松散类型的,因此须要有一种方法来检测给定变量的数据类型,typeof 就是负责提供这方面信息的操做符。对一个值使用 typeof 操做符可能返回下列某个字符串:函数
例如:学习
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"。设计
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"。
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。
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 |
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
在进行算数计算时,全部的八进制和十六进制表示的数值最终都将被转换成十进制数值。
浮点数值必须包含一个小数点,且小数点后面必需要有一位**非 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."); }
因为内存的限制,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
由上可知,最大值和最小值也算是有穷的。
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() 方法,在测试返回的值。
能够把非数值转换成数值的函数有 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() 能够接受第二个参数,第二个参数只能是 二、 八、 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
String 类型表示字符串,能够由双引号("")或单引号('')表示,因此下面这两种字符串都是有效的:
var firstName = "Clear"; var lastName = 'Design';
但有一点须要注意的是,以什么引号开头就必须以什么引号结尾,好比下面这种写法就是错误的:
var name = "Clear Design';
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表示希腊字符Σ |
ECMAScript 中的字符串是不可变的,字符串一旦建立,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,而后再用另外一个包含新值的字符串填充该变量,例如:
var lang = "Java"; lang = lang + "Script";
上面的 lang 开始时包含 "Java",而第二行代码把 lang 从新定义为 "Java" 和 "Script" 的组合,即 "JavaScript"。第二行代码并非把原来的 lang 的值改变了,而是首先建立一个能容纳 10 个字符的新字符串,而后在这个字符串中填充 "Java" 和 "Script",因为新的字符串拼接完成后,原来的字符串已经没有用了,因此原来的字符串 "Java" 和 "Script" 会被销毁,这些都是发生在后台的。
前面提到 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() 方法接受一个参数,参数只能是 二、 八、 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() 函数的转换规则以下:
下面再看几个例子:
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"
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 类型的基本概念的方法。
以上部分主要是笔者对 ECMAScript 中的一些基本概念的简单总结,本篇主要写的仍是在进一步学习 ECMAScript 中须要了解的一些基本且重要的概念。
若有写的很差的地方还请多指出讨论。