js 中的基本类型和隐式转换
基本类型
在 JavaScript 中,基本类型(基本数值、基本数据类型)是一种既非对象也无方法或属性的数据。有 7 种原始数据类型:
- string
- number
js
它能够存储 2^-1074(Number.MIN_VALUE)和 2^1024(Number.MAX_VALUE)之间的正浮点数;
以及 -2^-1074 和 -2^1024 之间的负浮点数;
但是它仅能安全地存储在 -(2^53 − 1)(Number.MIN_SAFE_INTEGER)到
2^53 − 1(Number.MAX_SAFE_INTEGER)范围内的整数。
超出这个范围,JavaScript 将不能安全地表示整数;
相反,它们将由双精度浮点近似表示。
可以使用 Number.isSafeInteger() 检查一个数是否在安全的整数范围内。
- bigint
js
BigInt 类型在 Javascript 中是一个数字的原始值,它可以表示任意大小的整数。
使用 BigInt,你可以安全地存储和操作巨大的整数,
甚至超过 Number 的安全整数限制(Number.MAX_SAFE_INTEGER)。
let bigNumber = BigInt("1000000000000000000000");
let bigNumberString = bigNumber.toString();
console.log(bigNumberString); // 输出 "1000000000000000000000"
- boolean
- undefined
- symbol
js
Symbol 是唯一并且不可变的原始值并且可以用来作为对象属性的键(如下)。
在某些程序语言当中,Symbol 也被称作“原子类型”(atom)。
***symbol 的目的是去创建一个唯一属性键,保证不会与其它代码中的键产生冲突。***
- null
所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。变量会被赋予一个新值,而基本类型不能像数组、对象以及函数那样被改变。
基本类型没有方法,但仍然表现得像有方法一样。当在基本类型上访问属性时,JavaScript 自动将值装入包装器对象中,并访问该对象上的属性。 例如,"foo".includes("f") 隐式创建了一个 String 包装对象,并在该对象上调用 String.prototype.includes()。这种自动装箱行为在 JavaScript 代码中是无法观察到的,但却是各种行为的一个很好的心理模型——例如,为什么“改变”基本类型不起作用(因为 str.Foo = 1 不是赋值给 str 本身的 Foo 属性,而是赋值给了一个临时包装器对象)。【间接证明 js 是弱类型语言】
引用类型
- Object
js
在计算机科学中,对象(object)是指内存中的可以被标识符引用的一块区域。
在 JavaScript 中,对象是唯一可变 (en-US)的值。
事实上,函数也是具有额外可调用能力的对象
数据类型typeof
返回值
类型 | typeof 返回值 | 对象包装器 |
---|---|---|
单元格 | 单元格 | 单元格 |
单元格 | 单元格 | 单元格 |
Null | "object" | N/A |
Undefined | "undefined" | N/A |
Boolean | "boolean" | Boolean |
Number | "number" | Number |
BigInt | "bigint" | BigInt |
String | "string" | String |
Symbol | "symbol" | Symbol |
隐式转换
+
运算符:如果运算对象是字符串,执行字符串串联;否则,执行数值相加;==
运算符:如果其中一个操作数是对象,另一个是基本类型,按此顺序使用对象的@@toPrimitive()
(以 "default" 作为提示),valueOf()
和toString()
方法将对象转换为基本类型。(这个基本类型转换与相加中使用的转换相同
看一些例子:
- 有类型转化的比较
js
"1" == 1; // true
1 == "1"; // true
0 == false; // true
0 == null; // false
0 == undefined; // false
0 == !!null; // true, 看看逻辑非运算符
0 == !!undefined; // true, 看看逻辑非运算符
null == undefined; // true
const number1 = new Number(3);
const number2 = new Number(3);
number1 == 3; // true
number1 == number2; // false
- 比较对象
js
const object1 = {
key: "value",
};
const object2 = {
key: "value",
};
console.log(object1 == object2); // false
console.log(object1 == object1); // true
- 比较字符串和 String 对象:请注意,使用构造的字符串 new String() 是对象。如果将其中之一与字符串文字进行比较,则该 String 对象将被转换为字符串文字并对其内容进行比较。但是,如果两个操作数都是 String 对象,则将它们作为对象进行比较,并且必须引用相同的对象才能进行比较
js
const string1 = "hello";
const string2 = String("hello");
const string3 = new String("hello");
const string4 = new String("hello");
console.log(string1 == string2); // true
console.log(string1 == string3); // true
console.log(string2 == string3); // true
console.log(string3 == string4); // false
console.log(string4 == string4); // true
- 比较数组和字符串
JS
const a = [1, 2, 3];
const b = "1,2,3";
a == b; // true, `a` converts to string
const c = [true, 0.5, "hey"];
const d = c.toString(); // "true,0.5,hey"
c == d; // true
运算符
- 可选链运算符
?.
:在引用为空 (nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。(可选链不能用于赋值)
js
const adventurer = {
name: "Alice",
cat: {
name: "Dinah",
},
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined
// !!!可选链不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
- 空值合并运算符
??
:空值合并运算符可以在使用可选链时设置一个默认值。
js
let customer = {
name: "Carl",
details: { age: 82 },
};
let customerCity = customer?.city ?? "暗之城";
console.log(customerCity); // “暗之城”