JS数据类型
- 1. Undefined类型
- 2. Null类型
- 3. Boolean类型
- 4. Number类型
- ① 浮点值
- ② 值的范围
- ③ NaN
- ④ 数值转换
- 5. BigInt类型
- ① 类型信息
- ② 运算
- ③ 比较
- 6. String类型
- ① 字符字面量
- ② 字符串的特点
- ③ 转换为字符串
- ④ 模板字面量
- ⑤ 字符串插值
- ⑥模板字面量标签函数
- ⑦ 原始字符串
- 7. Symbol类型
- ① 符号的基本用法
- ② 使用全局符号注册表
- ③ 使用符号作为属性
- ④ 常用内置符号
- ⑤ Symbol.asyncIterator (待更)
- ⑥ Symbol.hasInstance (待更)
- ⑦ Symbol.isConcatSqreadable (待更)
- ⑧ Symbol.iterator(待更)
- ⑨ Symbol.match (待更)
- ⑩ Symbol.replace (待更)
- ⑪ Symbol.search (待更)
- ⑫ Symbol.species (待更)
- ⑬ Symbol.split(待更)
- ⑭ Symbol.toPrimitive(待更)
- ⑮ Symbol.toStringTag(待更)
- 8. Object类型
- typeof操作符
ECMAScript有7种简单数据类型:Undefined、Null、Boolean、Number、BigInt、String、和 Symbol;1种复杂数据类型:Object。
1. Undefined类型
该类型只有一个值,就是undefined。当使用var或let声明了变量但没有赋值时,就相当于给变量赋值了undefined值。
对于未声明的变量,只能执行一个有用的操作,就是对它调用typeof。无论是声明还是未声明,typeof 返回的都是字符串"undefined"。
2. Null类型
Null类型只有一个值,即特殊值null。null值表示一个空对象指针(所以typeof null会返回object)。
在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。
console.log(null == undefined); // true
console.log(null === undefined); // false
3. Boolean类型
Boolean有两个字面量:true 和 false。(布尔值 true 和 false是区分大小写的,True 和 False是有效的标识符)
其他类型转Boolean可以调用Boolean()
,下表总结了不同类型与布尔值之间的转换规则:
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 非空字符串 | “”(空字符串) |
Number | 非零数值(包括无穷值) | 0、NaN |
Object | 任意对象 | null |
Undefined | N/A(不存在) | undefined |
Boolean([]) // true
Boolean({}) // true
(if等流控制语句会制动执行其他类型值到布尔值的转换)
4. Number类型
Number类型使用IEEE 754格式表示整数和浮点数(即双精度)。不同的数值类型有对应不同的数值字面格式:
- 十进制:直接表达即可;
- 八进制:以
0
开头,如 075;当字面量中包含的数字超过了应有范围,就会忽略前面的 0,后面的数字序列会被当做十进制处理,如 08 就是十进制的 8。(八进制字面量在严格模式下是无效的,会导致js引擎抛出语法错误。ECMAScript 2015或ES6中的八进制以0o
开头;严格模式下0
会被视为语法错误,如果要表达八进制值,应该使用0o
) - 十六进制: 以
0x
开头。
(使用八进制和十六进制格式创建的数值在所有数学操作中都会被视为十进制)
console.log(010 + 010) // 16
console.log(0x10 + 0x10) // 32
由于js保存数值的方式,在实际中可能存在正零(+0)或负零(-0),但它们在所有情况下都被认为是等同的。
(+0) === (-0) // true
① 浮点值
- 要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。(ECMAScript总是想方设法把值转换为整数。在小数点后面没有数字的情况下,数值就会变成整数。如果数值本身是整数,只是小数点后面跟着 0,那么它也会被当成整数。)
1.0 + 1.0 // 2
- 科学计数法:3.125e-17、2e7等(e前为系数,e后为要乘以 10 的几次方幂)。
- 注意: 由于浮点值的精度是有限的,所以在计算中不要去判断两个浮点数的和是不是等于另一个浮点数,
不要去测试某个特定的浮点数
,如0.1 + 0.2 == 0.3 // false
② 值的范围
- 由于内存的限制,ECMAScript并不支持表示这世界上所有的数值。ECMAScript可以表示的最小值保存在
Number.MIN_VALUE
中,可以表示的最大值保存在Number.MAX_VALUE
. - 如果数值超出了JS可以表示的范围,那么这个数会自动转换为一个特殊的值
Infinity
。任何无法表示的负数以-Infinity
(负无穷大,可用Number.POSITIVE_INFINITY
取得),任何无法表示的正数以Infinity
(正无穷大,可用Number.NEGATIVE_INFINITY
取得)表示。 - 要确定一个数是不是有限大(即介于js能表示的最小值和最大值之间),可以用
isFinite()
函数(返回false为无穷值,返回true为非无穷值)。
③ NaN
有一个特殊的值叫 NaN
,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。
console.log(0/0); // NaNconsole.log(-0/+0); // NaNconsole.log(5/0); // Infinityconsole.log(5/-0); // -Infinity
- 任何涉及
NaN
的操作始终会返回NaN
NaN
不等于NaN
在内的任何值isNaN()
函数可以判断传入参数是否为数值
console.log(isNaN(NaN)); // trueconsole.log(isNaN(10)); // false,10是数值console.log(isNaN("11")); // false,可以转换为数值11console.log(isNaN("hsy")); // true,不可以转换为数值console.log(isNaN(true)); // false,可以转换为数值1
④ 数值转换
Number()
:规则如下
类型 | 规则 |
---|---|
Boolean | true转换为1,false转换为0 |
Number | 直接返回 |
null | 返回0 |
undefined | 返回NaN |
String | 如果字符串包含数值,数值前面带加减号的情况,则会被转换为一个十进制的数值(会忽略前面的0); 如果字符串包含有效的浮点值格式,则会被转换为相应的浮点值(会忽略前面的0); 如果字符串包含有效的十六进制格式,则会被转换为该十六进制对应的十进制整数值; 如果是空字符串,则返回0; 其他情况返回NaN。 |
Object | 调用valueOf() 方法,并按照上述规则转换返回值。如果转换的结果是NaN,则调用toString() 方法,在按照转换字符串的规则转换 |
一元加操作符遵循与Number()相同的转换规律
1 + 1 // 2
1 + '1' // '11' 一元加操作符有隐形转换字符串类型的特性
'1' + '1' // '11'
parseInt()
:
专注于字符串是否包含数值的模式。字符串前面的空格会被忽略,从第一个非空字符开始转换。
如果第一个字符不是数值字符、加号、减号,立即返回NaN(空字符串也会返回NaN)。
如果第一个字符是数值字符、加号、减号,则会继续依次检测每个字符,直至字符串末尾或碰到非数值字符串。如“123hsy”会被转换为123,“22.7”会被转换为22。
parseInt()
也能识别不同进制格式。但如果字符串以“0”开头,且紧跟着数值字符,在非严格模式下会被某些实现解释为八进制整数。
不同数值格式很容易混淆,因此parseInt()
可以传入第二个参数,用于指定底数(进制数),当提供了进制参数时,进制格式前面的“0x”可以省略。如parseInt(‘AF’,16)返回175。建议始终传入第二个进制参数
Number('010') // 10
parseInt('010') // 10
parseInt('010', 8) // 8
parseInt('010hsy', 8) // 8
parseInt('010.1') // 10
parseInt('0x010') // 16
parseFloat()
:
与parseInt()
类似。但其第一次解析到的小数点是有效的。它始终忽略字符串开的的零,十六进制数值始终会返回0。它只能解析十进制,但能识别所有浮点格式(包括科学计数法)。如果字符串表示整数(没有小数点或小数点后面只有零),则会返回整数(js总是想方设法地把数转化为整数)。
5. BigInt类型
js中Numberr类型只能安全的表示-253+1 和 253-1 任何超出此范围的整数值都可能失去精度。BigInt 是一种内置对象,它提供了一种方法来表示超出 [-253+1, 253-1] 范围的整数。BigInt 可以用任意精度表示整数。
可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数 BigInt()(但不包含 new 运算符)并传递一个整数值或字符串值。
const theBiggestInt = 9007199254740991n;const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991nconst hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991nconst hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991nconst hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111",
);
// ↪ 9007199254740991n
- BigInt 不能用于 Math 对象中的方法;不能和任何 Number 实例混合运算,两者必须转换成同一种类型。
- 在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。最好Number和BigInt不要互相转换
① 类型信息
typeof 1n === "bigint"; // true
typeof BigInt("1") === "bigint"; // truetypeof Object(1n) === "object"; // true
② 运算
- 以下操作符可以和 BigInt 一起使用: +、*、-、**、%。除 >>> (无符号右移)之- 外的 位操作 (en-US) 也可以支持。因为 BigInt 都是有符号的, >>> (无符号右移)不能用于 BigInt。
- 为了兼容 asm.js,BigInt 不支持单目 (+) 运算符。
- 当使用 BigInt 时,带小数的运算会被取整。
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// ↪ 9007199254740991nconst maxPlusOne = previousMaxSafe + 1n;
// ↪ 9007199254740992nconst theFuture = previousMaxSafe + 2n;
// ↪ 9007199254740993nconst multi = previousMaxSafe * 2n;
// ↪ 18014398509481982nconst subtr = multi – 10n;
// ↪ 18014398509481972nconst mod = multi % 10n;
// ↪ 2nconst bigN = 2n ** 54n;
// ↪ 18014398509481984nbigN * -1n
// ↪ –18014398509481984nconst expected = 4n / 2n;
// ↪ 2nconst rounded = 5n / 2n;
// ↪ 2n, not 2.5n
③ 比较
BigInt 和 Number 不是严格相等的,但是宽松相等的。
0n === 0;
// ↪ false0n == 0;
// ↪ true
6. String类型
String字符串类型表示零个或多个16位Unicode字符序列。可用单引号、双引号或反引号标示。
① 字符字面量
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 换页 |
\xnn | 以十六进制编码nn表示的字符(其中n为十六进制数字) |
\unnnn | 以十六进制编码的Unicode字符(其中n为十六进制数字) |
字符串的长度可以通过length属性
获取,这个属性返回字符串中16位字符的个数。如果字符串中包含双字节字符,那么length属性返回的值可能不是准确的字符数。
② 字符串的特点
ECMAScript中的字符串是不可变的,一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量。
③ 转换为字符串
toString()
:可用于数值、布尔值、对象和字符串值。null 和 undefined 值没有该方法。在对数值调用时,可以接收一个底数传参,即以什么底数来输出数值的字符串表示。String()
:如果不确定一个值是不是null 或 undefined ,可以使用该方法。如果值有toString()方法,则调用该方法(不传参)并返回结果;如果值是null,返回“null”;如果值是undefined,返回“undefined”。- 用加号操作符给一个值加上一个空字符串"",也可以将其转换为字符串。
④ 模板字面量
用反引号`包裹,与使用单引号或双引号不用,模板字面量保留换行字符,可以跨行定义字符串。模板字面量会保持反引号内部的空格。
⑤ 字符串插值
字符串插值通过${}
在模板字面量里使用一个js表达式。所有插入的值都会使用toString()
强制转换为字符串,任何js表达式都可以用于插入值。
⑥模板字面量标签函数
模板字面量支持定义标签函数,而通过便签函数可以自定义插值行为。
let a = 6;let b = 9;function simpleTag(strings, ...expressions) {console.log(strings);for (const expression of expressions) {console.log(expression);}return 'foobar';}let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;// ["", " + ", " = ", ""]// 6// 9// 15console.log(taggedResult); // foobarfunction zipTag(strings, ...expressions) {return strings[0] + expressions.map((e, i) => `${e}${strings[i + 1]}`).join('');}let taggedResult2 = zipTag`${ a } + ${ b } = ${ a + b }`;console.log(taggedResult2); // 6 + 9 = 15
⑦ 原始字符串
使用模板字面量可以直接获取原始的模板字面量内容,而不是被转换后的字符表示。为此可以使用磨人的String.raw
标签函数。
7. Symbol类型
符号是原始值,且符号实例是唯一、不可变的 。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。符号就是用来创建唯一记号,进而作用非字符串形式的对象属性。
① 符号的基本用法
符号需要使用 Symbol()
函数初始化。
let sym = Symbol();
console.log(typeof sym); // symbol
调用 Symbol()
函数时,可以传入一个字符串作为对符号的描述,将来可以通过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全没有关系。
let sym1 = Symbol('foo');
let sym2 = Symbol('foo');
console.log(sym1 == sym2); // false
符号没有字面量语法。
Symbol()
函数不能与new关键字一起作为构造函数使用。
let myBoolean = new Boolean();
console.log(typeof myBoolean); // "object"let myString = new String();
console.log(typeof myString); // "object"let myNumber = new Number();
console.log(typeof myNumber); // "object"let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor
② 使用全局符号注册表
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,使用 Symbol.for()
在全局符号注册表中创建并重用符号。
let fooSymbol = Symbol.for('foo');
console.log(typeof fooSymbol); // symbol
Symbol.for()
对没分字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运行时注册表,发现不存在对应符号,就会生成一个新符号实例并添加到注册表中。后续使用相同字符串的调用会同样检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
let fooSymbol = Symbol.for('foo'); // 创建新符号
let otherFooSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooSymbol === otherFooSymbol); // true
即使使用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()
定义的符号也并不相等。
let fooSymbol = Symbol.for('foo');
let otherFooSymbol = Symbol('foo');
console.log(fooSymbol === otherFooSymbol); // false
全局注册表中的符号必须使用字符串来创建,因此作为参数传给Symbol.for()
的任何值都会被转换为字符串。注册表中使用的键同时也会被用作符号描述。
let mySymbol = Symbol.for();
console.log(mySymbol); // Symbol(undefined)
可以使用 Symbol.keyFor()
来查询全局注册表,这个方法接收符号,返回该全局符号对应的字符串键。如果查询的不是全局符号,则返回undefined。如果传给 Symbol.keyFor()
的不是符号,则该方法抛出TypeError。
let mySymbol1 = Symbol.for('foo');
console.log(Symbol.keyFor(mySymbol1)); // foolet mySymbol2 = Symbol('foo');
console.log(Symbol.keyFor(mySymbol2)); // undefinedSymbol.keyFor(123); // TypeError: 123 is not a symbol
③ 使用符号作为属性
凡是可以使用字符串或数值作为属性的地方,都可以使用符号。这包括了对象字面量属性和Object.defineProperty()
/ Object.defineProperties()
定义的属性。对象字面量只能在计算属性语法中使用符号作为属性。
let s1 = Symbol('foo'),s2 = Symbol('bar'),s3 = Symbol('baz'),s4 = Symbol('qux');let o = {[s1]: 'foo val'
};
console.log(o); // { [Symbol(foo)]: 'foo val' }Object.defineProperty(o, s2, {value: 'bar val'});
console.log(o); // { [Symbol(foo)]: 'foo val', [Symbol(bar)]: 'bar val' }Object.defineProperties(o, {[s3]: {value: 'baz val'},[s4]: {value: 'qux val'}
})
console.log(o); // { [Symbol(foo)]: 'foo val', [Symbol(bar)]: 'bar val', [Symbol(baz)]: 'baz val', [Symbol(qux)]: 'qux val' }
类似于 Object.getOwnPropertyNames()
返回对象实例的常规属性数组, Object.getOwnPropertySymbols()
返回实例的符号属性数组。这两个方法的返回值彼此互斥。 Object.getOwnPropertyDescriptors()
会返回同时包含常规和符号属性描述符的对象。 Reflect.ownKeys()
会返回两种类型的键。
let s1 = Symbol('foo'),s2 = Symbol('bar');let o = {[s1]: 'foo val',[s2]: 'bar val',baz: 'baz val',qux: 'qux val'
};console.log(Object.getOwnPropertyNames(o)); // [ 'baz', 'qux' ]
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol(foo), Symbol(bar) ]
console.log(Object.getOwnPropertyDescriptors(o)); // { baz: {...}, qux: {...}, [Symbol(foo)]: {...}, [Symbol(bar)]: {...}}
console.log(Reflect.ownKeys(o)); // [ 'baz', 'qux', Symbol(foo), Symbol(bar) ]
④ 常用内置符号
在提到ECMAScript规范时,经常会引用符号在规范中的名称,前缀为 @@
。 比如@@iterator指的是Symbol.iterator。
⑤ Symbol.asyncIterator (待更)
⑥ Symbol.hasInstance (待更)
⑦ Symbol.isConcatSqreadable (待更)
⑧ Symbol.iterator(待更)
⑨ Symbol.match (待更)
⑩ Symbol.replace (待更)
⑪ Symbol.search (待更)
⑫ Symbol.species (待更)
⑬ Symbol.split(待更)
⑭ Symbol.toPrimitive(待更)
⑮ Symbol.toStringTag(待更)
8. Object类型
js中万物皆对象
对象其实就是一组数据和功能的集合。每个Object对象实例都有以下属性和方法:
constructor
:用于创建当前对象的函数。hasOwnProperty(propertyName)
:用于判断当前对象实例(不是原型)上是否存在给行的属性。要检查的属性名必须是字符串。isPrototypeOf(object)
:用于判断当前对象是否为另一个对象的原型。propertyIsEnumerable(propertyName)
:用于判断给定的属性是否可以使用for-in语句枚举。要检查的属性名必须是字符串。toLocaleString()
:返回对象的字符串表示,改字符串反映对象所在的本地执行环境。toString()
:返回对象的字符串表示。valueOf()
:返回对象对应的字符串、数值、或布尔值表示。通常与toString()的返回值相同。
typeof操作符
返回值:
"undefined"
:表示值未定义;"boolean"
:表示值为布尔值;"string"
:表示值为字符串;"number"
:表示值为数值;"object"
:表示值为对象(而不是函数)或null;"function"
:表示值为函数;"symbol"
:表示值为符号
调用 typeof null 返回的是"boject",这是因为特殊值null被认为是一个空对象的引用。