这里使用《JavaScript高级程序设计第四版》和MDN来做参考。
数据类型
JavaScript 是一种弱类型或者说动态语言。在程序运行过程中,类型会被自动确定。这也意味着你可以使用同一个变量保存不同类型的数据。
let a = true;
a = 1;
a = 'string'
复制代码
红宝书的数据类型跟MDN不一致,考虑到书籍的时效性,使用MDN作为标准记录。
最新的 ECMAScript 标准定义了 9 种数据类型:
- 6种原始类型:
- undefiend
typeof instance === "undefined"
- Boolean
typeof instance === "boolean"
- Number
typeof instance === "number"
- String
typeof instance === "string"
- BigInt
typeof instance === "bigint"
- Symbol
typeof instance === "symbol"
- undefiend
- null
typeof instance === "object"
null被认为是空对象的指针,所以返回object - Object
typeof instance === "object"
任何 constructed 对象实例的特殊非数据结构类型,也用做数据结构:new Object,new Array,new Map,new Set,new WeakMap,new WeakSet,new Date,和几乎所有通过 new keyword 创建的东西。 - Funtion 非数据结构,尽管 typeof 操作的结果是:
typeof instance === "function"
。这个结果是为 Function 的一个特殊缩写,尽管每个 Function 构造器都由 Object 构造器派生。
typeof操作符返回的值可能并不是我们想要的,有Object派生出来的结构类型可以使用instanceof操作符来判断、Array.isArray()、isNaN()等也提供了准确的判断。
类型补充说明
Number:
根据 ECMAScript 标准,JavaScript 中只有一种数字类型:基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(2^53 -1) 到 2^53 -1)。除了一般的number类型以外,+Infinity,-Infinity
和 NaN也被认为是number。在 ECMAScript 6 中,你也可以通过 Number.isSafeInteger()
方法还有 Number.MAX_SAFE_INTEGER
和 Number.MIN_SAFE_INTEGER
来检查值是否在双精度浮点数的取值范围内。 超出这个范围,JavaScript 中的数字不再安全了,也就是只有 second mathematical interger 可以在 JavaScript 数字类型中正确表现。
浮点数的内存空间是整数的两倍,所以ECMAScript总是会想方设法的把浮点数转成整数: let a = 1.0
会被当成整数处理。
浮点数的计算可能不准确。0.1 + 0.2 !== 0.3
NaN: NaN == NaN
和NaN === NaN
得到的都是false,我们通常用isNaN()来判断。
isNaN(xx)会尝试把xx转换为Number类型,如果不能成功,则会返回true。
isNaN(window) => true
isNaN(true) => false
true会被转换成Number类型的1,false则转成0isNaN('10') => false
isNaN('abc') => true
isNaN(10) => false
isNaN(undefiend) => true
BigInt
BigInt是通过在整数末尾附加 n 或调用构造函数来创建的。
const x = 2n ** 53n;
9007199254740992n
const y = x + 1n;
9007199254740993n
复制代码
Boolean
我们通常会使用if
语句来做条件判断,为了简写,if的条件通常都不会是Boolean类型的:
const a = {};
const b = 1;
const c = 'asfa';
if(a && b && c) ...
复制代码
如果if中的条件不是Boolean的话,会使用Boolean()转成Boolean类型。这里是一部分转换关系:
数据类型 | 结果true | 结果false |
---|---|---|
Boolean | true | false |
String | 非空字符串 | 空字符串 |
Number | 非0数值 | 0 |
Object | 任意对象和对象的延展数据结构 | null |
undefiend | — | undefiend |
类型声明
声明操作符有三种:var、let、const。也可以不适用操作符直接写。
不使用操作符
gg = 1
默认创建全局变量,不建议使用
var
旧时代的产物,但任然需要了解,可能再过10年依然有人在维护var的代码。
存在变量提升,作用域会穿透if,for,switch等语句块。不建议再使用。
let
声明的变量存在块级作用域,同一作用域无法再次声明。无法再次声明var过的变量。
需要注意的是,使用let声明变量,类似于一个IIFE的效果:
// 全局作用域下
let a = 1
var b = 1
window.a === undefined
window.b === 1
// 使用let类似于
(function(){
var a = 1;
})();
// 关于块级作用域比较常见的问题
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i); // 5个5
}, 0)
}
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i); // 01234
}, 0)
}
复制代码
const
跟let表现一致,多了一条:变量指向的内存地址无法被修改。如果是Object类型,只要不修改内存地址,可以做其他修改操作。
const a = 1;
a = 2; // VM6330:1 Uncaught TypeError: Assignment to constant variable.
a = '1'; // VM6330:1 Uncaught TypeError: Assignment to constant variable.
const b = [];
a.push(1); // 正常执行
const c = {name: 1};
c.name = 2; // 正常执行
复制代码