JavaScript 数据类型
数据类型就是 JavaScript 中可操作的数据的类型。
数据类型分为值类型
与引用类型
。
在 ES6 之前,主要有以下数据类型:
- 值类型
- 字符串
- 数字
- 布尔
- null
- undefined
- 引用类型
- 对象
- 数组
- 函数
1. 为什么需要不同的数据类型
在学习自然数学的时候,所有的加法减法等操作都是针对数字的,数字加上操作符让他们有了意义。
在学习语文课的时候,不同的词语可以组合成句子,主谓宾语法与词语相互结合赋予了句子意义。
在 JavaScript 中也是如此,配合数据类型才能知道怎么对数据进行操作。
上一小节有提到的字符串与数字就是如此。
如 3 + 4
,JavaScript碰到两边都是数字,就会做对应的加法操作。
程序需要不同类型的数据表示不同的内容,分别做对应的处理。
2. 值类型
2.1 字符串
字符串由字符组成,字符串在使用的时候会使用双引号(")
或者单引号(')
包裹。
var str1 = '字符串';
var str2 = "字符串";
console.log(str1); // 输出:"字符串"
console.log(str2); // 输出:"字符串"
上述例子中,两个变量都是字符串类型的,可以双引号和单引号包裹的结果是一样的。
但是如果需要在双引号包裹的字符串中使用双引号,或者在单引号包裹的字符串中使用单引号,需要使用/
进行转义,否则会报错,因为 JavaScript 无法知道字符串的结束位置。
var str1 = '使\'用\'单\'引\'号';
var str2 = "使\"用\"双\"引\"号";
console.log(str1); // 输出:"使'用'单'引'号"
console.log(str2); // 输出:"使"用"双"引"号"
// 以下代码会报错
var str3 = "哼"!";
var str4 = ''哼!';
大部分开发者会使用单引号包裹字符串。
因为为了网页的动态展示、复杂交互等,需要用 JavaScript 书写 HTML 模版,而 HTML 的属性按照习惯是使用双引号包裹的(XML 标准允许单引号和双引号,在 HTML5 的标准中甚至不需要书写引号)。
这样如果使用 JavaScript 中的字符串表示 HTML 就会变成如下情况:
var html = "<div class=\"title text-red\" style=\"display: inline-block;\">我是一个红色的标题</div>";
为了契合书写 HTML 的习惯,防止代码中充斥的大量的转义,就会使用如下使用单引号的形式。
var html = '<div class="title text-red" style="display: inline-block;">我是一个红色的标题</div>';
2.2 数字
数字是最好理解的一种类型,因为生活中都会接触到。
数字可以细分为浮点数和整数,浮点数就是带有小数位的数,但事实上在 JavaScript 只有64位的浮点数
,具体的范围是 [-2^53 ~ 2^53]
,整数也使用浮点数表示。
数字类型也存在负数,如果数字的区间为 (0, 1)
,则可以省略小数点前的 0
。
var num1 = 5;
var num2 = .1;
var num3 = 0.5;
var num4 = -10;
var num5 = 884739573;
以上是数字的一些表示方式。
如果数字的大小超过最大值或者最小值,那他的值在 JavaScript 中会表示为 Infinity
和 -Infinity
。
var base = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
var num1 = 99999 * base;
var num2 = -99999 * base;
console.log(num1); // 输出:Infinity
console.log(num2); // 输出:-Infinity
这两个值分别表示为无穷大
和无穷小
。
JavaScript 中还可以用数字表示二进制
、八进制
与十六进制
。
二进制是以 0b
开头的数字。
var val10 = 0b1010;
var val8 = 0b1000;
console.log(val10); // 输出:10
console.log(val8); // 输出:8
在输出的时候还是会以十进制的结果进行输出。
八进制则可以用 0
开头的数字表示。
var val56 = 070;
console.log(val56); // 输出:56
十六进制使用 0x
开头表示。
var val10 = 0xA;
console.log(val10); // 输出:10
十六进制是比较常用的一种方式,二进制和八进制的表示使用相对较少。
2.3 布尔
布尔值表示两种状态,如同使用零和一区分状态的开关一样。
开关布尔值两种状态对应 true
和 false
两个值。
通常 true
被称为真值
,false
被称为假值
,两者也被统一称为布尔值
。
var empty = true;
var isVIP = false;
通常在只有两种状态的情况下会使用布尔值。
以下值在转换成布尔值的时候会转换成 false
。
- null
- undefined
- NaN
- 0 ( 数字 0 )
- 空字符串
2.4 null
null
是一个非常特殊的类型,表示对象的值未设置,也可以简单理解成空
,什么都没有
。
通常null
会在应该获取到一个对象,但是没获取到的时候进行使用,结合对象会更好理解。
在初始化一个变量的时候,有时候类型不确定,或者应该是一个对象,但还有设置值的时候会使用到null。
var obj = null;
2.5 undefined
undefined
从中文意思上理解就是不确定或者没有定义。
一个变量在声明后如果没有赋值,他的值就是undefined
。
var age;
console.log(age); // 输出:undefined
一个函数在没有指定返回值的时候,默认就会返回undefined
。
function fn() {
console.log('我是名字为fn的函数');
}
var val = fn();
console.log(val); // 输出:undefined
函数fn
没有提供返回值,但val
的值为undefined
。
比较有趣的是,undefined
既是一种数据类型,在浏览器中又是作为全局变量存在的,也就是window
对象下的一个属性。
console.log('undefined' in window); // 输出:true
使用in
关键字可以校验某个对象下是否存在某个属性。这里的意思就是undefined
属性是否在window对象
下存在。
控制台会输出布尔值true
,为一个真值,表示属性是确实存在的。
3. 引用类型
3.1 函数
函数其实是一段 JavaScript
代码,调用函数就会执行函数中的代码。
使用 function
关键字就可以定义一个函数,简单的函数语法如下:
function 函数名(参数) {
函数体;
return 返回值;
}
var ret = 函数名(参数1) // 调用函数
函数名就是函数的名字,在调用函数的时候会被使用到。
参数则是传递给函数的数据,函数内部可以访问到传进来的参数。
return
则标志着函数的结束,返回值会被作为结果进行返回。
function add(arg1, arg2) {
var sum = arg1 + arg2;
return sum;
}
var num1 = add(1, 2);
var num2 = add(4, 2);
console.log(num1); // 输出:3
console.log(num2); // 输出:6
上面这个例子就是声明了一个名为 add
的函数,其功能就是把两个参数求和并返回。
可以看到函数让代码更加有 意义
,调用 add
函数的地方可以很好的理解这里是在做求和操作,同时提高了代码的复用率。
3.2 对象
对象由属性和方法组成。
其格式如下:
var obj = {
属性名1: 属性值1,
属性名2: 属性值2,
方法名1: 方法1,
方法名2: 方法2,
'属性名3': 属性值3,
};
属性名和方法名都为字符串,如果其符合变量命名规范,则可以不使用引号包裹。
本质上方法也可以算作一个属性,通常在对象里一个属性的属性值为一个函数,就会称之为方法。
var obj = {
name: '小明',
age: 12,
say: function() {
console.log('我叫' + this.name + ', 我的年龄是' + this.age + '岁');
},
'father-name': '小蓝',
};
console.log(obj.name); // 输出:小明
console.log(obj['father-name']); // 输出:小蓝
obj.say(); // 调用 say 方法,会输出:我叫小明, 我的年龄是12岁
上述例子中的 obj
对象具有三个属性(name、age、father-name)一个方法(say)。
属性可以是任意的数据类型,格式为属性名: 属性值
,多个属性则由逗号(,)
分隔,方法则只能为一个函数,通常会是一个匿名函数(函数相关的详细内容可以查阅函数章节)。
通过对象.属性
就可以访问到对象属性的属性值,如果属性名是一个不符合变量命名规范的值,则可以通过对象['属性名']
进行访问,方法同理,因为本质上方法也是属性。
既然属性可以是任意的数据类型,则也可以是一个对象:
var obj = {
name: '小明',
colors: {
hair: 'red',
eye: 'blue',
skin: 'white',
},
};
理论上在内存允许的情况下,可以进行无限层的对象嵌套。
以上的例子都是采用字面量
的方式创建一个对象,还有许多种方式可以创建对象。
如使用Object
构造一个新对象。
var obj = new Object();
obj.name = '小明';
obj.age = 16;
obj.colors = {
hair: 'red',
eye: 'blue',
};
console.log(obj.colors.hair); // 输出:red
console.log(obj.name); // 输出:小明
obj.name = '小红';
console.log(obj); // 将会在控制台输出 obj 对象
通过 new Object()
就可以创建一个新的对象。
通过对象.属性 = 属性值
的方式就可以设置一个属性和属性值,这一方式遵循以下规则:
- 如果要赋值的属性不存在,则会创建这个属性并赋值
- 如果要赋值的属性存在,则会修改这个属性的值
另外还可以使用构造函数
、Object.create
等方式创建对象,具体请参考对象章节。
3.3 数组
数组是一组数据构成的列表。
数组由中括号包裹,每一项通过逗号
进行分隔:
var arr = [1, '2', 3, 4, 5];
console.log(arr[0]); // 输出:1
console.log(arr[1]); // 输出:"2"
和对象一样的是,数组的每一项也可以是任意类型的数据。
如果需要访问数组中的每一项可以通过数组[下标]
的格式进行访问。
下标就是数组每一项的编号,这个编号从0
开始,第一项为0
,第二项为1
,以此类推。
数组可以理解成一种特殊的对象,他原生具有一些方法,如遍历数组:
var arr = ['a', 'b', 'c'];
arr.forEach(function(item, index) {
console.log(item, index); // "a" 0, "b" 1, "c" 2
});
通过数组.forEach
的方式就可以遍历数组,forEach
方法接受一个函数,这个函数在遍历到每一项的时候会被调用,并将每一项的值和下标作为参数传递过来。
既然具有一些方法,同样的也具有一些属性,最常用的就是length
属性:
var arr = [1, 2, 3];
console.log(arr.length); // 输出:3
数组的 length
属性会返回数组的长度。
4. 值类型和引用类型的区分方式
从内存角度出发,值类型放在内存栈中,引用类型则放在内存堆中。
引用类型的数据长度是不固定的,如对象所占用的空间很大一部分由属性值决定,而属性值又可以是任意类型。
另外最大的区别就如分类名一样,引用类型的数据本身是指向内存上的一块地址,操作的时候对地址上的值进行操作。
而值类型直接操作值,不论是复制或是修改都是直接产生一个新的值。
var obj1 = {
name: '小明',
};
var obj2 = obj1;
obj2.name = '小红';
console.log(obj1.name); // 输出:小红
var val1 = 1;
var val2 = val2;
val2 = 2;
console.log(val1); // 输出:1
通过上面的例子就可以看出引用类型和值类型在 JavaScript 程序中的区别。
引用类型在进行复制的时候,其实就是多了一个引用,操作的值是同一个。
而值类型进行复制后,则是一个新的值。
5. 小结
- 数据类型是比较重要的一个概念,在分类上分为引用类型和值类型。
- 值类型包括:字符串、数字、布尔、null、undefined。
- 引用类型包括:函数、对象、数组。
- 引用类型相对复杂,每一种类型也具有很多特性,其内容可以参阅对应的章节。