Javascript初級(jí)知識(shí)點(diǎn)(原型,閉包衫冻,異步)整理

JS

變量類型和計(jì)算

  • typeof 能判斷那些類型
  • 何時(shí)使用 === 何時(shí)使用 ==
  • 值類型和引用類型的區(qū)別
  • 手寫深拷貝

值類型和引用類型

值類型存儲(chǔ)在棧內(nèi)存中诀紊,引用類型存儲(chǔ)在堆內(nèi)存中

// 值類型
let a = 100
let b = a
a = 200
console.log(b)  // 100
// 引用類型
let a = { age: 20 }
let b = a
b.age = 21
console.log(a.age)  // 21

常見值類型和引用類型

// 常見值類型
let u   // undefined
const s = 'abc'
const n = 100
const b = true
const s = Symbol('s')
// 常見引用類型
const obj = { x: 100 }
const arr = ['a', 'b', 'c']

const n = null // 特殊引用類型,指針指向?yàn)榭盏刂?
// 特殊的引用類型隅俘,但不用于存儲(chǔ)數(shù)據(jù)邻奠,所以沒有拷貝、復(fù)制函數(shù)這一說
function fun() {}

類型判斷

typeof 運(yùn)算符

  • 識(shí)別所以值類型
  • 識(shí)別函數(shù)
  • 判斷是否是引用類型(不可再細(xì)分)

深克隆

function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj === null) {
        // obj 是 null礼患,或是不是對(duì)象和數(shù)組愉舔,直接返回
        return obj
    }

    // 初始化返回結(jié)果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }

    for (let key in obj) {
        // 保證 key 不是原型的屬性
        if (obj.hasOwnProperty(key)) {
            // 遞歸
            result[key] = deepClone(obj[key])
        }
    }

    return result
}

類型轉(zhuǎn)換

  • 字符串拼接
  • ==
  • if 語句邏輯運(yùn)算
const a = 100 + 10 // 110
const b = 100 + '10' // 10010
const c = true + '10' // true10

const d = 100 + parseInt('10') // 110

==

100 == '100' // true
0 == '0' // true
0 == false // true
false == '' // true
null == undefined // true
NaN == NaN // false

// 除了 == null 之外捏鱼,其他都一律用 === ,例如:
const obj = { x: 100 }
if (obj.a == null) {}
// 相當(dāng)于
if (obj.a === null || obj.a === undefined) {}

邏輯運(yùn)算

if 語句和邏輯運(yùn)算

  • truly 變量:!!a === true 的變量
  • falsely 變量:!!a === false 的變量

原型和原型鏈

  • 如何判斷一個(gè)變量是不是數(shù)組贰镣?
  • 手寫一個(gè)簡(jiǎn)易的 jQuery,考慮插件和擴(kuò)展性
  • class 的原型本質(zhì)膳凝,怎么理解碑隆?

class

class Student {
    constructor(name, number) {
        this.name = name
        this.number = number
    }
    greeting() {
        console.log(`Hello, My name is ${this.name}, number is ${this.number}`)
    }
}

// 實(shí)例化
const zhangsan = new Student('zhangsan', 1)
zhangsan.greeting() // Hello, My name is zhangsan, number is 1

繼承

// 父類
class Person {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat something`)
    }
}

// 子類
class Student extends Person {
    constructor(name, number) {
        super(name)
        this.number = number
    }
    greeting() {
        console.log(`Hello, My name is ${this.name}, number is ${this.number}`)
    }
}

// 子類
class Teacher extends Person {
    constructor(name, subject) {
        super(name)
        this.subject = subject
    }
    teach() {
        console.log(`My name is ${this.name}, and I am teaching ${this.subject}`)
    }
}

// 實(shí)例化
const zhangsan = new Student('zhangsan', 1)
zhangsan.greeting() // Hello, My name is zhangsan, number is 1
zhangsan.eat() // zhangsan eat something

const mrWang = new Teacher('wang', 'Math')
mrWang.eat()  // wang eat something
mrWang.teach()  // My name is wang, and I am teaching Math

// 類型判斷
console.log(zhangsan instanceof Student) // true
console.log(zhangsan instanceof Person) // true
console.log(zhangsan instanceof Object) // true

// true
console.log([] instanceof Array)
console.log([] instanceof Object)
console.log({} instanceof Object)

原型

// class 實(shí)際上是函數(shù),語法糖而已
typeof Person // function
typeof Student // function

// 隱式原型和顯示原型
console.log(zhangsan.__proto__)
console.log(Student.prototype)
console.log(zhangsan.__proto__ === Student.prototype) // true

原型關(guān)系

  • 每個(gè) class 都有顯示原型 prototype
  • 每個(gè)實(shí)例都有隱式原型 __ proto__
  • 實(shí)例的 __ proto__指向?qū)?yīng)的 class 的 prototype

原型鏈

console.log(Student.prototype.__proto__)
console.log(Person.prototype)
console.log(Person.prototype === Student.prototype.__proto__) // true

instanceof

手動(dòng)實(shí)現(xiàn) instanceof

function myInstanceof(left, right) {
    // 獲取類的原型
    let prototype = right.prototype
    // 獲取對(duì)象的原型
    left = left.__proto__
    // 判斷對(duì)象的類型是否等于類型的原型
    while (true) {
        if (left === null)
            return false
        if (prototype === left)
            return true
        left = left.__proto__
    }
}

手寫一個(gè)簡(jiǎn)易的 jQuery蹬音,考慮插件和擴(kuò)展性

class jQuery {
    constructor(selector) {
        const result = document.querySelectorAll(selector)
        const length = result.length
        for (let i = 0; i < length; i++) {
            this[i] = result[i]
        }
        this.length = length
        this.selector = selector
    }
    get(index) {
        return this[index]
    }
    each(fn) {
        for (let i = 0; i < this.length; i ++) {
            const elem = this[i]
            fn(elem)
        }
    }
    on(type, fn) {
        return this.each(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
}

// 插件
jQuery.prototype.dialog = function (info) {
    alert(info)
}

// “造輪子”
class myJQuery extends jQuery {
    constructor(selector) {
        super(selector)
    }
    // 擴(kuò)展自己的方法
    addClass(className) {
        // ...
    }
    style(data) {
        // ...
    }
}

作用域和閉包

  • this 的不同應(yīng)用場(chǎng)景上煤,如何取值?
  • 手寫 bind 函數(shù)
  • 實(shí)際開發(fā)中閉包的應(yīng)用場(chǎng)景祟绊,舉例說明
  • 創(chuàng)建 10 個(gè) <a> 標(biāo)簽點(diǎn)擊的時(shí)候彈出對(duì)應(yīng)的序號(hào)

作用域

let a = 0
function fn1() {
    let a1 = 100

    function fn2() {
        let a2 = 200

        function fn3() {
            let a3 = 300
            return a + a1 + a2 + a3
        }
        fn3()
    }
    fn2()
}
fn1()
  • 全局作用域
  • 函數(shù)作用域
  • 塊級(jí)作用域(ES6新增)

自由變量

  • 一個(gè)變量在當(dāng)前作用域沒有定義楼入,但被使用了
  • 向上級(jí)作用域哥捕,一層一層依次尋找,直到找到了為止
  • 如果在全局作用域都沒有找到嘉熊,則報(bào)錯(cuò) xxx is not defined

閉包

  • 作用域應(yīng)用的特殊情況遥赚,有兩種表現(xiàn)
  • 函數(shù)作為參數(shù)被傳遞
  • 函數(shù)作為值被返回
// 函數(shù)作為返回值
function create() {
    let a = 100
    return function () {
        console.log(a)
    }
}

let fn = create()
let a = 200
fn() // 100

// 函數(shù)作為參數(shù)
function print(fn) {
    let a = 200
    fn()
}

let a = 100
function fn() {
    console.log(a)
}
print(fn) // 100

閉包:自由變量的查找,是在函數(shù)定義的地方阐肤,向上級(jí)作用域查找

不是在執(zhí)行的地方Y旆稹!孕惜!

this

  • 作為普通函數(shù)
  • 使用 call apply bind
  • 作為對(duì)象方法被調(diào)用
  • 在 class 方法中調(diào)用
  • 箭頭函數(shù)

this 取什么值是在函數(shù)執(zhí)行的時(shí)候確定的愧薛,不是在定義的時(shí)候

function fn1() {
    console.log(this)
}
fn1() // window

fn1.call({x: 100}) // {x: 100}

const fn2 = fn1.bind({x: 200})
fn2() // {x: 200}

箭頭函數(shù)

const zhangsan = {
    name: 'zhangsan',
    greeting() {
        // this 即當(dāng)前對(duì)象
        console.log(this)
    },
    wait() {
        setTimeout(function() {
            // this === window
            console.log(this)
        })
    }
}

// 箭頭函數(shù)的 this 永遠(yuǎn)取上級(jí)作用域的 this
const zhangsan = {
    name: 'zhangsan',
    // this 即當(dāng)前對(duì)象
    greeting() {
        console.log(this)
    },
    wait() {
        setTimeout(() => {
            // this 即當(dāng)前對(duì)象
            console.log(this)
        })
    }
}

創(chuàng)建 10 個(gè) <a> 標(biāo)簽點(diǎn)擊的時(shí)候彈出對(duì)應(yīng)的序號(hào)

let a
for (let i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function(e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}

手寫 bind 函數(shù)

Function.prototype.myBind = function() {
    // 將參數(shù)拆解為數(shù)組
    const args = Array.prototype.slice.call(arguments)

    // 獲取 this(數(shù)組第一項(xiàng))
    const that = args.shift()

    // fn.bind(...) 中的 fn
    const self = this

    // 返回一個(gè)函數(shù)
    return function() {
        return self.apply(that, args)
    }
}

實(shí)際開發(fā)中閉包的應(yīng)用

  • 隱藏?cái)?shù)據(jù)

  • 如做一個(gè)簡(jiǎn)單的 cache 工具

  • function createCache() {
        const data = {} // 閉包中的數(shù)據(jù),被隱藏衫画,不被外界訪問
        return {
            set(key, value) {
                data[key] = value
            },
            get(key) {
                return data[key]
            }
        }
    }
    
    const c = createCache()
    c.set('a', 100)
    console.log(c.get('a'))
    

異步

  • 同步和異步得區(qū)別是什么毫炉?

  • 手寫 Promise 加載一張圖片

  • 前端使用異步的場(chǎng)景

  • 請(qǐng)描述 event loop (事件循環(huán)/事件輪詢)的機(jī)制,可畫圖

  • 什么是宏認(rèn)為和微任務(wù)削罩,兩者有什么區(qū)別瞄勾?

  • Promise 有哪三種狀態(tài)?如何變化弥激?

  • Promise 的 then 和 catch 的連接問題

  • async/await 語法

  • Promise 和 setTimeout 的順序問題

單線程

  • JS 是單線程語言进陡,只能同時(shí)做一件事
  • 瀏覽器和 nodejs 已支持 JS 啟動(dòng)進(jìn)程,如 Web Worker
  • JS 和 DOM 渲染共用同一個(gè)線程微服,因?yàn)?JS 可修改 DOM 結(jié)構(gòu)
  • 異步基于 回調(diào) callback 函數(shù)形式

callback

// 異步
console.log(100)
setTimeout(function() {
  console.log(200)
}, 1000)
console.log(300)

// 同步
console.log(100)
alert(200)
console.log(300)

異步不會(huì)阻塞代碼執(zhí)行

同步會(huì)阻塞代碼執(zhí)行

應(yīng)用場(chǎng)景

  • 網(wǎng)絡(luò)請(qǐng)求趾疚,如 ajax 圖片加載
  • 定時(shí)任務(wù),如 setTimeout

promise

基本使用

// 加載圖片
function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`圖片加載失敗 ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
    return p
}
const url = 'www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
loadImg(url).then(img => {
    console.log(img.width)
    return img
}).then(img => {
    console.log(img.height)
}).catch(ex => console.error(ex))

狀態(tài)

  • 三種狀態(tài)
    • pending
    • resolved
    • rejected
    • 變化: pending => resolved 或 pending => rejected
    • 變化是不可逆的
  • 狀態(tài)的表現(xiàn)和變化
    • pending 狀態(tài)以蕴,不會(huì)觸發(fā) then 和 catch
    • resolved 狀態(tài)糙麦,會(huì)觸發(fā)后續(xù)的 then 回調(diào)函數(shù)
    • rejected 狀態(tài),會(huì)觸發(fā)后續(xù)的 catch 回調(diào)函數(shù)
const p1 = new Promise((resolve, reject) => {})
console.log(p1) // pending

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  })
})
console.log(p2) // pending 一開始打印時(shí)
setTimeout(() => console.log(p2)) // resolved

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject()
  })
})
console.log(p3) // pending 一開始打印時(shí)
setTimeout(() => console.log(p3)) // rejected

// 直接獲取一個(gè) resolved 狀態(tài)的 Promise
const resolved = Promise.resolve(100)
console.log(resolved) // resolved

// 直接獲取一個(gè) rejected 狀態(tài)的 Promise
const resolved = Promise.reject('err')
console.log(resolved) // rejected
  • then 和 catch 對(duì)狀態(tài)的影響
    • then 正常返回 resolved 舒裤,里面有報(bào)錯(cuò)則返回 rejected
    • catch正常返回 resolved 喳资,里面有報(bào)錯(cuò)則返回 rejected
// then() 一般正常返回 resolved 狀態(tài)的 promise
Promise.resolve().then(() => {
    return 100
})

// then() 里拋出錯(cuò)誤,會(huì)返回 rejected 狀態(tài)的 promise
Promise.resolve().then(() => {
    throw new Error('err')
})

// catch() 不拋出錯(cuò)誤腾供,會(huì)返回 resolved 狀態(tài)的 promise
Promise.reject().catch(() => {
    console.error('catch some error')
})

// catch() 拋出錯(cuò)誤仆邓,會(huì)返回 rejected 狀態(tài)的 promise
Promise.reject().catch(() => {
    console.error('catch some error')
    throw new Error('err')
})

// 第一題
Promise.resolve().then(() => {
    console.log(1)
}).catch(() => {
    console.log(2)
}).then(() => {
    console.log(3)
})

// 第二題
Promise.resolve().then(() => { // 返回 rejected 狀態(tài)的 promise
    console.log(1)
    throw new Error('erro1')
}).catch(() => { // 返回 resolved 狀態(tài)的 promise
    console.log(2)
}).then(() => {
    console.log(3)
})

// 第三題
Promise.resolve().then(() => { // 返回 rejected 狀態(tài)的 promise
    console.log(1)
    throw new Error('erro1')
}).catch(() => { // 返回 resolved 狀態(tài)的 promise
    console.log(2)
}).catch(() => {
    console.log(3)
})

event-loop

  • JS 是單線程運(yùn)行的
  • 異步要基于回調(diào)來實(shí)現(xiàn)
  • event loop 就是異步回調(diào)的實(shí)現(xiàn)原理

JS 如何執(zhí)行的

  • 從前到后,一行一行執(zhí)行
  • 如果某一行執(zhí)行報(bào)錯(cuò)伴鳖,則停止下面代碼的執(zhí)行
  • 先把同步代碼執(zhí)行完节值,再執(zhí)行異步

event loop 執(zhí)行過程

  • 同步代碼,一行一行放在 Call Stack 執(zhí)行
  • 遇到異步榜聂,會(huì)先 “記錄” 下搞疗,等待時(shí)機(jī)(定時(shí),網(wǎng)絡(luò)請(qǐng)求)
  • 時(shí)機(jī)到了须肆,就移動(dòng)到 Callback Queue
  • 如果 Call Stack 為空(即同步代碼執(zhí)行完)Event Loop 開始工作
  • 輪詢查找 Callback Queue 匿乃,如果有則移動(dòng)到 Call Stack 執(zhí)行
  • 然后繼續(xù)輪詢查找(永動(dòng)機(jī)一樣)

DOM 事件和 event loop

  • 異步(setTimeout桩皿,ajax 等)使用回調(diào),基于 event loop
  • DOM 事件也使用回調(diào)幢炸,基于 event loop

async/await

  • 異步回調(diào) callback hell
  • Promise 基于 then catch 鏈?zhǔn)秸{(diào)用泄隔,但也是基于回調(diào)函數(shù)
  • async/await 是同步語法,徹底消滅回調(diào)函數(shù)

有很多 async 的面試題宛徊,例如

  • async 直接返回佛嬉,是什么
  • async 直接返回 promise
  • await 后面不加 promise

基本語法

function loadImg(src) {
    const promise = new Promise((resolve, reject) => {
        const img = document.createElement('img')
        img.onload = () => {
            resolve(img)
        }
        img.onerror = () => {
            reject(new Error(`圖片加載失敗 ${src}`))
        }
        img.src = src
    })
    return promise
}

async function loadImg1() {
    const src1 = 'www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
    const img1 = await loadImg(src1)
    return img1
}

async function loadImg2() {
    const src2 = 'https://avatars3.githubusercontent.com/u/9583120'
    const img2 = await loadImg(src2)
    return img2
}

(async function () {
    // 注意:await 必須放在 async 函數(shù)中,否則會(huì)報(bào)錯(cuò)
    try {
        // 加載第一張圖片
        const img1 = await loadImg1()
        console.log(img1)
        // 加載第二張圖片
        const img2 = await loadImg2()
        console.log(img2)
    } catch (ex) {
        console.error(ex)
    }
})()

async/await 和 promise 的關(guān)系

  • async/await 是消滅異步回調(diào)的終極武器
  • 但和 promise 并不互斥
  • 兩者反而相輔相成
  • await 相當(dāng)于 promise 的 then
  • try...catch 可捕獲異常闸天,代替了 promise 的 catch
  • async 函數(shù)返回結(jié)果都是 Promise 對(duì)象(如果函數(shù)內(nèi)沒返回 Promise 暖呕,則自動(dòng)封裝一下)
async function fn2() {
    return new Promise(() => {})
}
console.log( fn2() )

async function fn1() {
    return 100
}
console.log( fn1() ) // 相當(dāng)于 Promise.resolve(100)
  • await 后面跟 Promise 對(duì)象:會(huì)阻斷后續(xù)代碼,等待狀態(tài)變?yōu)?resolved 苞氮,才獲取結(jié)果并繼續(xù)執(zhí)行
  • await 后續(xù)跟非 Promise 對(duì)象:會(huì)直接返回
(async function () {
    const p1 = new Promise(() => {})
    await p1
    console.log('p1') // 不會(huì)執(zhí)行
})()

(async function () {
    const p2 = Promise.resolve(100)
    const res = await p2
    console.log(res) // 100
})()

(async function () {
    const res = await 100
    console.log(res) // 100
})()

(async function () {
    const p3 = Promise.reject('some err')
    const res = await p3
    console.log(res) // 不會(huì)執(zhí)行
})()
  • try...catch 捕獲 rejected 狀態(tài)
(async function () {
    const p4 = Promise.reject('some err')
    try {
        const res = await p4
        console.log(res)
    } catch (ex) {
        console.error(ex)
    }
})()

總結(jié)來看:

  • async 封裝 Promise
  • await 處理 Promise 成功
  • try...catch 處理 Promise 失敗

異步本質(zhì)

await 是同步寫法湾揽,但本質(zhì)還是異步調(diào)用。

async function async1 () {
  console.log('async1 start')
  await async2()
  console.log('async1 end') // 關(guān)鍵在這一步笼吟,它相當(dāng)于放在 callback 中钝腺,最后執(zhí)行
}

async function async2 () {
  console.log('async2')
}

console.log('script start')
async1()
console.log('script end')

即,只要遇到了 await 赞厕,后面的代碼都相當(dāng)于放在 callback 里。

for...of

  • for ... in (以及 forEach for)是常規(guī)的同步遍歷
  • for ... of 常用與異步的循環(huán)
// 定時(shí)算乘法
function multi(num) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(num * num)
        }, 1000)
    })
}

// // 使用 forEach 定硝,是 1s 之后打印出所有結(jié)果皿桑,即 3 個(gè)值是一起被計(jì)算出來的
// function test1 () {
//     const nums = [1, 2, 3];
//     nums.forEach(async x => {
//         const res = await multi(x);
//         console.log(res);
//     })
// }
// test1();

// 使用 for...of ,可以讓計(jì)算挨個(gè)串行執(zhí)行
async function test2 () {
    const nums = [1, 2, 3];
    for (let x of nums) {
        // 在 for...of 循環(huán)體的內(nèi)部蔬啡,遇到 await 會(huì)挨個(gè)串行計(jì)算
        const res = await multi(x)
        console.log(res)
    }
}
test2()

微任務(wù)/宏任務(wù)

  • 宏任務(wù):setTimeout setInterval DOM 事件
  • 微任務(wù):Promise(對(duì)于前端來說)
  • 微任務(wù)比宏任務(wù)執(zhí)行的更早
console.log(100)
setTimeout(() => {
    console.log(200)
})
Promise.resolve().then(() => {
    console.log(300)
})
console.log(400)
// 100 400 300 200

event loop 和 DOM 渲染

  • 每一次 call stack 結(jié)束诲侮,都會(huì)觸發(fā) DOM 渲染(不一定非得渲染,就是給一次 DOM 渲染的機(jī)會(huì)O潴 )
  • 然后再進(jìn)行 event loop
const $p1 = $('<p>一段文字</p>')
const $p2 = $('<p>一段文字</p>')
const $p3 = $('<p>一段文字</p>')
$('#container')
            .append($p1)
            .append($p2)
            .append($p3)

console.log('length',  $('#container').children().length )
alert('本次 call stack 結(jié)束沟绪,DOM 結(jié)構(gòu)已更新,但尚未觸發(fā)渲染')
// (alert 會(huì)阻斷 js 執(zhí)行空猜,也會(huì)阻斷 DOM 渲染绽慈,便于查看效果)
// 到此,即本次 call stack 結(jié)束后(同步任務(wù)都執(zhí)行完了)辈毯,瀏覽器會(huì)自動(dòng)觸發(fā)渲染坝疼,不用代碼干預(yù)

// 另外,按照 event loop 觸發(fā) DOM 渲染時(shí)機(jī)谆沃,setTimeout 時(shí) alert 钝凶,就能看到 DOM 渲染后的結(jié)果了
setTimeout(function () {
    alert('setTimeout 是在下一次 Call Stack ,就能看到 DOM 渲染出來的結(jié)果了')
})

宏任務(wù)和微任務(wù)的區(qū)別

  • 宏任務(wù):DOM 渲染后再觸發(fā)
  • 微任務(wù):DOM 渲染前會(huì)觸發(fā)
// 修改 DOM
const $p1 = $('<p>一段文字</p>')
const $p2 = $('<p>一段文字</p>')
const $p3 = $('<p>一段文字</p>')
$('#container')
    .append($p1)
    .append($p2)
    .append($p3)

// // 微任務(wù):渲染之前執(zhí)行(DOM 結(jié)構(gòu)已更新)
// Promise.resolve().then(() => {
//     const length = $('#container').children().length
//     alert(`micro task ${length}`)
// })

// 宏任務(wù):渲染之后執(zhí)行(DOM 結(jié)構(gòu)已更新)
setTimeout(() => {
    const length = $('#container').children().length
    alert(`macro task ${length}`)
})

再深入思考一下:為何兩者會(huì)有以上區(qū)別唁影,一個(gè)在渲染前耕陷,一個(gè)在渲染后掂名?

  • 微任務(wù):ES 語法標(biāo)準(zhǔn)之內(nèi),JS 引擎來統(tǒng)一處理哟沫。即饺蔑,不用瀏覽器有任何關(guān)于,即可一次性處理完南用,更快更及時(shí)膀钠。
  • 宏任務(wù):ES 語法沒有,JS 引擎不處理裹虫,瀏覽器(或 nodejs)干預(yù)處理肿嘲。

經(jīng)典面試題

async function async1 () {
  console.log('async1 start')
  await async2() // 這一句會(huì)同步執(zhí)行,返回 Promise 筑公,其中的 `console.log('async2')` 也會(huì)同步執(zhí)行
  console.log('async1 end') // 上面有 await 雳窟,下面就變成了“異步”,類似 cakkback 的功能(微任務(wù))
}

async function async2 () {
  console.log('async2')
}

console.log('script start')

setTimeout(function () { // 異步匣屡,宏任務(wù)
  console.log('setTimeout')
}, 0)

async1()

new Promise (function (resolve) { // 返回 Promise 之后封救,即同步執(zhí)行完成,then 是異步代碼
  console.log('promise1') // Promise 的函數(shù)體會(huì)立刻執(zhí)行
  resolve()
}).then (function () { // 異步捣作,微任務(wù)
  console.log('promise2')
})

console.log('script end')

// 同步代碼執(zhí)行完之后誉结,屢一下現(xiàn)有的異步未執(zhí)行的,按照順序
// 1. async1 函數(shù)中 await 后面的內(nèi)容 —— 微任務(wù)
// 2. setTimeout —— 宏任務(wù)
// 3. then —— 微任務(wù)

模塊化

ES6 Module

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末券躁,一起剝皮案震驚了整個(gè)濱河市惩坑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌也拜,老刑警劉巖以舒,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異慢哈,居然都是意外死亡蔓钟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門卵贱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滥沫,“玉大人,你說我怎么就攤上這事键俱∮缎常” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵方妖,是天一觀的道長(zhǎng)狭魂。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么雌澄? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任斋泄,我火速辦了婚禮,結(jié)果婚禮上镐牺,老公的妹妹穿的比我還像新娘炫掐。我一直安慰自己,他們只是感情好睬涧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布募胃。 她就那樣靜靜地躺著,像睡著了一般畦浓。 火紅的嫁衣襯著肌膚如雪痹束。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天讶请,我揣著相機(jī)與錄音祷嘶,去河邊找鬼。 笑死夺溢,一個(gè)胖子當(dāng)著我的面吹牛论巍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播风响,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼嘉汰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了状勤?” 一聲冷哼從身側(cè)響起郑现,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荧降,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攒读,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡朵诫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薄扁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剪返。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖邓梅,靈堂內(nèi)的尸體忽然破棺而出脱盲,到底是詐尸還是另有隱情,我是刑警寧澤日缨,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布钱反,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏面哥。R本人自食惡果不足惜哎壳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尚卫。 院中可真熱鬧归榕,春花似錦、人聲如沸吱涉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怎爵。三九已至特石,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疙咸,已是汗流浹背县匠。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撒轮,地道東北人乞旦。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像题山,于是被迫代替她去往敵國(guó)和親兰粉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 針對(duì)面試的 JavaScript 知識(shí)點(diǎn)整理 1.介紹一下js的數(shù)據(jù)類型有哪些顶瞳,值是如何存儲(chǔ)的 JavaSc...
    Moon_f3e1閱讀 229評(píng)論 0 0
  • 1玖姑,什么是單線程,和異步有什么關(guān)系 單線程-只有一個(gè)線程慨菱,只能做一件事 單線程的原因:避免DOM 渲染的沖突 瀏覽...
    darrell閱讀 562評(píng)論 0 1
  • 今天感恩節(jié)哎焰络,感謝一直在我身邊的親朋好友。感恩相遇符喝!感恩不離不棄闪彼。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,559評(píng)論 0 11
  • 彩排完协饲,天已黑
    劉凱書法閱讀 4,199評(píng)論 1 3
  • 表情是什么畏腕,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息茉稠。高興了當(dāng)然就笑了描馅,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,445評(píng)論 2 7