ES新特性、TS、JS性能優化

ES新特性

1、let、const

塊級作用域
變量提升
最佳實踐:不使用var ,默認使用const ,明確會改的使用let。

2、解構

  • 數組
const arr = [1,2,3]
const [a,b] = arr;
const [,,c] = arr;

使用…方式解構

const [a,...rest] = arr;

默認值

const [a,b,c,d = 12] = arr
  • 對象
const obj = {
    name:'zs',
    age:18
}
const {name} = obj;
// 重命名
const {name:rename} = obj;

3、模板字符串

let str = `
    i am 
    ${name}
`
// 帶標籤的模板字符串
const str  = console.log`hello world`

4、字符串的擴展方法

  • includes()
  • startsWith()
  • endsWith()

5、參數默認值、 剩餘參數

… 操作符
function fn(…args){}

6、展開數組

const arr = [1,2,3];
console.log(...arr)

7、箭頭函數

不會改變this的指向。
箭頭函數不適用:

  • 構造函數
  • 沒有arguments
  • 沒有this

8、對象字面量

const obj = {
    foo:123,
    method1(){
        console.log('1')
    },
    //計算屬性名
    [Math.random](){

    }
}

9、Object

  • Object.assign 多個對象複製到一個目標對象。
const source1 = {
    a:123,
    b:23
}
const target = {
    a:123,
    c:23
}
const res = Object.assign(target,source1)
  • Object.is 判斷兩個值是否一樣

10、proxy

Object.defineProperty

proxy

const person = {
    name:'ss',
    age:19
}

const personProxy = new Proxy(person,{
    get(target,key){
        console.log(target,key)
        return 100;
    },
    set(target,key,value){
        console.log(target,key,value)
    }
})
console.log(personProxy.name)
personProxy.sex = '女'

proxy的優勢:

  • defineProperty只能監視屬性的讀寫,proxy可以監視delete、方法調用等
const person = {
    name:'ss',
    age:19
}
const personProxy = new Proxy(person,{
    deleteProperty(target,property){
        console.log('delete')
    }
})
delete personProxy.age

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OffyGgUn-1593528494642)(./img/1.png)]

  • proxy更好的監視數組
const list = []
const listProxy = new Proxy(list,{
    set(target,property,value){
        console.log(target,property,value)
        target[property] = value;
        return true//表示設置成功
    }
})
listProxy.push(10)

11、reflect

統一的對象操作API
靜態類
內部封裝了一系列對對象的底層操作 。

const person = {
    name:'ss',
    age:19
}

const personProxy = new Proxy(person,{
    get(target,key){
        // ... 自定義邏輯
       return Reflect.get(target,key)
    },
    set(target,key,value){
        console.log(target,key,value)
    }
})
console.log(personProxy.name)
personProxy.sex = '女'

Reflect.has
Reflect.deleteProperty
Reflect.ownkeys

12、promise

異步編程解決方案

13、class

// es5
function Person(name) {
    this.name = name
}
Person.prototype.say = function(){}
// es6
class Person{
    constructor(name){
        this.name = name
    }
    say(){

    }
}
const person = new Person('zhangsan');
  • 靜態方法
class Person{
    constructor(name){
        this.name = name
    }
    // 實例方法
    say(){

    }
    // 靜態方法
    static create(name){
        return new Person(name)
    }
}
  • 實例方法
  • 類的繼承 – extends
class Person{
    constructor(name){
        this.name = name
    }
    say(){
        console.log('父say')
    }   
}
class Student extends Person{
    constructor(name,number){
        super(name)
        this.number = number
    }
    hello(){
        super.say();
        console.log('hello')
    }
}
let stu = new Student('zhaosi',12342);
stu.hello();

14、set、map

Set 不允許重複

const set = new Set();
set.add(1).add(2).add(3)
// 遍歷
set.forEach(()=>{})
for(let i of set){

}
set.size
set.has()
set.delete()
set.clear()

const arr = [1,2,3,1,4,2]
const set1 = new Set(arr)
Array.from(set1)
const arr1 = [...set1]

Map
類似對象,

const obj = {
}
obj[true] = 'value'
obj[123] = 'value'
obj[{a:1}] = 'value'

Object.keys(obj)

const m = new Map()
const tom = {name:'tom'}
m.set(tom,99)

m.has()
m.delete()
m.clear()

m.forEach(()=>{})

15、Symbol

const a = Symbol()
console.log(a)

const obj = {
}
obj[Symbol('a')] = 123;
obj[Symbol('b')] = 445;
console.log(obj[Symbol('a')])

const a = Symbol.for('foo')
const b = Symbol.for('foo')
console.log(a===b)

const obj1 = {
    [Symbol.toStringTag]:'XObject'
}
console.log(obj1.toString()) // [object XObject]

私有屬性

  • 唯一性
  • for…in \ Object.key() 獲取不到
  • Object.getOwnPropertySymbol(obj)

16、for…of – 迭代器

const arr = [2,324,12,324,2,234]
for(let i of arr){ 
    console.log(i)
    if(i>188){
        break
    }
}
// arr.forEach() //無法中斷循環
// arr.some()
// arr.every()

// 遍歷set、map

可迭代接口 Iterable
實現Iterable接口,是使用for…of的前提

const arr = [1,23,321,421]
const iterator = arr[Symbol.iterator]() 
iterator.next()

實現可迭代接口

const obj= {
    store:['foo','bar','baz'],
    [Symbol.iterator]:function(){
        let index = 0;
        const self = this;
        return {
            next:function(){
                const res =  {
                    value:self.store[index],
                    done:index>=self.store.length
                }
                index ++
                return res;
            }
        }
    }
}

for(let item of obj){
    console.log(item)
}

*** 迭代器模式 ***

const todo = {
    life:['s','d'],
    learn:['e','w2'],
    work:['dfa'],
    each:function(cb){
        const all = [].concat(this.life,this.learn,this.work)
        for(const item of all){
            cb(item)
        }
    },
    [Symbol.iterator]:function(){
        const all = [...this.life,...this.learn,...this.work]
        let index = 0;
        return {
            next:function(){
                return {
                    value:all[index],
                    done:index++>=all.length
                }
            }
        }
    }
}
//for(let item of to.life){}
//for(let item of to.learn){}
//for(let item of to.work){}

todo.each(function(item){
    console.log(item)
})
for(let item of todo){
    console.log(item)
}

17、生成器 generator

避免回調嵌套

function * foo(){
    console.log('zcc')
    return 100
}
const res = foo();
console.log(res)
res.next() 

// 配合 yield 
function * boo(){
    console.log('111')
    yield 100
    console.log('222')
    yield 200
    console.log('333')
    yield 300
}
const gen = boo();
gen.next()

生成器應用

// 案例 : 發號器
function * createID(){
    let id = 1;
    while(true){
        yield id++
    }
}
const id = createID();
id.next()
// 實現iterator方法
const todo = {
    life:['s','d'],
    learn:['e','w2'],
    work:['dfa'],
    [Symbol.iterator]:function * (){
        const all = [...this.life,...this.learn,...this.work]
        for(let item of all){
            console.log(item)
        }
    }
}
for(let item of todo){
    console.log(item)
}

18、ES Modules

模塊化

19、ES2016 ES2017

ES2016

  • Array.prototype.includes
  • 指數運算符
    Math.pow()
    ** 2**10

ES2017

  • Object.values()
  • Object.entries()
  • Object.getOwnPropertyDescriptors()
  • String.prototype.padStart
  • String.prototype.padEnd
  • 函數參數中添加尾逗號
function foo(arg1,arg2,){

}
  • async/await

TS

解決JS類型系統問題

  • 強類型 VS 弱類型 (類型安全)
    強類型有更強的類型約束。
    強類型不允許隱式類型轉換。

  • 靜態類型 VS 動態類型 (類型檢查)
    變量聲明時就是明確的。-- 靜態類型
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SCbTOyNS-1593528494643)(./img/2.png)]

  • 弱類型的問題

    • 運行階段才能發現錯誤
    • 類型不明確,造成函數功能發生改變
    • 對對象索引發生錯誤
const obj = {}
obj[123] = 456
obj[123] // undefined
  • 強類型的優勢
    • 錯誤更早的暴露
    • 代碼更智能,編碼更準確
    • 重構更牢靠
    • 減少不必要的類型判斷

flow(工具)

1、 JS的類型檢查器
通過類型註解的方式,檢查類型。

function sum(a:number,b:number){
    return a + b
}

通過babel去除註解代碼。
2、 使用

yarn add flow-bin --dev // 安裝 

yarn flow init //初始化配置文件

yarn flow 
yarn flow stop //停止命令

3、 編譯移除註解

yarn add flow-remove-types --dev // 移除

yarn flow-remove-types . -d dist 

 // 或者 通過babel方式移除
yarn add @babel/core @babel/cli @babel/preset-flow --dev

yarn babel part01/module02/flow -d dist // 命令

通過babel的 方式 要配置.babelrc文件,配置如下:

{
    "presets":["@babel/preset-flow"]
}

4、開發工具插件
Flow Language Support VScode插件
5、 flow類型

6、 flow運行環境API
內置對象

TS (語言)

1、JS的超集

  • 可以對ES新特性編譯(類似babel)
  • 功能強大、生態健全、完善
  • 任意JS環境都支持
  • TS屬於漸進式的
  • 【缺點】語言本省多了很多概念,如接口、泛型
  • 【缺點】項目初期,增加開發成本
    2、基本使用 ts代碼–> js代碼
    yarn add typescript --dev
    tsc .\01-getting-start.ts
    
    

3、配置文件

tsc --init   

tsconfig.json
4、 原始類型
原始類型
標準庫-- 就是內置對象所對應的說明
5、 TS中文錯誤消息
tsc --locale zh-Ch

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-45u2mvba-1593528494645)(./img/3.png)]

6、作用域問題

作用域問題

7、類型

隱式類型推斷
類型斷言

// as 關鍵字
const num1 = res as number; //(推薦)
//或
const num2 = <number>res; // 會和JSX標籤衝突

8、 接口
接口

9、類

類和接口 類和接口

用接口抽象類的共同屬性

抽象類:約束子類必須有某些成員,只能被繼承;
子類必須實現父類的抽象方法。

abstract class Animals {
   eat(food:string):void{}
   abstract run(distance:number):void
}

10、泛型 泛型
11、類型聲明

JS性能優化

1、內存管理
申請、使用、釋放空間。

2、垃圾回收 、常見GC算法

  • JS中的垃圾
    • JS中內存管理是自動的
    • 對象不再被引用時是垃圾
    • 對象不能從根上訪問到時是垃圾
  • 可達對象 可達
    • 引用、作用域鏈
    • 全局執行上下文(根)
  • GC算法
    • GC-垃圾回收
    • GC可以在內存中找到垃圾
      • 程序中不再使用的對象
      • 程序中不能訪問到的對象
    • GC是一種機制(垃圾回收器完成的具體工作)
    • 工作內容就是查找垃圾釋放空間、回收空間
    • 算法就是工作時查找和回收所遵循的規則
  • 常見GC算法
    • 引用計數引用計數
      • [思想] 設置引用數,判斷當前引用數是否爲0
      • 引用計數器
      • 引用關係改變時修改引用數字
      • 引用數字爲0 回收
      • [優點] 發現垃圾時立即回收
      • [優點] 最大限度減少程序暫停
      • [缺點] 無法回收循環引用的對象循環引用
      • [缺點] 時間開銷大
    • 標記清除
      • [原理] 分標記和清除兩個階段
      • 遍歷所有對象找到標記活動對象
      • 遍歷所有對象清除沒有標記的對象
      • 回收相應的空間
      • [優點] 解決循環引用的問題
      • [缺點] 空間碎片化
    • 標記整理
      • [原理] 標記清除的增強操作
      • 標記階段和標記清除一樣
      • 清除階段會先執行整理,移動對象位置
    • 分代回收 (V8)

3、V8的垃圾回收

  • V8
    • JS 執行引擎
    • 即時編譯
    • 內存設限
  • V8垃圾回收策略
    • 分代回收思想
    • 內存分新生代和老生代
    • 針對不同的生代採用不用的算法
    • V8中常用算法
      • 分代回收
      • 空間複製
      • 標記清除
      • 標記整理
      • 標記增量
  • 新生代垃圾回收
    • V8內存分配
      • V8內存空間一分爲二
      • 小空間用於存儲新生代對象(32M | 16M)
      • 新生代指的是存活時間短的對象
        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yOXCqj7p-1593528494647)(./img/4.png)]
    • 回收實現
      • 回收過程採用複製算法+標記整理
      • 新生代內存區分爲2個等大小空間
      • 使用空間爲From,空閒空間爲To
      • 活動對象存儲於From空間
      • 標記整理後將活動對象拷貝至To
      • From和To交換空間完成釋放
      • 拷貝過程中可能會出現晉升(將新生代對象移動至老生代)
      • 一輪GC還存活的新生代對象需要晉升
      • To空間使用率超過25% — 晉升
  • 老生代垃圾回收
    • 老生代對象存放在右側老生代區
    • 64位操作系統1.4G 32位 700M
    • 老生代對象就是存活時間較長的對象
    • 垃圾回收實現
      • 主要採用標記清除、標記整理、增量標記算法
      • 首先使用標記清除完成垃圾空間的回收
      • 採用標記整理進行空間優化(對象晉升時)
      • 採用增量標記進行效率優化
    • VS 新生代
      • 新生代—空間換時間
      • 老生代不適合複製算法(空間浪費、複製量大)

4、performance工具

  • 爲啥使用performance
    • GC的目的是爲了實現內存空間的良性循環
    • 良性循環的基石是合理利用
    • 時刻關注才能確定是否合理
    • performance提供多種監控方式
  • performance使用
    • 打開瀏覽器輸入目標網址
    • F12面板 — 性能
    • 開啓錄製功能,訪問具體頁面
    • 執行用戶行爲,一段時間後停止錄製
    • 分析界面中記錄的內存信息
  • 內存問題的體現
    • 頁面出現延遲加載或經常性暫停
    • 頁面持續性出現槽糕的性能
    • 頁面性能隨時間延長越來越差
  • 界定內存問題的標準
    • 內存泄漏 內存使用持續升高
    • 內存膨脹 在多數設備上都存在性能問題
    • 頻繁垃圾回收 通過內存變化圖分析
  • 監控內存的幾種方式
    • 瀏覽器任務管理器任務管理器
      • shift+esc 打開任務管理器面板
      • 右鍵點擊 — 選擇JS使用內存
    • Timeline 時序圖記錄Timeline
    • 堆快照查找分離DOM Memory
      • 什麼是分離DOM
        • 界面元素存活在DOM樹上
        • 垃圾對象時的DOM節點
        • 分離狀態的DOM節點
      • 搜索(deta)
    • 判斷是否存在頻繁的垃圾回收
      • 爲什麼確定頻繁垃圾回收?
        • GC工作時應用程序是停止的
        • 頻繁且過長的GC會導致應用假死
        • 用戶使用中感知應用卡頓
      • 確定頻繁的垃圾回收
        • timeline中頻繁的上升下降
        • 任務管理器中數據頻繁的增加減小

5、代碼優化

  • 如何精準測試JS性能?

    • 本質上就是採集大量的執行樣本進行數學統計和分析
    • 使用基於Benchmark.js的https://jsperf.com完成
  • jsperf使用流程

    • 使用GitHub賬號登錄
    • 填寫個人信息(非必填)
    • 填寫詳細的測試用例信息(title、slug)
    • 填寫準備代碼(DOM操作時經常使用)
    • 填寫必要有setup與teardown代碼
    • 填寫測試代碼片段
  • 慎用全局變量慎用全局變量

    • 全局變量定義在全局執行上下文,是所有作用域鏈的頂端
    • 全局執行上下文一直存在於上下文執行棧,直到程序退出
    • 如果某個局部作用域出現了同名變量則會出現遮蔽或污染全局
  • 緩存全局變量全局變量

    • 將使用中無法避免的全局變量緩存到局部
  • 通過原型對象添加附加方法原型對象添加

  • 避開閉包陷阱閉包

    • 閉包的特點
      • 外部具有指向內部的引用
      • 在‘外’部作用域訪問‘內’部作用域的數據
    • 關於閉包
      • 閉包是一種強大的語法
      • 閉包使用不當很容易出現內存泄漏
      • 不要爲了閉包而閉包
  • 避免屬性訪問方法使用屬性訪問方法

    • JS不需屬性的訪問方法,所有屬性都是外部可見的
    • 使用屬性訪問方法只會增加一層重定義,沒有訪問的控制力
  • for循環優化for

  • 選擇最優的循環方法最優的循環方法

    • for(中)
    • for … in (低)
    • foreach (高)
  • 文檔碎片優化節點添加節點添加

  • 克隆優化節點節點克隆

  • 直接量替換new ObjectObject

本模塊思維導圖

Q:vue項目有很多分離DOM,如何定位到是哪裏生成的呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章