Blog Logo

前端高级知识点(一)

写于2021-03-17 08:39 阅读耗时13分钟 阅读量


  • 一、高阶函数
    • 什么是高阶函数
    • 高阶函数应用场景
  • 二、柯里化函数
    • 判断变量类型的方法
    • 柯里化函数
  • 三、观察者模式
    • 什么是闭包
    • 订阅发布模式
    • 观察者模式
  • 四、手写Promise
    • Promise/A+规范
    • Promise为何产生?
    • Promise优缺点?
    • Promise特点?
    • 实现一个简单Promise
    • 进一步实现一个简单Promise
    • 实现一个完整的promise库
    • 测试promise
    • 实现resolve、reject、catch、finally
    • 实现race、all

一、高阶函数

1.什么是高阶函数?

1.参数是函数

function say(cb) {
    cb()
}

2.函数返回函数

function say() {
    return function() {}
}

2.高阶函数应用场景?

需要在公共方法前调用其他方法

// 公共方法
function say() {
    console.log('say')
}

// say方法前调用一个beforeSay
Function.prototype.before = function(cb) {
    const that = this
    return function() {
        cb()
        that()
    }
}
const beforeSay = say.before(function(){
    console.log('beforeSay')
})
beforeSay()

可以换成()=>

Function.prototype.before = function(cb) {
    return () => {
        cb()
        this()
    }
}

实现传参:

// 公共方法
function say(a, b) {
    console.log('say', a, b)
}

// say方法前调用一个beforeSay
Function.prototype.before = function(cb) {
    return (...args) => {
        cb()
        this(...args)
    }
}
const beforeSay = say.before(function(){
    console.log('beforeSay')
})
beforeSay('hello', 'world')

箭头函数无arguments。 ...的意义: return (...args)剩余运算符this(...args)展开运算符


二、柯里化函数

1.判断变量类型的方法

1.typeof 判断不出对象类型

typeof [] // object
typeof {} // object

2.constructor 谁构造出来的

[].constructor // Array
({}).constructor // Object

3.inistanceof 谁是谁的实例 proto

[] instanceof Array // true
({}) instanceof Object // true

4.Object.prototype.toString.call()

Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call({}) // [object Object]

Array.isArray的原理:

Array.myIsArray = function(o) {
    return Object.prototype.toString.call(Object(o) === '[object Array]');
}

2.柯里化函数

1.类型判断

function isType(value, type) {
    return Object.prototype.toString.call(value) === `[object ${type}]`
}

isType([], "Array") // true
isType({}, "Object") // true

2.柯里化函数实现类型判断

function isType(type) {
    return function(value) {
        return Object.prototype.toString.call(value) === `[object ${type}]`
    }
}
const isArray = isType('Array')
const isObject = isType('Object')
isArray([]) // true
isObject({}) // true

3.柯里化函数实现柯里化方法 实现一个currying方法,使其成立?

function sum(a,b,c,d,e,f){
    return a+b+c+d+e+f
}

const r = currying(sum)(1,2)(3,4)(5)(6)
// 输出21

function currying() {
  // TODO
  ...
}

实现如下:

const currying = (fn, arr = []) => {
    const len = fn.length
    return function(...args) {
        arr = [...arr, ...args]
        if(arr.length < len) {
            return currying(fn, arr)
        } else {
            return fn(...arr)
        }
    }
}

4.currying方法同样作用于isType

// 基础:
function isType(value, type) {
    return Object.prototype.toString.call(value) === `[object ${type}]`
}
isType([], "Array")

// 进阶:
function isType(type) {
    return function(value) {
        return Object.prototype.toString.call(value) === `[object ${type}]`
    }
}
// 进阶一:
const isArray = isType('Array')
isArray([])

// 进阶二:
const isArray = currying(isType)('Array')
isArray([])

三、观察者模式

1.什么是闭包?

函数定义和执行不在同一个作用域下。 举例:同步获取两个txt的内容

let fs = require('fs')
let school = {}
let index = 0
const cb = () => {
    if(++index === 2) {
        console.log(school)
    }
}
fs.readFile('./name.txt', 'utf-8', function(err, data){
    school.name = data
    cb()
})
fs.readFile('./age.txt', 'utf-8', function(err, data){
    school.age = data
    cb()
})
// 输出{ name: 'wuwei', age: '28' }

使用闭包:

const cb = after(2, function() {
    console.log(school)
})
function after(times, callback) {
    // 闭包
    return function() {
        if(--times === 0) {
            callback()
        }
    }
}

2.订阅发布模式

emit-on emit:订阅,数组中的方法依次执行 on:发布,方法添加到数组

let fs = require('fs')
let school = {}
fs.readFile('./name.txt', 'utf-8', function(err, data){
    school.name = data
    event.emit()
})
fs.readFile('./age.txt', 'utf-8', function(err, data){
    school.age = data
    event.emit()
})

let event = {
    arr: [],
    on(fn) {
        this.arr.push(fn)
    },
    emit() {
        this.arr.forEach(fn=>fn())
    }
}
event.on(function(){
    if(Object.keys(school).length === 2) {
        console.log(school)
    }
})

订阅发布无直接关联,靠中介来完成。 观察者模式有直接关联。


3.观察者模式

有观察者、被观察者。 观察者放到被观察者中,被观察者发生改变通知观察者。 内部用到发布订阅模式,收集观察者。

举例:我和我媳妇儿观察小宝宝的心里状态变化

// 观察者模式
// 观察者、被观察者
class Subject { // 被观察者 小宝宝
    constructor(name) {
        this.name = name
        this.state = '开心的'
        this.observers = []
    }
    // Subject.prototype.attach
    attach(o) {
        this.observers.push(o)
    }
    setState(newState) {
        this.state = newState
        this.observers.forEach(o=>o.update(this))
    }
}

class Observer { // 观察者 我/我媳妇儿
    constructor(name) {
        this.name = name
    }
    update(o) {
        console.log('当前',this.name,'被通知了',',当前小宝宝的状态是',o.state)
    }
}

let baby = new Subject('小宝宝')
let parent = new Observer('爸爸')
let monther = new Observer('妈妈')
// 爸爸观察小宝宝
baby.attach(parent)
// 妈妈观察小宝宝
baby.attach(monther)
// 小宝宝被欺负了
baby.setState('被欺负了')

// 输出
// 当前 爸爸 被通知了 ,当前小宝宝的状态是 被欺负了
// 当前 妈妈 被通知了 ,当前小宝宝的状态是 被欺负了

四.手写Promise

1.Promise/A+规范

Promise都通过这个规范来实现。 ES6内部已经实现、IE都不支持Promise,需要polyfill,es6-promise。 地址:https://promisesaplus.com


2.Promise为何产生?

解决异步问题。


3.Promise优缺点?

优点: 1.解决多个异步请求最终获取同步结果 Promise.all

2.解决链式异步请求问题,上一个的输出是下一个的输入 使用Promise链式调用

缺点:还是基于回调实现的


4.Promise特点?

1.Promise有三种状态:成功态、失败态、等待态 2.成功fulfilled,失败rejected、等待pending(不成功也不失败) 3.用户自己定义成功失败原因 4.promise构造方法会立即执行 5.成功后不执行失败,失败后不执行成功 6.出异常也会走失败回调 7.promise实例有then方法,一个参数是成功回调,一个参数是失败回调

let promise = new Promise((resolve, reject)=>{
    resolve('success')
    reject('error')
    throw new Error('error')
})
promise.then((rst)=>{
    console.log(rst)
},(err)=>{
    console.error('fail', err)
})

5.实现一个简单Promise

基于Promise上面提到的7个特点来写Promise:

const RESOLVE = 'fulfilled'
const REJECT = 'rejected'
const PENDING = 'pending'

class Promise {
    constructor(executor) {
        this.state = PENDING
        this.value = undefined
        this.reason = undefined
        let resolve = (value) => {
            if (this.state === PENDING) {
                this.value = value
                this.state = RESOLVE
            }
        }
        let reject = (err) => {
            if (this.state === PENDING) {
                this.reason = err
                this.state = REJECT
            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onFulfilled, onRejected) {
        if (this.state === RESOLVE) {
            onFulfilled(this.value)
        }
        if (this.state === REJECT) {
            onRejected(this.reason)
        }
    }
}

6.进一步实现一个简单Promise

Promise除了上面7个特点外,还有个重要特点: 一个prmoise实例可以多次then,当前状态如果是pending时,需要将成功回调、失败回调存放起来,稍后调用。

let promise = new Promise((resolve, reject)=>{
    console.log('1')
    setTimeout(() => {
        resolve()
    })
})
promise.then(()=>{
    console.log('2')
},(err)=>{
    console.log('3')
})

console.log('4')
promise.then(()=>{
    console.log('5')
},(err)=>{
    console.log('6')
})
console.log('7')

执行结果:1、4、7、2、5


为了依次执行then方法的成功和失败回调,使用订阅发布模式将其存起来。 完整Promise实现如下:

const RESOLVE = 'fulfilled'
const REJECT = 'rejected'
const PENDING = 'pending'

class Promise {
    constructor(executor) {
        this.state = PENDING
        this.value = undefined
        this.reason = undefined
        this.onResolvedCallbacks = []
        this.onRejectedCallbacks = []
        let resolve = (value) => {
            if (this.state === PENDING) {
                this.value = value
                this.state = RESOLVE
                this.onResolvedCallbacks.forEach(fn=>fn())
            }
        }
        let reject = (err) => {
            if (this.state === PENDING) {
                this.reason = err
                this.state = REJECT
                this.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onFulfilled, onRejected) {
        if (this.state === RESOLVE) {
            onFulfilled(this.value)
        }
        if (this.state === REJECT) {
            onRejected(this.reason)
        }
        if(this.state === PENDING) {
            this.onResolvedCallbacks.push(() => {
                onFulfilled(this.value)
            })
            this.onRejectedCallbacks.push(() => {
                onRejected(this.reason)
            })
        }
    }
}

7.实现一个完整的promise库

除了上面特点,promise还有以下特点:

  • 1.prmoise成功和失败的回调的返回值,可以传递到外层的then
  • 2.返回值是普通值、promise、出错
    • 普通值,走下一次成功 出错,走下一次失败
    • 值promise,采用promise状态,成功走成功,失败走失败
    • 错误处理 如果离自己最近的then,没出错,会向下找
  • 3.每次执行promise,then返回一个”新的promise“
  • 4.then需要实现透传
  • 5.兼容其他promise ...
const RESOLVE = 'fulfilled'
const REJECT = 'reject'
const PENDING = 'pending'
const resolvePromise = (promise2, x, resolve, reject) => {
    if(promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    let called;
    if((typeof x === 'object' && x!==null) || typeof x === 'function') {
        try {
            let then = x.then
            if (typeof then === 'function') {
                then.call(x, y=>{
                    if (called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject)
                },e=>{
                    if (called) return;
                    called = true;
                    reject(e)
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e)
        }
    } else {
        resolve(x)
    }
}
class Promise {
    constructor(executor) {
        this.state = PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
        let resolve = (value) => {
            if(value instanceof Promise){
                return value.then(resolve,reject);
            }
            if (this.state === PENDING) {
                this.value = value
                this.state = RESOLVE
                this.onFulfilledCallbacks.forEach(fn=>fn())
            }
        }
        let reject = (reason) => {
            if (this.state === PENDING) {
                this.reason = reason
                this.state = REJECT
                this.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
        let promise2 = new Promise((resolve, reject)=>{
            if (this.state === RESOLVE) {
                setTimeout(()=>{
                    try {
                        let x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                },0)
            }
            if (this.state === REJECT) {
                setTimeout(()=>{
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                },0)

            }
            if (this.state === PENDING) {
                this.onFulfilledCallbacks.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    },0)
                })
                this.onRejectedCallbacks.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    },0)
                })
            }
        })
        return promise2
    }

}
Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd
}
module.exports = Promise

8.测试promise

promise的延迟对象,将resolve 和 reject放到一个对象中:

Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd
}

安装npm install promises-aplus-tests -g; 运行promises-aplus-tests Promise.js进行测试。

运行测试结果,如果有错误或未完善,则抛出需要更改的点:

error


测试成功:

success


9.实现resolve、reject、catch、finally

Promise.resolve:快速创建一个成功的promise Promise.reject:快速创建一个失败的promise

class Promise {
    ...
    static resolve(data){
        return new Promise((resolve,reject)=>{
            resolve(data);
        })
    }
    static reject(reason){
        return new Promise((resolve,reject)=>{
            reject(reason);
        })
    }
}

catch:catch的本质就是then方法,表示的是没有成功的失败函数

Promise.prototype.catch = function(errCallback) {
    return this.then(null,errCallback)
}

finally:finally的本质就是then方法,表示的是无论如何都会执行

Promise.prototype.finally = function(callback) {
    return this.then((value)=>{
        return Promise.resolve(callback()).then(()=>value)
    },(reason)=>{
        return Promise.reject(callback()).then(()=>{throw reason})
    })
}

10.实现race、all

Promise.race:快速执行所有promise,哪个快,返回哪个的结果 Promise.all:快速执行所有promise,全部成功才成功,返回所有结果数组

class Promise {
    ...
    static race(promises){
        return new Promise((resolve,reject)=>{
            for(let i = 0; i < promises.length; i++) {
                let result = promises[i]
                if(typeof result.then === 'function'){
                    result.then(resolve,reject)
                }else{
                    resolve(result)
                }
            }
        })
    }
    
    static all(promises){
        return new Promise((resolve,reject)=>{
            let arr = []
            let index = 0
            const processData = (key, value) => {
                arr[key] = value
                if(++index === promises.length) {
                    resolve(arr)
                }
            }
            for(let i = 0; i < promises.length; i++) {
                let result = promises[i]
                if(typeof result.then === 'function'){
                    result.then((data)=>{
                        processData(i,data)
                    },reject)
                }else{
                    processData(i,result)
                }
            }
        })
    }
}

Headshot of Maxi Ferreira

怀着敬畏之心,做好每一件事。