javaScript 为了方便dom稳定有序地渲染就被设计为单线程方式,不会存在性能消耗,更安全, 如果有比较耗时的任务存在,就会表现为假死状态,所以需要异步编程去执行一些任务,例如:ajax请求,也可以需要多线程任务环境执行 如:web worker
js 和webApi 按执行机制分为 宏任务和微任务
- 宏任务: script(整体代码) setTimeout setInterval I/O UI交互事件 postMessage MessageChannel setImmediate(Node.js 环境)
- 微任务 Promise Object.observe MutaionObserver process.nextTick(Node.js 环境)
宏任务:可以理解为当前执行堆栈中运行的任务 微任务:需要等待执行结果的任务
代码执行过程中 遇到需要等待执行的任务 将其放入消息队列中, 等当前执行堆栈任务执行完毕,event loop 开始起作用,执行微任务中的消息队列,直到消息队列清空,开始执行宏任务消息队列中的任务,直至清空,等待下一任务
放入消息队列中的任务,通过回调函数的方式执行,回调函数因为作用域中保留相关的作用域链,从而能找到相关的执行上下文,从而保证任务能够顺利进行
var a = []
for (var i = 0; i < 10; i++){
a[i] = function(){
console.log(i)
}
}
a[6]()解释: i 通过 var 声明为 全局变量,当循环执行完时所有 a(在全局执行上下文中被创建) 中的函数的作用域[[scope]]: 为EC(anonymous),循环执行完后全局执行上下文中的 i 变为10,当执行a中的函数时,函数的作用域链<匿名函数EC(anonymous),全执行上下文EC(G)>,顺着作用域,i在全局执行上下文中,此时循环早已执行完,所以结果 打印 10
var tmp = 123
if(true){
console.log(tmp)
let tmp
}解析: let 声明的变量存在提升(解析层面的创建,可能有不同理解,也可以简单的理解为不提升),但是确没有初始化值undefined, let 什么的变量只有在代码执行的时候才会赋值,所以此时会报语法错误:初始化错误,也就是暂时性死区,所以习惯性let 声明的变量放在执行代码最上面
var arr = [12, 34, 32, 89, 4]
// 解析, 使用扩展符
Math.max(...arr)- var 在函数外申明的变量为全局变量,函数内申明的为函数的局部变量,都存在提升, 可以重复声明
- let 和 const 声明的变量只能在声明后使用,声明语句中每次都会有一个独立的执行上下文保存数据,也就是有一个独立的作用域
- const 声明的变量不可更改(基本数据类型不能更改,引用数据类型不能改变引用地址),所以const 不能用在 for 循环声明中
var a = 10;
var obj = {
a: 20,
fn(){
seTimeout(()=>{
console.log(this.a)
})
}
}
obj.fn()解析: obj中的 fn 方法在被创建的之后[[scope]] EC(obj.fn), obj.fn 执行的时候,fn的执行上下文:<EC(obj.fn), EC(G)> fn中的函数体 字符串被解析,计时器中的 回调函数为箭头函数无没有this,只会继承obj.fn 中的this, EC(obj.fn)的this指向 obj, 所以在代码执行的时候, 只能在 obj 中查找a, 此时所以答应 20, 补充一下,此时若找不到a ,也不会寻着作用域链继续向上查找a,因为this 指向了obj, 只能在此对象上查找,所以找不到的结果就只能为 undefined, 这就是对象方法的特殊性
备注:箭头函数的影响
- 对象方法中
fn(){}为对象中函数的简易声明方法,和fn:()=>{}不同,前者中的this指向当前方法的对象,后者因箭头函数没有this, 只会继承执行上下文外层的this
Symbol生成的值为一个独一无二的值,用途可以有:
- 用作对象的属性模拟私有属性
- 扩展对象属性,防止属性名冲突
- 用作uuid?
浅拷贝和深拷贝都是对于引用类型的数值来说的 浅拷贝:将数据的引用地址全部或者部分指向新的变量 深拷贝:在堆内存中创建新的空间,存储复制来的数据,从而会有新的引用地址,创建新的空间需要通过 声明式或者构造式语法
- TypeScript 包含所有 JavaScript 的语法新特性,
- TypeScript基于JavaScript 引入了很多java 的类型系统,属于JavaScript的扩展
- TypeScript 在浏览器端需要编译成JavaScript,可向下兼容到ES3
优点:
- 可以渐进式学习
- 通过类型系统 提前警示类型问题,提高代码质量
- 方便管理大型项目 缺点:
- 需要一定的学习成本,比如接口,泛型,类,枚举等概念
- 从集成到构建需要一定学习成本,和一些库可能不兼容
优点:
- 引用计数为0时,立即回收最大限度减少程序暂停 缺点:
- 无法回收循环引用的对象
- 时间开销打(需要为每个数据进行计数)
在标记清除的过程中,会移动对象位置,形成连续的空间,防止空间碎片产生
- 回收过程采用复制算法+标记整理
- 新生代内存区分为两个等大的小空间
- 使用空间为 From, 空闲空间为To
- 活动对象存储于From 空间
- 标记整理后将活动对象拷贝至To
- From 与 To空间交换空间完成释放 回收新生代细节:
- 拷贝过程中可能出现晋升
- 晋升就是将新生代对象移动至老生代
- 一轮GC还存活的新生代对象 需要晋升
- 另外,To空间使用率超过25% 后需要晋升
在程序执行过程中自动判断在一些时机上对数据进行分段式标记,美执行一段时间就进行标记,代码执行完也就差不多完成了标记,从而减少垃圾回收的时间