1.分类:
1.原始类型(6种)
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
2. 对象类型
- Object: 任意对象
- Funtion: 一种特别的对象(可以执行)
- Array: 一种特别的对象(数值下标,内部数据是有序的)
2.判断
因为ECMAScript的类型系统是松散的,所以需要一种手段来确定任意变量的数据类型。typeof操作符就是为此而生的。对一个值使用typeof操作符会返回下列字符串之一:
- "undefined"表示值未定义;
- "boolean"表示值为布尔值;
- "string"表示值为字符串;
- "number"表示值为数值;
- "object"表示值为对象(而不是函数)或null;
- "function"表示值为函数;
- "symbol"表示值为符号。
注意:严格来讲,函数在ECMAScript中被认为是对象,并不代表一种数据类型。可是,函数也有自己特殊的属性。为此,就有必要通过typeof操作符来区分函数和其他对象。
1.1 Undefined类型
Undefined类型只有一个值,就是特殊值undefined。当使用var或let声明了变量但没有初始化时,就相当于给变量赋予了undefined值:
let message;
console.log(message == undefined); // true
注意 :即使未初始化的变量会被自动赋予undefined值,但我们仍然建议在声明变量的同时进行初始化。这样,当typeof返回"undefined"时,你就会知道那是因为给定的变量尚未声明,而不是声明了但未初始化。
1.2 Null类型
Null类型同样只有一个值,即特殊值null。逻辑上讲,null值表示一个空对象指针,这也是给typeof传一个null会返回"object"的原因:
let car = null;
console.log(typeof car); // "object"
在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。这样,只要检查这个变量的值是不是null就可以知道这个变量是否在后来被重新赋予了一个对象的引用。
1.3 Boolean类型
Boolean(布尔值)类型是ECMAScript中使用最频繁的类型之一,有两个字面值:true和false。这两个布尔值不同于数值,因此true不等于1,false不等于0。下面是给变量赋布尔值的例子:
let found = true;
let lost = false;
注意: 布尔值字面量 true 和 false 是区分大小写的。
Boolean()转型函数可以在任意类型的数据上调用,而且始终返回一个布尔值。什么值能转换为true或false的规则取决于数据类型和实际的值。下表总结了不同类型与布尔值之间的转换规则。
数据类型 | 转换为true的值 | 转换为false的值 |
Boolean | true | false |
String | 非空字符创 | " "(空字符创) |
Number | 非零数值(包括无穷值) | 0,NaN |
Object | 任意对象 | null |
Undefined | N/A(不存在) | undefined |
理解以上转换非常重要,因为像if等流控制语句会自动执行其他类型值到布尔值的转换,例如:
let message = "Hello world! ";
if (message) {
console.log("Value is true");
}
在这个例子中,console.log会输出字符串"Value is true",因为字符串message会被自动转换为等价的布尔值true。由于存在这种自动转换,理解流控制语句中使用的是什么变量就非常重要。错误地使用对象而不是布尔值会明显改变应用程序的执行流。
1.4 Number类型
ECMAScript中最有意思的数据类型或许就是Number了。Number类型表示整数和浮点值(在某些语言中也叫双精度值)。不同的数值类型相应地也有不同的数值字面量格式。
最基本的数值字面量格式是十进制整数,直接写出来即可:
let intNum = 55; // 整数
要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数,但推荐加上。下面是几个例子:
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
有一个特殊的数值叫NaN,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。
数值转换:
有3个函数可以将非数值转换为数值:
- Number() -> 可用于任何数据类型
- parseInt() -> 主要用于将字符串转换为数值
- parseFloat() -> 主要用于将字符串转换为数值
对于同样的参数,这3个函数执行的操作也不同。
Number()函数基于如下规则执行转换。
- 布尔值,true转换为1,false转换为0。
- 数值,直接返回。
- null,返回0。
- undefined,返回NaN。
- 字符串,应用以下规则。
- 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,Number("1")返回1, Number("123")返回123, Number("011")返回11(忽略前面的零)。
- 如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
- 如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整数值。
- 如果是空字符串(不包含字符),则返回0。
- 如果字符串包含除上述情况之外的其他字符,则返回NaN。
- 对象,调用valueOf()方法,并按照上述规则转换返回的值。如果转换结果是NaN,则调用toString()方法,再按照转换字符串的规则转换。
考虑到用Number()函数转换字符串时相对复杂且有点反常规,通常在需要得到整数时可以优先使用parseInt()函数。parseInt()函数更专注于字符串是否包含数值模式。
下面几个转换示例有助于理解parseInt():
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
不同的数值格式很容易混淆,因此parseInt()也接收第二个参数,用于指定底数(进制数)。如果知道要解析的值是十六进制,那么可以传入16作为第二个参数,以便正确解析:
let num = parseInt("0xAF", 16); // 175
通过第二个参数,可以极大扩展转换后获得的结果类型。比如:
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
parseFloat()函数与parseInt()函数的不同点:
- 可以解析浮点数值字符
- 忽略字符串开头的零。比如十六进制数值始终会返回0。
- 只能解析十进制值,不能指定底数。
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
1.5 String类型
字符串可以使用双引号(")、单引号(')或反引号(`)标示,因此下面的代码都是合法的:
let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`
跟某些语言中使用不同的引号会改变对字符串的解释方式不同,ECMAScript语法中表示字符串的引号没有区别。不过要注意的是,以某种引号作为字符串开头,必须仍然以该种引号作为字符串结尾。比如,下面的写法会导致语法错误:
let firstName = 'Nicholas"; //语法错误:开头和结尾的引号必须是同一种
1. 字符字面量
字符串数据类型包含一些字符字面量,用于表示非打印字符或有其他用途的字符,如下表所示:
2. 字符串的特点
ECMAScript中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量,如下所示:
let lang = "Java";
lang = lang + "Script";
这里,变量lang一开始包含字符串"Java"。紧接着,lang被重新定义为包含"Java"和"Script"的组合,也就是"JavaScript"。整个过程首先会分配一个足够容纳10个字符的空间,然后填充上"Java"和“Script”。最后销毁原始的字符串"Java"和字符串"Script",因为这两个字符串都没有用了。
3. 转换为字符串
有两种方式把一个值转换为字符串:toString() 和 String()。
toString()函数:
toString()方法可见于数值、布尔值、对象和字符串值。null和undefined值没有toString()方法。这个方法唯一用途就是返回当前的字符串等价物。比如:
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); //字符串"true"
String()函数:
如果你不确定一个值是不是null或undefined,可以使用String()转型函数,它始终会返回表示相应类型值的字符串。String()函数遵循如下规则。
- 如果值有toString()方法,则调用该方法并返回结果。
- 如果值是null,返回"null"。
- 如果值是undefined,返回''undefined''。
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
注意:用加号操作符给值加上一个空字符串""也可以将其转换为字符串。
4. 模板字面量
ECMAScript 6新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串:
let myMultiLineString = 'first line\nsecond line';
let myMultiLineTemplateLiteral = `first line
second line`;
console.log(myMultiLineString);
// "first line
// second line"
console.log(myMultiLineTemplateLiteral);
// "first line
// second line"
console.log(myMultiLineString === myMultiLineTemplateLiteral); //true
顾名思义,模板字面量在定义模板时特别有用,比如下面这个HTML模板:
let pageHTML = `
<div>
<a href="#">
<span>Jake</span>
</a>
</div>`;
5. 字符串插值
模板字面量最常用的一个特性是支持字符串插值,也就是可以在一个连续定义中插入一个或多个值。技术上讲,模板字面量不是字符串,而是一种特殊的JavaScript句法表达式,只不过求值后得到的是字符串。模板字面量在定义时立即求值并转换为字符串实例,任何插入的变量也会从它们最接近的作用域中取值。
let value = 5;
let exponent = 'second';
// 以前,字符串插值是这样实现的:
let interpolatedString =
value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25
所有插入的值都会使用toString()强制转型为字符串,而且任何JavaScript表达式都可以用于插值。
1.6 Object类型
ECMAScript中的对象其实就是一组数据和功能的集合。对象通过new操作符后跟对象类型的名称来创建。开发者可以通过创建Object类型的实例来创建自己的对象,然后再给对象添加属性和方法:
let o = new Object();
每个Object实例都有如下属性和方法。
- constructor:用于创建当前对象的函数。在前面的例子中,这个属性的值就是Object()函数。
- hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属性。要检查的属性名必须是字符串(如o.hasOwnProperty("name"))或符号。
- isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。
- propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用for-in语句枚举。与hasOwnProperty()一样,属性名必须是字符串。、
- toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。
因为在ECMAScript中Object是所有对象的基类,所以任何对象都有这些属性和方法。