前端笔记 ---ES 新特性与 TypeScript、JS 性能优化

ES新特性
首先了解一下什么是ES

ES(ECMAScript),具体背景什么的就不介绍了,需要记住ES是JS(JavaScript)的一种语法规范,换句话说,ES是JS的规范,JS是ES的一种实现

ES只提供基本语法,所以只停留在语言层面

ES2015(ES6)
ES2015在2015年6月发布,后续简称ES6

ES6主要为了解决以下四类问题
1.解决原有语法不足或问题
2.对原有语法进行增强
3.全新的方法,对象或功能
4.全新的数据结构和数据类型

1.let const var

let const是ES6中新增的声明变量的方法

1.var,let声明的都是变量
2.var存在变量提升,可以先调用后声明,let不存在变量提升,只能先声明后调用,所以存在暂时性死区
3.var只有全局作用域和局部作用域,let存在块级作用域,可以通过let声明变量的方式解决闭包的问题
4.var声明的变量可以重复声明,let不允许重复声明相同名称的变量
5.Const与let的区别是let可修改const不可修改(基本数据类型,对象不可修改指针),其他一致

暂时性死区:
在let或const定义之前的块级作用域内,不允许调用未定义的变量

个人理解,暂时性死区是let const这两种变量声明方式不存在变量提升的表现

console.log(a) //报错
const a = 0

2.数组解构

const arr = ['foo','bar','guo']
const [foo, ...arg] = arr
const [, , foo] = arr

3.对象解构
通过对应Object中的key值来解构,若外部定义了与Object同名的key值变量,可以修改提取名字 Const { name : objName }

4.模板字符串

str,${str}` 可自动换行,可通过${str}拼接字符串,js代码执行结果

5.字符串扩展方法
Include() startsWith() endsWith()

6.参数默认值 function (bar, enable = true) 只能出现在末尾
7.剩余参数 ...args 只能出现在末尾
8....也可以用来展开剩余数组,ES6之前是使用apply()实现
9.箭头函数 => 不会改变this指向
10.Proxy

new Proxy(person, {
get(target,property){
return property in target ? target[property] : undefined
set (target, property, value) {
Target[property] = value
相比于Object.defineProperty
1.proxy可以扩展更多的方法调用
2.Proxy对于数组对象的监视更好
3.Proxy是以非侵入的方式监管了对象的读写
16.Set 去重new Set(arr)
17.Map
Map类型相比Object类型的区别就是,Map类型可以将任意类型的数据作为key值进行存储,Object只能使用string作为key,不是string类型的自动转换成string作为key值

18.Symbol
用来为对象添加独一无二的key 将Symbol类型作为key值添加到Object类型中时,无法通过遍历的方式去获取,可以通过Object.getOwnPropertySymbols来获取,获取的结果全是Symbol类型的

19.For of
一个可以遍历所有类型的循环方式

20.Iterator
我这里就不过多讲了(毕竟我是个菜鸟)

TypeScript
TypeScript是JavaScript的超集,用来解决JavaScript弱类型和动态语言的问题

判断类型(: string|number|bollean|...)

可以用作方法后面,定义方法的返回值,若没有返回值, : void

数组类型:

let list: number[] = [1, 2, 3];
// ES5:var list = [1,2,3];
let list: Array<number> = [1, 2, 3]; // Array<number>泛型语法
// ES5:var list = [1,2,3];
enum Direction {
  NORTH = 0,
  SOUTH,
  EAST,
  WEST,
let dir: Direction = Direction.NORTH;
///声明的枚举类型中的数据会自增++,可以定义指定数据,不定义默认为0开始

类型断言:通知编译器我确定这个变量的类型为什么,避免编译器报错

let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; //或者通过as let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; Interface 约束了实现该接口的类型和需要定义的内容 通过implements去实现

访问修饰符 Public 默认的,可以不写,可以被外部访问 Protected 受保护的,可以被子类访问,不可被外部访问 Private 私有的,不可以被外部访问,只能在当前类中访问

抽象类abstract class
只能被继承不能被new实例化

通过在方法名后面<T>并在对应不确定参数类型的参数后面: T 来实现
某些npm包中不包含ts的类型声明的相关代码,需要通过npm下载@type 对应的资源文件

JavaScript性能优化
内存:表示一片可操作性的空间 内存管理 开发者主动申请空间 => 使用空间 => 释放空间

声明变量 let 变量的读写 变量= null
JavaScript中的垃圾:
对象不再被引用
对象不能从根上访问到时
JavaScript的可达对象:可以访问到的对象(引用,作用域链)
标准是从根上出发是否能被找到
JavaScript的根可以理解为全局变量对象
程序中不再使用的对象 程序中不能再访问到的对象

GC是一种机制,垃圾回收器完成具体的工作 工作内容是查找垃圾,释放空间,回收空间 算法就是工作时查找和回收所遵循的规则、

常见的GC算法

引用计数算法

核心思想:设置引用数,判断当前引用数是否为0
引用计数器:通过监测引用关系,对计数器+-,为0时回收
1.发现垃圾立即回收
2.最大限度减少程序的暂停
1.无法回收循环引用对象
2.时间开销大

标记清除算法

核心思想:分标记和清除两个阶段完成
遍历所有对象找标记活动对象
遍历所有对象清除没有标记的对象
回收相应空间
解决对象循环引用无法回收的问题
不会立即回收垃圾对象
空间碎片化
当可达对象分隔了两个无法直接可达的对象时,标记清除算法会将分隔的两个对象的域放入到空闲列表中当有新的声
明需要内存空间的时候,如果内存大小与分隔的两个对象中的空间匹配,可直接使用,若大小不完全匹配,
会造成空间碎片化

标记整理算法

核心思想:标记清除算法的增强
会先执行整理,移动对象位置,在进行标记清除算法的操作
减少碎片化空间
不会立即回收垃圾对象
主流JavaScript执行引擎,即时编译,内存设限(64位:不超过1.5G 32位:不超过800MB)

V8垃圾回收策略

回收的是堆中的对象数据
1.采用分代回收的思想
2.内存分为新生代和老生代
3.针对不同算法采用不同算法

V8常用GC算法

1.分代回收
2.空间复制
3.标记清除
4.标记整理
5.标记增量

新生代对象的回收
V8将内存空间分为两部分,小空间用于存储新生代对象(32M | 16M) 新生代对象指的是存活时间较短的对象

回收过程采用复制算法+标记整理算法
新生代内存区分为两个等大小的空间
使用空间From 空闲空间To
活动对象存储于From空间中
标记整理后将活动对象拷贝至To中
From与To交换空间完成释放

注意: 拷贝过程可能出现晋升(将新生代对象移动至老生代对象) 如何判断晋升: 1.一轮GC后还存活的新生代对象需要晋升 2.To空间使用率超过25%

老生代对象的回收
存放在右侧(1.4G | 700MB) 老生代对象指的是存活时间较长的对象

主要采用标记清除+标记整理+增量标记算法
首先使用标记清除完成垃圾回收
采用标记整理进行空间优化
采用增量标记进行效率优化
新生代区域垃圾回收使用空间换时间
老生代区域垃圾回收不适合复制算法

performance

GC的目的是为了实现内存空间的良性循环
时刻关注才能确定是否合理
performance提供多种监控方式
通过performance时刻监控内存
打开浏览器输入目标网址
进入开发人员工具面板,选择性能
开启录制功能,访问具体页面
执行用户行为,一段时间后停止录制
分析界面中记录的内存信息

内存问题的体现

1.页面延迟加载或经常性暂停 (频繁垃圾回收) 2.页面出现持续性糟糕的性能 (内存膨胀) 3.随着时间加长,页面性能越来越差 (内存泄漏)

界定内存问题的标准

内存泄漏:内存使用持续升高
内存膨胀:在多数设备上都存在性能问题
频繁垃圾回收:通过内存变化图分析

监控内存的几种方式

1.浏览器任务管理器 (shift+esc)
2.Timeline时序图记录
3.堆快照查找分离DOM
4.判断是否在频繁垃圾回收
1.慎用全局变量
2.缓存全局变量
3.通过原型对象添加附加方法
4.慎用闭包
5.避免属性方法使用
6.for循环优化
7.选择最优的循环方式
8.文档碎片优化节点添加
9.克隆优化节点操作