STAY HUNGRY , STAY FOOLISH.

求知若饥,虚心若愚。

       浏览:

前端高级知识点(一)

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

一、高阶函数

1.什么是高阶函数?

1.参数是函数

1
2
3
function say(cb) {
cb()
}

2.函数返回函数

1
2
3
function say() {
return function() {}
}

2.高阶函数应用场景?

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

1
2
3
4
// 公共方法
function say() {
console.log('say')
}

1
2
3
4
5
6
7
8
9
10
11
12
// say方法前调用一个beforeSay
Function.prototype.before = function(cb) {
const that = this
return function() {
cb()
that()
}
}
const beforeSay = say.before(function(){
console.log('beforeSay')
})
beforeSay()

可以换成()=>

1
2
3
4
5
6
Function.prototype.before = function(cb) {
return () => {
cb()
this()
}
}

实现传参:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 公共方法
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 判断不出对象类型

1
2
typeof [] // object
typeof {} // object

2.constructor 谁构造出来的

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

3.inistanceof 谁是谁的实例 proto

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

4.Object.prototype.toString.call()

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

Array.isArray的原理:

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

2.柯里化函数

1.类型判断

1
2
3
4
5
6
function isType(value, type) {
return Object.prototype.toString.call(value) === `[object ${type}]`
}

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

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

1
2
3
4
5
6
7
8
9
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方法,使其成立?

1
2
3
4
5
6
7
8
9
10
11
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
...
}

实现如下:

1
2
3
4
5
6
7
8
9
10
11
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 基础:
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的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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' }

使用闭包:

1
2
3
4
5
6
7
8
9
10
11
const cb = after(2, function() {
console.log(school)
})
function after(times, callback) {
// 闭包
return function() {
if(--times === 0) {
callback()
}
}
}

2.订阅发布模式

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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.观察者模式

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 观察者模式
// 观察者、被观察者
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方法,一个参数是成功回调,一个参数是失败回调

1
2
3
4
5
6
7
8
9
10
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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时,需要将成功回调、失败回调存放起来,稍后调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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放到一个对象中:

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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方法,表示的是没有成功的失败函数

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

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

1
2
3
4
5
6
7
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,全部成功才成功,返回所有结果数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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)
}
}
})
}
}