前端工程师必须掌握的6种数据类型

760 阅读12分钟

ECMAScript有5种简单数据类型:Undefined、Null、Boolean、Number、String和一种复杂数据类型:Object。

1. Undefined 类型

Undefined类型只有一只值,即undefined。声明但未进行初始化的变量的值是undefined。具体请看下面的例子:

// 声明但未进行初始化的变量的值是undefined
var message;
alert(message == undefined); //true

// 可以使用undefined显式初始化变量,ECMA-262第三版引入undefined这个值,主要用于区分空对象指针(null)与未初始化的变量。
var message = undefined; 
alert(typeof age); // true

// 未声明的变量,直接使用会报错
var message; 
alert(message); // "undefined"
alert(age); // 报错!

// 未声明的变量,使用typeof操作符检测不会报错
var message; 
alert(typeof message);// "undefined"
alert(typeof age); // "undefined" ,

2. NUll类型

Null类型与Undefined类型一样也只有一个值,这个特殊值是null。null表示一个空对象指针,而这也正是typeof null === 'object'的原因。

var person = null;
alert(typeof person); // "object"

一般而言,如果定义的变量准备用于保存对象,那么最好将改变量初始化为null,这样只要检测是否为null就可以知道该对象是否为空。

if(person != null){
    // do something...
}

实际上undefined值是由null派生出来的,因为ECMA-262规定,对它们进行相等性测试时,要返回true

alert(null == undefined); // true,注意这里是“==”,不是“===”

注意:无论在什么时候都没有必要将一个变量初始化为undefined,但是很有必要将一个空对象初始化成null

3. Boolean类型

Boolean类型只有两个值truefalse,需要注意的是true不一定等于1,而false也不一定等于0。另外这两个值区分大小写,TrueFalse(以及其他的混合大小写)都不是Boolean值。

虽然Boolean只要两个值,但是所有类型的值都有与这两个值等价的值。可以调用转型函数Boolean(),将其他类型的值转化成Boolean值。

各种数据类型转成Boolean值的规则:

数据类型 准换为true的值 转换为false的值
Boolean true false
String 任意非空字符 “”(空字符串)
Number 任意非零数值(包括无穷大) 0和NaN
Object 任何对象 null
Undefined n/a(N/A)是not applicable的缩写,意思是“不适用” undefined

4.Number类型

ECMAScript使用IEEE754格式来表示整数和浮点数(也叫双精度数值)。ECMAScript中,整数可以使用十进制、十六进制以及八进制来表示。

八进制第一位必须是0,然后是八进制的数字序列(0-7),如果字面数值超出范围,第一位的0将被忽略,当成十进制数值解析。

var octalNum1 = 070; // 有效的八进制,解析为十进制的56
var octalNum2 = 079; // 无效的八进制,解析为十进制的79
var octalNum3 = 08; // 无效的八进制,解析为十进制的8
// 注意:八进制字面量在严格模式下是无效的,会导致支持JavaScript引擎抛出错误

十进制字面量前两位必须是0x,后面跟任意十六进制的字符(0-9及A-F)。其中A-F可以大写,也可以小写。

var hexNum1 = 0xa; // 十六进制的表示的10(十进制)
var hexNum2 = 0x1f; // 十六进制表示的31 (十进制)

注意:在进行算数运算时,所有八进制、十六进制表示的数值最终都将被转换成十进制的数值

4.1 浮点数值

所谓浮点数,就是有小数点的数。保存浮点数所需的空间是保存整数的两倍,因此ECMAScript会适当的将浮点数值转化成整数值。例如,当小数点后面没有跟任何数字时。更多浮点数的转换及表示请看下面的例子:

var floatNum1 = 1.1;
var floatNum2 = 1.0; // 存储时,会被智能转化成整数
var floatNum3 = .1;// 有效,但是不推荐!
var floatNum4 = 3.125e7 // 等于3125000。科学计数法表示浮点数,用e表示的数值等于e前面的数值乘以10的指数次幂,e可以大写也可以小写。
var floatNum5 = 0.0000006; // 会被转化成6e-7。默认情况下ECMAscript会将后面带有6个零以上的浮点转化成科学计数法。

浮点数值的最高精度是17位小数,但是在进行算数计算时,其精度远远不如整数,例如:0.1加0.2的结果不等于0.3,而是0.30000000000000004。这个舍入误差会导致无法测试特定的浮点数值。

if(a+b==0.3){ // 不要做这样的测试!
    alert('你获得了0.3') 
}

提示:关于浮点数的误差,是基于IEEE754数值的浮点计算的通病,ECMAScript并非独此一家,其他相同数值格式的语言也存在这个问题

4.2 数值范围

  • ECMAScript能够表示的最小数值保存在Number.MIN_VALUE中,这个值是5e-324
  • 能够表示的最大数值保存在Number.MAX_VALUE中,这个值是1.7976931348623157e+308
  • 超出最小值会被自动转换成0,负数会转化成-0,正数会转化成0
  • 超出最大值会被自动转换成Infinity(无穷大),负数会转换成-Infinity,正数会转换成Infinity -Infinity无法再进行计算
  • 可以使用isFinite()函数来检测某个数值是否是又穷的
var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result)); // false

提示:访问Number.POSITIVE_INFINITYNumber.NEGATIVE_INFINITY 也可以得到正负的Infinty值

4.3 NaN

NaN即非数值(not a Number),是一个特殊的数值,这个数值表示一个本来要返回数值但是未返回数值的情况(这样就不会报错了)。例如:在其他语言中,任何数值除以0都会报错,但在ECMAScript中,会返回NaN。NaN有如下要注意的点:

  • 任何涉及NaN的操作,都会返回NaN
  • NaN与任何值都不相等,包括NaN本身
  • 可以使用isNaN()函数确定一个值是否”不是数值“
alert(NaN == NaN); // false

alert(isNaN(NaN)); // true
alert(isNaN(10)); // false(10是一个数值)
alert(isNaN("10")); // false("10"可以被转化成数值)
alert(isNaN("blue")); // true ("blue"不能被转化成数值)
alert(isNaN(true)); // false (true可以被转化成数值1)

alert(0/0); // NaN
alert(10/0); // Infinity
alert(-10/0); // -Infinity

提示:有意思的是isNaN()同样适用于对象。对象调用isNaN()首先会调用对象的valueOf()方法,然后确定该方法是否可以转化为数值,如不能,会调用对象的toString()方法,再测试返回值。而这个过程也是ECMAScript中内置很熟和操作符的一般执行流程

4.4 数值转换

有三个函数可以将非数值转换为数值:Number()parseInt()parseFloat()

  • Number() 可以用于任何数据类型
  • parseInt() 用于将字符串转化成整型
  • parseFloat() 用于将字符串转化成浮点型
4.4.1 Number()函数的转换规则
// 布尔类型
Number(Boolean); // true 和 false将分别转换成1和0
// 数值类型
Number(123); // 返回 123。不转换,只做简单的传入和返回
// Null类型
Number(null); // 返回 0
// Undefined类型
Number(undefined); // 返回NaN
// 字符串——只有整数:
Number("100"); // 返回 100。
Number("012"); // 返回 12。注意:前导零被忽略了
// 字符串——只有浮点数
Number("0.123"); // 返回 0.123
Number("01.23");// 返回 1.23。注意:前导零被忽略了
// 字符串——只有十六进制的数值
Number("0xf"); // 返回 15。16进制被转换成十进制
// 空字符串
Number(""); // 返回 0。空字符串被转换成0

// 包含除了上述格式之外的字符
Number("abdc%&3023"); // 返回 NaN

// 对象
Number({}); // 返回 NaN。首先调用valueOf()方法,然后依照前面的规则转换,如果结果是NAN,则调用toString()方法,然后再次依照前面的规则转换返回的字符串。
4.4.2 parseInt()函数的转换规则
  • parseInt()会忽略字符串前面的空格,直至找到第一个非空字符。
  • 如果第一个字符不是数字字符或者符号,parseInt()会直接返回NaN。也就是说用parseInt()转换空字符串会返回NaN,而Number()会返回0。
  • 如果第一个字符是数字字符,parseInt()会继续解析后面的字符,直至解析完所有字符或者遇到了一个非数字字符。例如:“123blue45” 会被解析为12322.5会被解析为22
  • parseInt()能够识别出各种格式(八进制、十六进制、十进制)。如果以“0x”开头且后面跟数字字符,就会当做十六进制,如果“0”开头且后跟数字字符,则会将其当做一个八进制数来解析。
  • 使用parseInt()时,可以指定第二个参数:转换时使用的基数(即多少进制),这样可以保证得到正确结果(ECMAScript不同版本的这个方法存在差异)。多数情况下,我们要解析的都是十进制数值,因此始终将10作为第二个参数是非常必要的!
var num1 = parseInt("1234blue"); // 1234
var num2 = parseInt(""); // NaN
var num3 = parseInt("0xA"); // 10
var num4 = parseInt(22.5); // 22
var num5 = parseInt("070"); // 70
var num6 = parseInt("70");  // 70
var num7 = parseInt("0xf"); // 15
4.4.3 parseFloat()函数的转换规则

parseFloat()只解析十进制,因此它没有用第二个参数指定基数的用法。需要注意的是:如果一个字符串包含的是一个可解析为整数的数(没有小数点,或小数点后都是零),parseFloat()会返回整数。

var num1 = parseFloat("1234blue"); // 1234(整数)
var num2 = parseFloat("0xA"); // 0 
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

5. String类型

  • String类型用于表示由零个或多个16位Unicode字符组成的字符序列,即字符串。字符串可以由""''表示。
  • 字符串一旦创建就不能更改,要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。这就是旧版本浏览器处理字符串很慢的原因所在。

5.1 字符串中的转义字符

字符串中包含一些特殊的字符字面量,也叫转义字符,或者具有其他用途的字符。这些字符字面量如下表所示:

字面量 含义
\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表示希腊字符中的Σ

以上字符可以出现在字符串任意位置,而且也将作为一个单独的字符来解析。例如:

var text = "This is : \u03a3"; // \u03a3 这6个转义序列会被当做一个字符
alert("This is : \u03a3".length);//输出10

5.2 转换为字符串的方式(两种)

  • 转换为字符串有两种方式,第一种是使用几乎每个值( null和undefined除外)都有的toString()方法。
  • toString()可以传递基数,通过传递基数toString()可以输出二进制、八进制、十进制、乃至其他任意的有效进制格式表示的字符串值
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"
  • 由于null和undefined没有toString()方法,所以在不知道要转换的值是不是null或者undefined时,可以使用String()方法将其转化成字符串。 String()方法的转换规则如下:
1、如果有toString()方法,调用该方法(没有参数)并返回结果
2、如果值是null,返回“null”
3、如果是undefined(未初始化或初始化为undefined的变量),返回“undefined”
  • 转换为字符串的第二种方式是:把这个值与一个字符串("")加在一起,例如:123+“”会得到“123”

提示:复杂的数据建议使用toString()String(),简单的推荐使用加号链接的方式。

6. Object类型

在ECMAScript中,对象其实就是一组数据和功能的组合。创建对象的方式有两种,一种是通过new关键字,另一种是字面量的方式。

var obj = new Object();
var obj = {}

6.1 Object实例的属性和方法

  1. constructor:保存着用于创建当前对象的函数。上面例子中,constructor(构造函数)就是Object()。
  2. hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是实例的原型中)是否存在。例如:
var Person = function(){this.name='linlif'}
var person = new Person()
person.hasOwnProperty("name") // true 
  1. isPrototypeOf(object):用于判断一个对象是否为一个实例的原型。例如:
function Parent() {this.name = "linlif";}
Parent.prototype.alertP = function() {
  alert("Parent");
}

function Child() {this.age = 25;}
Child.prototype.alertC = function() {
  alert("Child");
}

function F() {}
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
var child = new Child();

Parent.prototype.isPrototypeOf(child); // true
Child.prototype.isPrototypeOf(child); // true
  1. propertyIsEnumerable(propertyName): 用于检查给定的属性是否能够使用for-in语句来枚举。与hasOwnProperty()方法一样,参数必须是字符串形式。for-in可以枚举对象本身的属性和原型上的属性,而propertyIsEnumerable只能判断本身的属性是否可以枚举。此外,预定义的属性不是可列举的,而用户定义的属性总是可列举的。
function Person (){ this.name = 'linlif' };
Person.prototype.age = 25;
var obj = new Person()
for (var key in obj) {
  if (obj.hasOwnProperty(key)){
    console.log(key) // name
  }else{
    console.log(key) // age
  }
}
  1. toLocaleString(): 返回对象的字符串表示,该字符串与执行环境的地区对应。
  2. toString():返回对象的字符串表示。
  3. valueOf():返回对象的字符串、数值或布尔类型表示。通常与toString()方法的的返回值相同。

最后,附上一张脑图,方便大家理解和记忆!

本文没有涉及ES6新增Symbol数据类型,有兴趣的请自行查阅读阮一峰老师的在线书籍。地址:es6.ruanyifeng.com/#docs/symbo…

本文是JavaScript基础系列的第一篇文章,后续会继续补上剩下的,欢迎持续关注!写总结真不容易,但坚持就是胜利,为自己加油!(๑•̀ㅂ•́)و✧