ECMAScript新特性,TypeScript语言,Javascript性能优化
ECMAScript新特性
TypeScript语言
-
作用
- 解决javascipt自有类型系统的问题,大大提高代码的可靠程度 强类型和弱类型
- 强类型不允许随意的隐式类型转换,而弱类型是允许的 静态类型和动态类型
- 静态类型:声明过后,它的类型不允许再修改
-
动态类型:在运行阶段才能明确变量类型,而且变量的类型可以随时改变
javascript则是弱类型、动态类型语言,缺失了类型系统的可靠性;没有编译环节,需求不多
Flow
TypeScript
作用
任何一种javascript运行环境都支持,功能更为强大,生态也更健全、更完善(Angular/vue.js3.0);前端领域的第二语言,适合长周期大项目;
-
缺点
- 一、语言本身多了很多概念(属于渐进式)
- 二、项目初期,TypeScript会增加一些成本 快速上手
- yarn init --yes 初始化项目中的package.json,管理项目的依赖性
- yarn add typescript --dev 做为项目的开发依赖来安装
-
yarn tsc 文件名 会生成一个js文件(ECMAScript3的语法)
如果使用yarn命令报错使用以下方法修改权限
window +x -> Windw.powerShell(管理员A) -> set-ExecutionPolicy RemoteSigned -> y -> get-ExecutionPolicy
。
配置文件
- 编译整个项目,编译之前创建一个typescript配置文件
- yarn tsc --init 运行之后会生成一个tsconfig.json文件 原始类型
- 标准库就是内置对象所对应的声明 中文错误消息
- yarn tsc --locale zh-CN 作用域问题
- 两种方法,第二种更常用
//方法一
// (function(){
// const a=123
// })()
//方法二
const a=123
export {}
-
Object类型
-
export {} //确保跟其它示例没有成员冲突
const foo:object=function(){}//[]//{}
const obj:{foo:number,bar:string}={foo:123,bar:'string'}
-
数组类型
-
const arr1:Array<number>=[1,2,3]
const arr2:number[]=[1,2,3]
// -----------------------------
function sum(...args:number[]){
// 判断是不是每个成员都是数字
return args.reduce((prev,current)=>prev+current,0)
}
-
元组类型
- 明确元素数量,以及每个元素类型的数组
const tuple:[number,string]=[12,'zce']
// const age=tuple[0]
// const name=tuple[1]
const [age,name]=tuple
// ------------------------------
Object.entries({
foo:123,
bar:456
})
-
枚举类型
-
// const PostStatus={
// Draft:0,
// Unpublished:1,
// Published:2
// }
const enum PostStatus{
Draft=0,
Unpublished=1,
Published=2
}
// 如果不给定指定的值,默认会从0开始累加,如果给第一个属性一个固定值,后面会在这个基础上累加
const post={
title:'Hello TypeScript',
content:'TypeScript is a typed superset of JavaScript.',
status:PostStatus.Draft//2//1//0
}
-
函数类型
-
function func1(a:number,b?:number,...rest:number[]):string{
return 'func1'
}
// -----------------------------------------------
const func2:(a:number,b:number)=>string=function(a:number,b:number):string{
return 'func2'
}
-
任意类型
-
function stringify(value:any){
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo:any='string'
foo=100
foo.bar()
// any类型是不安全的
-
隐式类型推断
-
let age=10//number
// age='string'
let foo
foo=100
foo='string'
// 建议为每个变量添加明确的类型
-
类型断言
- 类型断言并不是类型转换,只是在编译过程的转换,而类型转换是代码在运行时的概念
// 假定这个nums来自一个明确的接口
const nums=[110,120,119,112]
const res=nums.find(i=>i>0)
// const square=res*res
const num1=res as number
const num2=<number>res//JSX下不能使用
-
接口
- 一种规范(契约),约束一个对象的结构
interface Post{
title:string
content:string
}
function printPost(post:Post){
console.log(post.title);
console.log(post.content);
}
printPost({
title:'Hello TypeScript',
content:'A javascript superset'
})
// 可选成员、只读成员、动态成员
interface Post{
title:string
content:string
subtitle?:string//可选成员
readonly summary:string//只读成员
}
const hello:Post={
title:'Hello TypeScript',
content:'A javascript superset',
summary:'A javascript'
}
// ---------------------------------------
interface Cache{
[prop:string]:string
}
const cache:Cache={}
cache.foo='value1'
cache.bar='value2'
-
类
- 描述一类具体事物的抽象特征,用来描述一类具体对象的抽象成员;
- es6以前,函数+原型 模拟实现类
- es6开始javascript 中有了专门的class
- typescript 增强了class的相关语法
class Person{//在typescript中类的属性必须要有一个初始值,可以在等号后面赋值,也可以在构造函数中赋值
name:string//='init name'
age:number
constructor(name:string,age:number){
this.name=name
this.age=age
}
sayHi(msg:string):void{
console.log(`I am ${this.name},${msg}`);
}
}
//类的访问修饰符
class Person{//在typescript中类的属性必须要有一个初始值,可以在等号后面赋值,也可以在构造函数中赋值
public name:string//='init name'
private age:number
protected gender:boolean
// protected readonly gender:boolean //只读属性
constructor(name:string,age:number){
this.name=name
this.age=age
this.gender=true
}
sayHi(msg:string):void{
console.log(`I am ${this.name},${msg}`);
console.log(this.age);
}
}
class Student extends Person{
constructor (name:string,age:number){
super(name,age)
console.log(this.gender);
}
}
const tom=new Person('tom',18)
console.log(tom.name);
-
泛型
- 在声明的时候不去指定具体类型,在调用的时候指定它的类型
function createArray<T>(length:number,value:T):T[]{
const arr=Array<T>(length).fill(value)
return arr
}
const res=createArray<string>(3,'foo')
Javascript性能优化
javascript语言的优化
内存管理
- 内存:由可读写单元组成,表示一片可操作空间
- 管理:认为的去操作一片空间的申请、使用和释放
- 内存管理:开发者主动申请空间、使用空间、释放空间
- 管理流程:申请-使用-释放
//memory management
// 申请
let obj = {}
// 使用
obj.name = 'lg'
// 释放
obj = null
垃圾回收与常见GC算法
- javascript中内存管理是自动的
- 对象不再被引用时是垃圾
- 对象不能从根本上访问到时是垃圾
javascript中的可达对象
- 可以访问到的对象就是可达对象(引用、作用域链)
- 可达的标准就是从根出发是否能够被找到
- javascript 中的根就可以理解为是全局变量对象
GC定义与作用
- GC就是垃圾回收机制的简写
- GC可以找到内存中的垃圾、并释放和回收空间
- 算法就是工作时查找和回收多遵循的规则
1.程序中不再需要使用的对象
2.程序中不能再访问到的对象
常见的GC算法
引用计数
-
核心思想:设置引用数判断当前引用数是否为0
-
引用计数器
-
引用关系改变时修改引用数字
-
引用计数算法优点
- 发现垃圾时立即回收
- 最大限度减少程序暂停 引用计数算法缺点
-
无法回收循环引用的对象
:时间开销大
标记清除
- 核心思想:分标记和清除两个阶段完成
- 遍历所有对象找标记活动对象
- 遍历所有对象清除没有标记对象
- 回收相应的空间
- 标记整理
- 分代回收
v8引擎的垃圾回收
Performance工具
谷歌浏览器提供的性能工具
内存问题
内存问题的提现
- 页面出现延迟加载或经常性暂停
- 页面持续性出现糟糕的性能
- 页面的性能随时间延长越来越差
界定内存问题的标准
- 内存泄漏:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题
- 频繁垃圾回收:通过内存变化图进行分析
监控内存的几种方式
- 浏览器任务管理器
Shift+Esc - TimeLine时序图记录
F12 performance(性能) 录制 - 堆快照查找分离DOM1
F12 memory(内存) Take snapshot(获取快照) 搜索deta - 判断是否存在频繁的垃圾回收(GC)
代码优化
如何精准测试Javascript性能
- 本质上是采用大量的执行样本进行数学统计和分析
- 使用基于Benchmark.js的链接: https://jsbench.me/完成
使用流程- 使用github账号登录
- 填写个人信息(非必填)
- 填写详细的测试用例信息(title,slug)
- 填写准备代码(DOM操作时经常使用)
- 填写必要的setup和teardown代码
- 填写代码测试片段
慎用全局变量
- 全局变量定义在全局执行上下文,是所有作用域的顶端
- 全局执行上下文一直存在于上下文执行栈,直到程序退出
- 如果某个局部作用域出现了同名变量则会遮蔽或污染全局
缓存全局变量
- 将无法避免的全局变量缓存到局部
通过原型新增方法
避开闭包陷阱
-
外部具有指向内部的引用
-
在“外”部作用域访问“内”部作用域的数据
关于闭包
- 闭包是一种强大的语法
- 闭包使用不当很容易出现内存泄漏
- 不要为了闭包而闭包
避免属性访问方法使用
javascript中的面向对象
- JS不需属性的访问方法,所有属性都是外部可见的
- 使用属性访问方法只会增加一层重定义,没有访问的控制力
for循环优化
最优的循环方式
文档碎片化节点添加
节点的添加操作必然会有回流和重绘
克隆优化节点操作
直接量替换new Object
JSBench
jsperf已经不维护了
链接: https://jsbench.me/完成
堆栈中的JS执行
减少判断层级
减少作用域查找层级
减少数据读取次数
界面元素存活在DOM树上;垃圾对象时的DOM节点;分离状态的DOM节点 ↩︎