JavaScript 相关概念
数据类型
基本:number, string, boolean, undefined, null, symbol, bigint
引用:object
堆栈区别
栈
空间小、效率高
存储大小固定
可以直接读取
在定义时就已经分配好了空间
堆
空间大,效率低
存储大小不固定
通过引用读取
Map vs Object
意外的键
Map默认情况不包含任何键。只包含显式插入的键。
一个Object有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
键的类型
一个Map的键可以是任意值,包括函数、对象或任意基本类型。
键的顺序
Map中的 key 是有序的。因此,当迭代的时候,一个Map对象以插入的顺序返回键值。
一个Object的键是无序的注意:自ECMAScript 2015规范以来,对象_确实_保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。
Size
Object的键值对个数只能手动计算
迭代
迭代一个Object需要以某种方式获取它的键然后才能迭代。
性能
在频繁增删键值对的场景下表现更好。
在频繁添加和删除键值对的场景下未作出优化。
Set, Map, WeakSet, WeakMap
Set
成员不能重复;
只有键值,没有键名,有点类似数组;
可以遍历,方法有add、delete、has
WeakSet
成员都是对象(引用);
成员都是弱引用,随时可以消失(不计入垃圾回收机制)。可以用来保存 DOM 节点,不容易造成内存泄露;
不能遍历,方法有add、delete、has;
Map
本质上是键值对的集合,类似集合;
可以遍历,方法很多,可以跟各种数据格式转换;
WeakMap
只接收对象为键名(null 除外),不接受其他类型的值作为键名;
键名指向的对象,不计入垃圾回收机制;
不能遍历,方法同get、set、has、delete;
弱引用
不会被垃圾回收考虑,加入一个对象只有被一个弱引用
,那么就会直接把它清除掉。
Arguments
在js中,我们在调用有参数的函数时,当往这个调用的有参函数传参时,js会把所传的参数全部存到一个叫arguments的对象里面。它是一个类数组数据
instanceof
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
手动实现
数组去重
使用 Set
使用 indexOf
迭代处理
null & undefined
undefined
undefined 一般不会显式地赋值,表示最原始、自然地状态
下列四种情况会出现 undefined
声明了一个变量,但没有赋值
访问对象上不存在的属性
函数定义了形参,但没有传递实参
使用 void 对表达式求值
null
null 有自己的类型,但是 type of null 会返回 Object
类数组 vs 数组
转换方法
使用 Array.from()
内存泄漏情况
意外的全局变量;
闭包;
未被清空的定时器;
未被销毁的事件监听;
DOM 引用;
Object
Object.create()
**Object.create()
**方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
可以通过 Object.create()
来实现继承。
Object.create(null)
创建出来的对象不是 Object 的子类
Object.assign()
可以将一个对象复制到另一个对象,会覆盖重名属性。
Object.is()
用来比较两个值是否严格相等,和 === 逻辑基本相似
Object.setPrototypeOf() Object.getPrototypeOf()
设置 & 获取原型
Object.entries()
返回一个对象的键值对
Object.keys() Object.values()
返回一个数组,包含所有 keys / values
Symbol
为解决对象属性重名的问题,在 ES5 之前,对象属性只能使用 string
Symbol 用来标识独一无二的值
Symbol 不能 new ,因为他不是个对象
对象中以 symbol 为 key 的属性不能被 for...in, for...of 遍历,但是可以使用 Object.getOwnPropertySymbols() 来获得所有 symbol 为 key 的属性。
delete 操作符
delete
操作符用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放。
delete 删除数组,长度不变,元素变为 undefined
如果一个属性是用 var 创建的(其实他挂载在 window 下面),那么不能被delete
ES6 新增扩展
箭头函数 vs 普通函数
箭头函数的 this 指向在定义时就确定下来的
箭头函数不能通过 call,bind,apply 改变 this 指向
不能作为构造函数使用
没有原型 prototype
不能用作 Generator 函数
没有 arguments
String 扩展
加强对 Unicode 支持
字符串遍历
repeat() 等方法
模板字符串
RegExp
构造函数第一个参数是正则表达式,指定第二个参数不再报错、u修饰符、y修饰符、s修饰符。
Number
二进制和八进制的表示:0bxxxx, 0oxxx
新方法 parseInt(), parseFloat()
Number.EPSILON(常数e),Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTERGER
Math 的一些新方法
Function
函数默认值
rest 参数,rest 参数必须放在最后
函数内部严格模式
name 属性
Array
扩展运算符,可以理解成 rest 参数的**逆运算**
Proxy & Reflect
Proxy
const proxy = new Proxy(target, handler),target 是被代理的对象,handler 是配置参数
this 指向问题,被代理对象中的 this 会指向代理对象中的 this
Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers (en-US)的方法相同。Reflect
不是一个函数对象,因此它是不可构造的。
Class
Class 必须用 new 来实例化,而函数是可以不需要的
静态方法 & 静态属性
继承
子类的构造函数必须调用 super 方法,来获得 this 对象,因为子类没有 this,需要改造父类的this
ES5 原型继承 vs ES6 Class 继承
原型继承不会继承父类的属性;而 Class 继承可以
Module
CommonJS:用于 Node.js
AMD:用于浏览器
ES6 将一个文件即视为一个模块,通过 export 暴露,再使用 import 导入
export
支持导出:变量,函数,类
export 不能处于块级作用域内
import
export default
Common.js
Common.js 加载时同步的,只有加载完成后,才能继续执行
Common.js vs ES6 Module
ES6 是编译时引入的,而 Common.js 是运行时引入的
ES6 输出的模块是引用,而 Common.js 是拷贝
ES6 可以引用 Common.js,但反之不可
Iterator
结构类似于一个带头结点的 LinkedList
Iterator 接口部署在 Symbol.iterator
属性上
上述 obj 就实现了 Iterator 接口,他是可迭代的
for...in 遍历属性
for...of 消费 iterator
... 扩展运算符
函数调用,将数组转换为一个个参数
深拷贝数组,合并数组
Math.max(), [].push()
单线程
Q: JavaScript 为什么使用单线程?
A: JS主要实现用户与浏览器的交互,以及操作DOM,使用单线程会避免许多问题。如,一个线程修改了 DOM 元素,另一个又要删除这个 DOM 元素,这时候会产生冲突。
线程:CPU 调度的最小单位
进程:资源分配的最小单位
TDZ
在代码块内,使用 let, const 声明之前,该变量都不可用
TDZ 的本质是:只要进入某一作用域,在声明变量前,该变量都不可用
闭包
函数和函数能访问到的变量就叫闭包
可以让内层函数访问到外层函数内容
避免使用全局变量
Generators / yield
可以控制函数的执行,yield 暂停函数,next() 启动执行
XHR 的 readyState
初始化
开始发送请求
请求发送完成
开始读取服务器相应
读取完成
== ===
==:比较数值是否相等
===:比较数值是否相等之外,还比较类型
NaN 和谁都不等,甚至包括自己,只能用 isNaN判断
一个字符串 == 数字时候,将字符串转换成数字
对象的比较不同于值比较,比较他们的引用
隐式转换
any + 字符串 => 字符串
bool + 字符串/数字 => 1 + 字符串/数字
undefined + 数字 => NaN + 数字 = NaN
null + 数字 => 0 + 数字
Examples
Last updated