ES 新特性与 TypeScript、JS 性能优化
ES2015
1、Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
使用:
const person = {}
cont personProxy = new Proxy(person, {
get(target, property) {
return property in target ? target[property] : 'default'
},
set() {}
})
2、Proxy对比defineProperty
Proxy相对于defineProperty更加强大,例如:
- proxy监听全对象,而defineProperty监听具体属性,需要指定
- defineProperty无法监听到属性新增和删除,而proxy可以
- defineProperty无法监听数组的变化
- proxy以非侵入式方式监听,而defineProperty不是
3、Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect
不是一个函数对象,因此它是不可构造的。
- 提供统一的对象操作Api
- 不能通过new,是静态方法类
- 具有13个方法(原本14个,淘汰一个)
Reflect.apply(target, thisArgument, argumentsList) // 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
Reflect.construct(target, argumentsList[, newTarget]) //对构造函数进行 new 操作,相当于执行 new target(...args)。
Reflect.defineProperty(target, propertyKey, attributes) //和 Object.defineProperty() 类似。如果设置成功就会返回 true
Reflect.deleteProperty(target, propertyKey) // 作为函数的delete操作符,相当于执行 delete target[name]。
Reflect.get(target, propertyKey[, receiver]) // 获取对象身上某个属性的值,类似于 target[name]。
Reflect.getOwnPropertyDescriptor(target, propertyKey) // 类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined.
Reflect.getPrototypeOf(target) // 类似于 Object.getPrototypeOf()。
Reflect.has(target, propertyKey) // 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.isExtensible(target) // 类似于 Object.isExtensible().
Reflect.ownKeys(target) // 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响).
Reflect.preventExtensions(target) // 类似于 Object.preventExtensions()。返回一个Boolean。
Reflect.set(target, propertyKey, value[, receiver]) // 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
Reflect.setPrototypeOf(target, prototype) // 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。
4、Symbol(符号)
- Symbol是新增的一种原数数据类型
- 主要作用是为对象添加一个独一无二的标识符(可以理解为key)
- 用Symbol模拟实现对象私有成员,避免、解决冲突
- 数据类型:number、string、function、bigInt、symbol、boolean、undefined、object
- 特殊类型:null,
JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object
5、类的继承 extends
-
在之前实现继承是通过原型的方式实现,现在可以通过class的extend可实现,内部实现上还是函数
-
由于class本质还是一个function 因此它就会拥有一个prototype属性,当new一个class时,会把class的porototype属性赋值给这个新对象的 proto属性
-
prototype是函数的一个属性,它是一个指针。对于构造函数来说,prototype是作为构造函数的属性。prototype也可以是一个对象,prototype是对象实例的原型对象。所以prototype即是属性,又是对象。在new一个对象时,可以理解为一个对象没有ptototype属性,所以把ptototype给一个对象的 proto
6、迭代器模式
- 提供统一的可迭代接口
- 语法层面上实现了此种模式
7、生成器
- 在方法前增加一个*号,则代表一个生成器函数
- 执行成功后返回的是一个对象
- 需要通过next方法进行继续执行
- 内部通过yield暂停
- 其次yield后的值会作为本次next的结果返回
- 同时会返回一个done的状态
- 应用场景:发号器
8、es2016
- includes方法:检测是否存在,且兼容NaN
- 指数运算符: **,如 2 ** 10
9、es2017
- object.values方法
- object.entry方法,key、valye数组的形式拿到对象的内容
- padStart,padEnd,如数字前补0
Typescript
概述
- ts是基于js之上的编程语言,解决js类型系统不足之处。
- 通过ts可提高代码的可靠程度
- ts是js的一个超集
- js是动态类型,ts是静态类型
- ts基于js添加了不少特性
ts作用域问题
- 变量默认在全局作用域,不允许重复
- 默认使用export {} 变成模块导出
ts类型
- Object 类型:函数、数组、对象
- Array 类型:Array, number[]
- 元祖类型:tuple types,可以理解为明确的类型、明确的长度的数据类型
- 枚举类型:enum,数字的是自动增加,字符串必须给定值,最终会变成双向的键值对
- 函数类型:
函数声明
1、形参类型限制
2、返回值类型
函数表达式
箭头函数式标明
- 任意类型:接受任意类型:any,属于动态类型
- 隐式类型推断:未声明类型,则会进行自动类型推断
- 类型断言:无法推断时,as关键词,尖括号,尖括号会和jsx冲突,建议使用as
接口
- 一种约定,一种规范
- interface进行定义 接口
- 形式为:key:类型
- 约定对象的结构,且必须实现接口定义的内容
- 可选成员:增加问好
- 只读成员:增加readonly,赋值后就不许再改了
- 任意成员:[x: types]: types
类
- 类用来描述一类具体事务的抽象特征
- 类的访问修饰符:private,public(默认的),proteted(受保护的)
- proteted:只允许在子类中使用
- private:只允许类的内部使用
- 只读属性:readonly,需要跟在修饰符后面
- 一个接口最好只限制一种能力,一个类可以实现多个接口,使用implements关键字,多个接口使用逗号分隔
性能优化
- 内存管理
- 垃圾回收与常见的GC算法
- V8引擎的垃圾回收
- performance工具
内存管理
- 内存:由可读写单元组成,表示一片可操作性的空间
- 管理:人为的去操作一片空间的申请、使用和释放
- 内存管理:开发者主动申请空间、使用空间、释放空间
- js并没有api可以直接开辟空间,而是使用变量声明、创建函数、创建类等方式,通过浏览器来开辟空间
- 使用空间时注意,避免不当操作造成空间泄露
垃圾回收
- js中内存管理是自动的
- 对象不再被引用时即是垃圾
- 对象不能从根上访问到时是垃圾
可达对象
- 可以访问到的对象就是可达对象
- 可达的标准就是从根出发是否能够被找到(从根上,到作用域链查找等)
- 根:可以理解为全局变量对象
GC算法介绍
- GC:就是垃圾回收机制的简写
- GC 可以找到内存中的垃圾、并释放和回收空间
- GC 里的垃圾是什么?
- 程序中不在需要使用的对象
- 程序中不能再访问到的对象
- GC 是一种机制,垃圾回收器完成具体的工作,而工作内容就是查找垃圾并释放和回收空间;算法就是工作时查找和回收所遵循的规则
- 常用的算法:引用计数、标记清除、标记整理、分代回收
GC:引用计数
- 核心思想:设置引用数,判断当前引用数是否为0,当为0的时候进行回收
- 实现原理:
- 维护一个引用计数器,当有变量引用时,计数器加1,不再引用时计数器减1,当计数器为0时,GC回收,释放空间
- 引用计数器:因为计数器存在,导致和其他机制有所区别
优缺点
- 当发现为0时,立即回收
- 减少 程序卡顿时间
- 因为时刻监测内存,当快满的时候就回收,因此内存不会慢
- 但是因需要维护计数器的变化,时间开销会相比其他机制大
- 同时,如果两个对象互相引用,因为互相不为0,因此无法删除
标记清除
- 核心思想:分两个阶段,第一个阶段将活动对象进行标记,第二个标记将未标记的清除掉,同时消除之前的标记
- 从根查找,沿着作用域链只要能找到的,就为可达对象,否则为不可达,后续会被GC进行清除
优缺点
- 可以解决引用计数时无法解决的互相引用问题
- 互相引用时,在作用域执行完毕后从根递归查找已无法可达,因此会被清除
- 缺点1:因清除掉后空间地址不连续,造成空间浪费
- 缺点2:碎片化,不会立即清除
标记整理
标记阶段和标记清除机制一直,不同点在于,在执行完毕第一阶段后,在执行第二阶段标记清除之前,会先进行一次空间整理,移动对象的位置,使可达的活动对象空间地址是连续的,之后再进行清除操作
-
减少碎片化
-
不会立即回收垃圾对象
V8
-
V8是一款主流的js执行引擎,chrome平台已在使用
-
V8 采用即时编译
-
内存设限
64为系统中 1.5g
32为系统中 800M
原因就是:当内存使用到1.5g的时候,使用增量标记的方式需要使用500毫秒。使用其他方式需要1s,从用户体验角度来说,设定此上线,且使用增量标记较合理
V8垃圾回收策略
-
采用分代回收思想,分为新生代、老生代,针对不同对象采用不同算法
-
先划分,按照新生代、老生代的模式分代回收
-
其次进行空间复制
-
标记清除
-
标记整理
-
标记增量
新生代回收
-
新生代空间被分为等分两部分
-
在64为系统中是32M单个
-
在32位系统中是16M单个
-
新生代指的是存活时间较短的对象
- 等分的两个空间划分为:使用空间为From,空间空间为To
- 如果声明变量时,开辟空间则会在From空间中存储,为活动对象,此时To空间为空闲状态,未使用
- 当From空间使用到一定比例时将会出发GC操作,顺序是先进行标记整理,然后将活动对象拷贝至TO空间。拷贝完毕后From区域被进行释放,TO编程了使用状态。进行了交换
- 1、一轮GC后还存活的新生代需要晋升。
- 2、TO空间的使用率超过25%,将全部拷贝至老生代(因为From和To需要交换,保证空间足够)
老生代回收
- 老生代对象存储在老生代区域
- 老生代的空间大小限制为:64位操作系统是1.4g,32位操作系统是700M
- 老生代对象就是指存活时间较长的对象
- 老生代的回收主要采用标记清除、标记整理、增量标记算法
- 首先:使用标记清除完成垃圾回见的回收,速度较快
- 标记整理需要根据条件触发:当新生代空间向老生代空间晋升,但空间无法满足时,会先进行比较整理进行空间优化,
- 最后采用增量标记进行效率优化
- 新生代使用空间换时间
- 老生代不适合复制算法,原因:大,时间长
V8执行流程
- scanner-扫描器,将纯文本的代码进行扫描。做词法分析,得到词法单元,最小的一个单元
- parser-解析器,语法分析,将词法分析的数据进行转化为ast树
- preparser,预解析,全量解析
示例
// 声明时未调用,因此会被认为是不被 执行的代码,运行预解析
function foo() {
console.log('foo')
}
// 声明时未调用,因此会被认为是不被执行的嗲吗,进行预解析
function fn() {}
// 函数立即执行,只进行一次全量解析
(function bar() {
})()
// 执行foo 那么需要重新对foo函数进行全量解析,此时foo函数被解析了两次
foo()
- lgnition 是V8提供的一个解释器
- turBoFan 是编译器模块
函数防抖与节流
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!