概括:
JavaScript的数据类型共有6种,ES6又增加第7中(symbol)。
- 数值(Number):整数和小数。
- 字符串(String):文本。
- 布尔值(boolean):只有两个值。true(真)、false(假)。
- Undefined:未定义或不存在。
- Null:表示空值
- 对象(Object):各种值组成的集合。
对象是最复杂的数据类型,又可细分为三种:
- 狭义的对象(object)
- 数组(array)
- 函数(function)
number,string,boolean这三个为原始类型。
object为合成类型
原始类型:最基本的数据类型,不能再细分。
合成类型:多个原始类型的值的合成。
1.number
1. 概括:JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算
1===1.0 //true
0.1+0.2=0.3 //false
0.3/0.1 //2.9999999999999996
(0.3-0.2)===(0.2-0.1) //false
2. 数值的表示法
JavaScript 的数值有多种表示方法,可以用字面形式直接表示,比如35(十进制)和0xFF(十六进制)。数值也可以采用科学计数法表示。
123e3 // 123000
123e-3 // 0.123
科学计数法允许字母e或E的后面,跟着一个整数,表示这个数值的指数部分。
以下两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。
小数点前的数字多于21位。
1234567890123456789012 // 1.2345678901234568e+21
123456789012345678901 // 123456789012345680000
小数点后的零多于5个。
0.0000003 // 3e-7
0.000003 // 0.000003
3.数值的进制
JavaScript 对整数提供四种进制的表示方法:十进制、十六进制、八进制、二进制。
- 十进制:没有前导0的数值。
- 二进制:有前缀0b或0B的数值。
- 八进制:有前缀0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
- 十六进制:有前缀0x或0X的数值。
默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。下面是一些例子。
0xff // 255
0o377 // 255
0b11 // 3
如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错。
0xzz // 报错
0o88 // 报错
0b22 // 报错
4.特殊数字 NaN
NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
5 - 'x' // NaN
上面代码运行时,会自动将字符串x转为数值,但是由于x不是数值,所以最后得到结果为NaN,表示它是“非数字”(NaN)。
一些数学函数的运算结果会出现NaN。
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
0除以0也会得到NaN。
0 / 0 // NaN
需要注意的是,NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
typeof NaN // 'number'
NaN不等于任何值,包括它本身。
NaN === NaN // false
数组的indexOf方法内部使用的是严格相等运算符,所以该方法对NaN不成立。
[NaN].indexOf(NaN) // -1
NaN在布尔运算时被当作false。
Boolean(NaN) // false
NaN与任何数(包括它自己)的运算,得到的都是NaN。
NaN + 32 // NaN
NaN - 32 // NaN
NaN * 32 // NaN
NaN / 32 // NaN
2. String
概述:字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。
'abc'
"abc"
单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号。
'key = "value"'
"It's a long journey"
如果要在单引号字符串的内部,使用单引号,就必须在内部的单引号前面加上反斜杠,用来转义。双引号字符串内部使用双引号,也是如此。
'Did she say \'Hello\'?'
"Did she say \"Hello\"?"
字符串默认只能写在一行内,分成多行将会报错。
'a
b
c'
// SyntaxError: Unexpected token ILLEGAL
如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠。
var longString = 'Long \
long \
long \
string';
longString
// "Long long long string"
上面代码表示,加了反斜杠以后,原来写在一行的字符串,可以分成多行书写。但是,输出的时候还是单行,效果与写在同一行完全一样。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错
连接运算符(+)可以连接多个单行字符串,将长字符串拆成多行书写,输出的时候也是单行。
var longString = 'Long '
+ 'long '
+ 'long '
+ 'string';
2. 转义
反斜杠(\)在字符串内有特殊含义,用来表示一些特殊字符,所以又称为转义符。 需要用反斜杠转义的特殊字符,主要有下面这些。
\0 :null(\u0000)
\b :后退键(\u0008)
\f :换页符(\u000C)
\n :换行符(\u000A)
\r :回车键(\u000D)
\t :制表符(\u0009)
\v :垂直制表符(\u000B)
\' :单引号(\u0027)
\" :双引号(\u0022)
\\ :反斜杠(\u005C)
3. boolean
概述:布尔值代表的就两个值,true、false。
- 两元逻辑运算符:&&(and) ||(or)
- 前置逻辑运算符: !(not)
- 相等运算符:===,!==,==,!=
- 比较运算符:>,>=,<,<=
4. undefined和null
概述:undefined和null都可以表示‘没有’,含义非常相似。语法效果几乎没区别。
- 变量没赋值(undefined)
- 有一个对象,现在不能赋值 (null)空对象
- 有一个非对象,不想赋值(undefined) 空非对象
5. Object
- 对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型。
什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
var obj = {
foo: 'Hello',
bar: 'World'
};
上面代码中,大括号就定义了一个对象,它被赋值给变量obj,所以变量obj就指向一个对象。该对象内部包含两个键值对(又称为两个“成员”),第一个键值对是foo: 'Hello',其中foo是“键名”(成员的名称),字符串Hello是“键值”(成员的值)。键名与键值之间用冒号分隔。第二个键值对是bar: 'World',bar是键名,World是键值。两个键值对之间用逗号分隔。
2. 键名
概述:对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。上面的代码也可以写成下面这样。
var obj = {
'foo': 'Hello',
'bar': 'World'
};
var obj = {
foo: 'Hello',
bar: 'World'
};
如果键名是数值,会被自动转为字符串。
var obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
.234: true,
0xFF: true
};
obj
// Object {
// 1: "a",
// 3.2: "b",
// 100: true,
// 0.01: true,
// 0.234: true,
// 255: true
// }
obj['100'] // true
上面代码中,对象obj的所有键名虽然看上去像数值,实际上都被自动转成了字符串。
如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。
// 报错
var obj = {
1p: 'Hello World'
};
// 不报错
var obj = {
'1p': 'Hello World',
'h w': 'Hello World',
'p+q': 'Hello World'
};
3.对象的引用
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。
var o1 = {};
var o2 = o1;
o1.a = 1;
o2.a // 1
o2.b = 2;
o1.b // 2
- 读取属性
读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。
var obj = {
p: 'Hello World'
};
obj.p // "Hello World"
obj['p'] // "Hello World"
请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。
var foo = 'bar';
var obj = {
foo: 1,
bar: 2
};
obj.foo // 1
obj[foo] // 2
上面代码中,引用对象obj的foo属性时,如果使用点运算符,foo就是字符串;如果使用方括号运算符,但是不使用引号,那么foo就是一个变量,指向字符串bar。
数字键可以不加引号,因为会自动转成字符串。
var obj = {
0.7: 'Hello World'
};
obj['0.7'] // "Hello World"
obj[0.7] // "Hello World"
注意,数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运算符。
var obj = {
123: 'hello world'
};
obj.123 // 报错
obj[123] // "hello world"
5.属性的赋值
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
JavaScript 允许属性的“后绑定”,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。
var obj = { p: 1 };
// 等价于
var obj = {};
obj.p = 1;
- 查看所有的属性
查看一个对象本身的所有属性,可以使用 Object.keys 方法。
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);
// ['key1', 'key2']
- delete 命令
delete命令用于删除对象的属性,删除成功后返回true。
var obj = { p: 1 };
Object.keys(obj) // ["p"]
delete obj.p // true
obj.p // undefined
Object.keys(obj) // []
上面代码中,delete命令删除对象obj的p属性。删除后,再读取p属性就会返回undefined,而且Object.keys方法的返回值也不再包括该属性。
注意,删除一个不存在的属性,delete不报错,而且返回true。
var obj = {};
delete obj.p // true
只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除。
var obj = Object.defineProperty({}, 'p', {
value: 123,
configurable: false
});
obj.p // 123
delete obj.p // false
- in 运算符
in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。
var obj = { p: 1 };
'p' in obj // true
in运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。
var obj = {};
'toString' in obj // true
- for…in 循环
for...in循环用来遍历一个对象的全部属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log(obj[i]);
}
// 1
// 2
// 3
使用for...in循环,提取对象属性名的例子。
var obj = {
x: 1,
y: 2
};
var props = [];
var i = 0;
for (var p in obj) {
props[i++] = p
}
props // ['x', 'y']
for...in循环有两个使用注意点。
-
它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
-
它不仅遍历对象自身的属性,还遍历继承的属性。