bind函数实现
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
由此我们可以首先得出 bind 函数的两个特点:
- 返回一个函数
- 可以传入参数
首先第一个功能在于传入的第一个参数改变this
1 2 3 4 5 6 7 8 9 10 11 12
| var foo = { value: 1 };
function bar() { console.log(this.value); }
var bindFoo = bar.bind(foo);
bindFoo();
|
关于指定 this 的指向,我们可以使用 call 或者 apply 实现,关于 call 和 apply 的模拟实现
1 2 3 4 5 6 7
| Function.prototype.bind2 = function(newThis){ var self = this return function(){ return self.apply(newThis) } }
|
接下来看第二点,可以传入参数。这个就有点让人费解了,我在 bind 的时候,是否可以传参呢?我在执行 bind 返回的函数的时候,可不可以传参呢?让我们看个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var foo = { value: 1 };
function bar(name, age) { console.log(this.value); console.log(name); console.log(age);
}
var bindFoo = bar.bind(foo, 'daisy'); bindFoo('18');
|
函数需要传 name 和 age 两个参数,竟然还可以在 bind 的时候,只传一个 name,在执行返回的函数的时候,再传另一个参数 age!
这可咋办?不急,我们用 arguments 进行处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.bind2 = function (context) {
var self = this; var args = Array.prototype.slice.call(arguments, 1);
return function () { var bindArgs = Array.prototype.slice.call(arguments); return self.apply(context, args.concat(bindArgs)); }
}
|
完成了这两点,最难的部分到啦!因为 bind 还有一个特点,就是
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
也就是说当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效。举个例子
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
| var value = 2;
var foo = { value: 1 };
function bar(name, age) { this.habit = 'shopping'; console.log(this.value); console.log(name); console.log(age); }
bar.prototype.friend = 'kevin';
var bindFoo = bar.bind(foo, 'daisy');
var obj = new bindFoo('18');
console.log(obj.habit); console.log(obj.friend);
|
注意:尽管在全局和 foo 中都声明了 value 值,最后依然返回了 undefind,说明绑定的 this 失效了,如果大家了解 new 的模拟实现,就会知道这个时候的 this 已经指向了 obj。
所以我们可以通过修改返回的函数的原型来实现,让我们写一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Function.prototype.bind2 = function (context) { var self = this; var args = Array.prototype.slice.call(arguments, 1);
var fBound = function () { var bindArgs = Array.prototype.slice.call(arguments); return self.apply(this instanceof fBound ? this : context, args.concat(bindArgs)); } fBound.prototype = this.prototype; return fBound; }
|
Promise
Promise的三种状态
pending 等待(比如网络请求需要一定的时间,这个过程为等待)
fulfill 完成(回调resolve函数)
reject 拒绝(回调reject函数)
一般情况下是在有异步操作时,使用Promise对异步操作进行封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| new Promise((resolve,reject) => { setTimeout(() => { resolve('学习promise')
},2000) }).then(value => { console.log(value); },reason=>{ console.log(reason); }).catch(err => { console.log(err); })
|
new Promise需要传入两个参数,一个为resolve,另一个为reject,这两个都是函数.
每个promise和下面的then都是一对,只有promise中resole或reject了(即promise的状态不是pedding),then中的回调函数才会执行
如果里面返回的对象有then方法,则也会自动封装成一个promise对象
catch
catch会处理前面没有在then里处理的错误
promise all
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Promise.all([ new Promise((resolve,reject) => { setTimeout(() => { resolve({name:'请求1',age:'18'}) },2000) }), new Promise((resolve,reject) => { setTimeout(() => { resolve({name:'请求2',age:'23'}) },2000) }) ]).then(res => { console.log(res); })
|
只有当promise.all中的所有promise都完成后才会执行then.其中then中的res是一个数组,是每个请求的结果.
如果其中有一个promise返回的是reject状态切没有被处理,则整个Promise.all返回的就是失败状态.如果传入的promise自己有处理失败的操作,则返回
Promise.Settled
传入一个promise数组,返回的是所有promise返回的结果的数组,不管是否成功.因此Promise.Settled返回的结果永远是成功
Promise.race
传入的promise数组中谁先返回结果就返回谁
使用map实现promise队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let a = [1, 3, 4, 5, 6] let promise = Promise.resolve() a.map(num => { promise = promise.then(value => { return new Promise(resolve => { setTimeout(() => { console.log(num); resolve() }, 1000); })
}) })
//每隔一秒输出
|
let a = [1, 3, 4, 5, 6]
let promise = Promise.resolve()
a.map(num => {
promise.then(value => {
return new Promise(resolve => {
setTimeout(() => {
console.log(num);
resolve()
}, 1000);
})
})
})
//一秒后一起输出
async与await语法糖
手撕
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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
| (function(window){ function Promise(excutor){ const that = this that.status = 'pending' that.data = undefined that.callbacks = [] function resolve(value){ if(that.status!=='pending'){ return } that.status = 'resolved' that.data = value if(that.callbacks.length>0){ setTimeout(()=>{ that.callbacks.forEach(callbacksObj=>{ callbacksObj.onResolved(value) }) },0) } } function reject(reason){ if(that.status!=='pending'){ return } that.status = 'rejected' that.data = reason if(that.callbacks.length>0){ setTimeout(()=>{ that.callbacks.forEach(callbacksObj=>{ callbacksObj.onRejected(reason) }) },0) } } try{ excutor(resolve,reject) }catch(error){ reject(error) } }
Promise.prototype.then = function(onResolved,onRejected){ const that = this if(typeof onResolved !== 'function'){ onResolved = () =>{ return that.data } } if(typeof onRejected !== 'function'){ onRejected = () =>{ return that.data } } function handle(result,resolve,reject){ try{ if(result instanceof Promise){ result.then(resolve,reject) }else{ resolve(result) } }catch(err){ reject(err) } } return new Promise((resolve,reject)=>{ if(that.status === 'pending'){ that.callbacks.push({ onResolved: value => { try{ let result = onResolved(value) if(result instanceof Promise){ result.then(resolve,reject) }else{ resolve(result) } }catch(err){ reject(err) } }, onRejected: reaseon => { try{ let result = onRejected(reaseon) if(result instanceof Promise){ result.then(resolve,reject) }else{ resolve(result) } }catch(err){ reject(err) } } }) }else if(that.status === 'resolved'){ setTimeout(() => { try{ let result = onResolved(that.data) if(result instanceof Promise){ result.then(resolve,reject) console.log(result.then(resolve,reject)) }else{ resolve(result) } }catch(err){ reject(err) } },0) }else if(that.status === 'rejected'){ setTimeout(() => { try{ let result = onRejected(that.data) if(result instanceof Promise){ result.then(resolve,reject) }else{ resolve(result) } }catch(err){ reject(err) } },0) } }) } Promise.prototype.catch = function(onRejected){ } Promise.resolve = function(value){ } Promise.reject = function(reaseon){ } Promise.all = function(promises){ } Promise.race = function(promises){ } window.Promise = Promise })(window)
|