000002 - JavaScript语言基础(二)
1、数据类型
ECMAScript有6中简单数据类型:Undefined、Null、Boolean、Number、String和Symbol。。Symbol(符号)是ECMAScript 6新增的。还有一种复杂数据类型叫Object(对象)。Object是一种无序名值对的集合。
1.1 typeof操作符
对一个值使用typeof操作符会返回下列字符串之一:
- "undefined"表示值未定义;
- "boolean"表示值为布尔值;
- "string"表示值为字符串;
- "number"表示值为数值;
- "object"表示值为对象(而不是函数)或null;
- "function"表示值为函数;
- "symbol"表示值为符号。
let message = "some string";
console.log(typeof message); // "string" console.log(typeof(message)); // "string"
console.log(typeof 95); // "number"
注意typeof在某些情况下返回的结果可能会让人费解,但技术上讲还是正确的。比如,调用typeof null返回的是"object"。这是因为特殊值null被认为是一个对空对象的引用。
1.2 Undefined类型
Undefined类型只有一个值,就是特殊值undefined。当使用var或let声明了变量但没有初始化时,就相当于给变量赋予了undefined值:
let message;
console.log(message == undefined); // true
let message = undefined;
console.log(message == undefined); // true
注意,包含undefined值的变量跟未定义变量是有区别的。请看下面的例子:
let message; // 这个变量被声明了,只是值为undefined
// 确保没有声明过这个变量
// let age
console.log(message); // "undefined"
console.log(age); // 报错
在上面的例子中,第一个console.log会指出变量message的值,即"undefined"。而第二个console.log要输出一个未声明的变量age的值,因此会导致报错。对未声明的变量,只能执行一个有用的操作,就是对它调用typeof。
undefined是一个假值。因此,如果需要,可以用更简洁的方式检测 它。不过要记住,也有很多其他可能的值同样是假值。所以一定要明确 自己想检测的就是undefined这个字面值,而不仅仅是假值
let message; // 这个变量被声明了,只是值为undefined
// age没有声明
if (message) {
// 这个块不会执行
}if (!message) {
// 这个块会执行
}if (age) {
// 这里会报错
}
1.3 Null类型
Null类型同样只有一个值,即特殊值null。逻辑上讲,null值表示一个空对象指针,这也是给typeof传一个null会返回"object"的原因:
let car = null;
console.log(typeof car); // "object"
在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。这样,只要检查这个变量的值是不是null就可以知道这个变量是否在后来被重新赋予了一个对象的引用,
if (car != null) {
// car是一个对象的引用
}
undefined值是由null值派生而来的,将它们定义为表面上相等,如下面的例子所示:
console.log(null == undefined); // true
即使null和undefined有关系,它们的用途也是完全不一样的。如前所述,永远不必显式地将变量值设置为undefined。但null不是这样的。任何时候,只要变量要保存对象,而当时又没有那个对象可保存,就要用null来填充该变量。这样就可以保持null是空对象指针的语义,并进一步将其与undefined区分开来
1.4 Boolean类型
Boolean(布尔值)类型是ECMAScript中使用最频繁的类型之一,有两个字面值:true和false。这两个布尔值不同于数值,因此true不等于1,false不等于0
let found = true;
let lost = false;
虽然布尔值只有两个,但所有其他ECMAScript类型的值都有相应布尔值的等价形式。要将一个其他类型的值转换为布尔值,可以调用特定的Boolean()转型函数
let message = "Hello world!";
let messageAsBoolean = Boolean(message);
数据类型 | 转换为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");
}
1.5Number类型
let intNum = 55; // 整数
整数也可以用八进制(以8为基数)或十六进制(以16为基数)字面量表示。对于八进制字面量,第一个数字必须是零(0),然后是相应的八进制数字(数值0~7)。如果字面量中包含的数字超出了应有的范围,就会忽略前缀的零,后面的数字序列会被当成十进制数,如下所示:
let octalNum1 = 070; // 八进制的56
let octalNum2 = 079; // 无效的八进制值,当成79处理
let octalNum3 = 08; // 无效的八进制值,当成8处理
要创建十六进制字面量,必须让真正的数值前缀0x(区分大小写),然后是十六进制数字(09以及AF)。十六进制数字中的字母大小写均可。下面是几个例子:
let hexNum1 = 0xA; // 十六进制10
let hexNum2 = 0x1f; // 十六进制31
使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值。
01.浮点数
要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
let floatNum1 = 1.; // 小数点后面没有数字,当成整数1处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数10处理
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以10的给定次幂的数值。ECMAScript中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大写或小写的字母e,再加上一个要乘的10的多少次幂。
let floatNum = 3.125e7; // 等于31250000
浮点值的精确度最高可达17位小数,但在算术计算中远不如整数精确。例如,0.1加0.2得到的不是0.3,而是0.300 000 000 000 000 04。由于这种微小的舍入错误,导致很难测试特定的浮点值
02.值的范围
ECMAScript可以表示的最小数值保存在Number.MIN_VALUE中, 这个值在多数浏览器中是5e-324;可以表示的最大数值保存在Number.MAX_VALUE中,这个值在多数浏览器中是1.797 693 134 862315 7e+308。
注意 使用Number.NEGATIVE_INFINITY和Number.POSITIVE_INFINITY也可以获取正、负Infinity。没错,这两个属性包含的值分别就是-Infinity和Infinity。
03. NaN
有一个特殊的数值叫NaN,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。
console.log(0/0); // NaN
console.log(-0/+0); // NaN
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
console.log(NaN == NaN); // false
ECMAScript提供了isNaN()函数。该函数接收一个参数,可以是任意数据类型,然后判断这个参数是否“不是数值”。把一个值 传给isNaN()后,该函数会尝试把它转换为数值。某些非数值的值可以直接转换成数值,如字符串"10"或布尔值。任何不能转换为数值的值都会导致这个函数返回true。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10是数值
console.log(isNaN("10")); // false,可以转换为数值10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值1
04.数值转换
有3个函数可以将非数值转换为数值:Number()、parseInt()和parseFloat()。Number()是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值
-
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()方法,再按照转换字符串的规则转换。
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1
parseInt()函数更专注于字符串是否包含数值模式。字符串最前面的空格会被忽 略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt()立即返回NaN。这意味着空字符串也 会返回NaN(这一点跟Number()不一样,它返回0)。如果第一个字 符是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符。如果字符串以"0x"开头,就会被解释为十六进制整数
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("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
通过第二个参数,可以极大扩展转换后获得的结果类型
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开始检测每个字符。同样,它也是解析到字符串末尾或者解析到一个无效的浮点数值字符为止,因此,"22.34.5"将转换成22.34。
parseFloat()函数的另一个不同之处在于,它始终忽略字符串开头的零。这个函数能识别前面讨论的所有浮点格式,以及十进制格式(开头的零始终被忽略)。十六进制数值始终会返回0。因为parseFloat()只解析十进制值,因此不能指定底数。
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.6 String类型
String(字符串)数据类型表示零或多个16位Unicode字符序列。字符
串可以使用双引号(")、单引号(')或反引号(`)标示
let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`
let firstName = 'Nicholas"; // 语法错误:开头和结尾的引号必须是同一种
01.字符串面量
字面量 | 含义 |
---|---|
\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等于希腊字符"Σ" |
02.字符串的特点
字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量
let lang = "Java";
lang = lang + "Script";
03. 转换为字符串
有两种方式把一个值转换为字符串。首先是使用几乎所有值都有的toString()方法。这个方法唯一的用途就是返回当前值的字符串等价物。
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true
toString()方法可见于数值、布尔值、对象和字符串值。null和undefined值没有toString()方法。
多数情况下,toString()不接收任何参数。不过,在对数值调用这个方法时,toString()可以接收一个底数参数,即以什么底数来输出数值的字符串表示。默认情况下,toString()返回数值的十进制 字符串表示。而通过传入参数,可以得到数值的二进制、八进制、十六进制,或者其他任何有效基数的字符串表示,比如:
let num = 10; console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
如果你不确定一个值是不是null或undefined,可以使用String()转型函数,它始终会返回表示相应类型值的字符串。String()函数遵循如下规则。
- 如果值有toString()方法,则调用该方法(不传参数)并返回结果。
- 如果值是null,返回"null"。
- 如果值是undefined,返回"undefined"。
04.模板字面量
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
05. 字符串插值
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
1.7 Object类型
每个Object实例都有如下属性和方法。
- constructor:用于创建当前对象的函数。
- hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属性。要检查的属性名必须是字符串(如o.hasOwnProperty(“name”))或符号。
- isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。
- propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用(本章稍后讨论的)for-in语句枚举。 与hasOwnProperty()一样,属性名必须是字符串。
- toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。