一、数据类型、类型检测、类型转换
1. 数据类型:参考资料
-
基础类型(值类型):Null、Undefined、Symbol(es6)、Boolean、String、Number、Bigint(es10),在内存中占据固定大小,保存在栈内存中。
附:JavaScript 数据类型之 Symbol、BigInt
-
引用类型(复杂数据类型):Object(包括Function函数、Array数组、Date日期、RegExp正则表达式,特殊基本包装类型String、Number、Boolean,单体内置对象Global、Math等),引用类型的值是对象,保存在堆内存中,栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址。
2. 类型检测:参考资料
- typeof:① 对于基本类型,除null外均可返回正确结果,null返回为object类型;② 对于引用类型,除function一律返回object类型,function返回function类型。
- instanceof:能够区分Array、Object和Function,适合用于判断两个对象是否属于实例关系,无法判断一个对象实例具体属于哪种类型,也无法判断Number,Boolean,String等基本数据类型。
- constructor:函数F被定义时,JS引擎会为F添加prototype原型,并在prototype上添加constructor属性,并让其指向F的引用。ps: null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
参考资料
- Object.prototype.toString.call():可精准判断各种数据类型。
- Array.isArray():可判断数组
3. 类型转换:参考资料
- 强制转换(显式转换):Number()、parseInt()、String()、Boolean()
- 自动转换(隐式转换):自动转换为布尔、字符串、数值
二、var、let和const区别
1. 作用域
- var声明的变量既是全局变量,也是顶层变量,可以跨块访问, 但不能跨函数访问。
ps:顶层对象,浏览器环境指的是window对象
- let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
- const声明只读常量,使用时必须初始化,只能在块作用域里访问,一旦声明常量的值就不能改变。
const实际上保证的并不是变量的值不得改动,而是变量指向的内存地址所保存的数据不得改动:对于简单类型的数据,值就保存在变量指向的那个内存地址,因此等同于常量;对于复杂类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,并不能确保改变量的结构不变。
用var或let声明过变量,再用const声明同样会报错!!!
let /const/function会把当前所在的大括号(除函数之外)作为一个全新的块级上下文,应用这个机制,在开发项目的时候,遇到循环事件绑定等类似的需求,无需再自己构建闭包来存储,只要基于let的块作用特征即可解决
对于简单类型的数据,值就保存在变量指向的那个内存地址,因此等同于常量
2. 重复声明
- var允许在相同作用域内重复声明变量,后面声明的变量会覆盖前面的
- let和const在同一作用域不允许重复声明变量
3. 变量提升
- var声明的变量存在「变量提升」情况:变量可以在声明之前调用,值为undefined
console.log(a) //undefined
var a = 10
//在编译阶段,编译器会将其变成以下执行:
var a;
console.log(a);
a = 10;
4. 暂时性死区
- let、const 声明的变量存在「暂时性死区」:变量在声明前都不可用
var a = 10;
if(true){
a = 'abc'; // ReferenceError
let a;
}
// let
console.log(b) // Cannot access 'b' before initialization
let b = 10
// const
console.log(c) // Cannot access 'c' before initialization
const c = 10
三、浏览器EventLoop(事件循环)
- 什么是浏览器事件循环
- 为什么会出现事件循环
- 事件循环机制
- 浏览器事件循环应用场景
- 扩展:Node事件循环