一、Promsie
promise翻译过来是承诺的意思,这个承诺会在未来有一个确切的答复,并且该承诺有三种状态,这个承诺一旦从等待状态变成为其他状态就永远不能更改状态了。
- pedding 等待中
- resolved 完成了
- rejected 拒绝了
Promise还实现了then链式调用,解决回调地狱的问题
实现第一步
搭建构造函数的大体框架
const PENDING = 'pending'
const RESOLVE = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn){
const that = this;
that.state = PENDING
that.value = null
that.resolveCallbacks = []
that.rejectCallbacks = []
//resolve与reject函数
//fn函数
}
- 首先创建三个常量,用于表示Promise的三个状态
- 在函数内部体内声明that,因为代码可能会异步执行,用于获取正确的this指向
- value用于保存resolve和reject传入的值
- resolveCallbacks 、rejectCallbacks 用于保存then中的回调,因为执行完Promise时状态可能还是等待中,需要把then中的回调保存起来,当状态改变时调用
第二步,完善resolve和reject函数
function resolve(value) {
if(that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value))
}
}
function reject(value) {
if(that.state === PENDING){
that.state = REJECTED
that.value = value;
that.rejectedCallbacks.map(cb => cb(that.value));
}
}
第三步,执行Promise传入的函数
try {
fn(resolve,reject)
} catch(e) {
reject(e)
}
- 执行传入的函数,并将上一步写的resolve,reject函数作为参数传进去
- 要注意,在执行函数过程中可能会报错,需要捕获错误并且执行reject
第四步,实现then函数
MyPromise.prototype.then = function (onFulfilled,onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === 'function'
?onFulfilled
:v => v
onRejected = typeof onRejected === 'function'
?onRejected
:r => throw r
}
if(that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled)
that.rejectedCallbacks.push(onRejected)
}
else if(that.state === RESOLVED) {
onFulfilled(that.value)
}
else {
onRejected(that.value)
}
- 首先判断两个参数是否为函数类型,因为这两个参数是可选的。当参数不是函数类型时,需要创建一个函数赋值给对应的参数
- 接下来进行一系列的逻辑判断,当状态不是等待态时,就去执行相对应得函数。如果是等待态,则将函数push进回调函数中
Promise完整代码
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn){
const that = this
that.state = PENDING
that.value = null
that.resolvedCallbacks = []
that.rejectedCallbacks = []
function resolve(value) {
if(that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value))
}
}
function reject(value) {
if(that.state === PENDING){
that.state = REJECTED
that.value = value;
that.rejectedCallbacks.map(cb => cb(that.value));
}
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
const that = this
//对传入的两个参数做判断,如果不是函数将其转为函数
onFulfilled =
typeof onFulfilled === 'function'
? onFulfilled
: v => v // onFulfilled = v => v
onRejected =
typeof onRejected === 'function'
? onRejected
: r => {
throw r
}
if(that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled)
that.rejectedCallbacks.push(onRejected)
}
else if(that.state === RESOLVED) {
onFulfilled(that.value)
}
else {
onRejected(that.value)
}
}
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功的回调数据')
}, 1000)
}).then(value => {
console.log('Promise.then: ', value)
})
二、call
除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。
call的实现思路:
- 不传入参数,默认为window
- 给新的对象添加一个函数,执行完后删除
(其实call的实现非常简单,总共8行代码)
Funtion.prototype.myCall = function (context){
//设置默认参数为window
var context = context || window
//给新对象添加方法fn
//getValue.call(a,1,2) => a.fn = getValue
//此处this.指向调用myCall的对象
context.fn = this
//取出除第一个以外的参数
var args = [...arguments].slice(1)
//
var result = context.fn(...args)
delete context.fn
return result
}
三、apply
apply则更简单,七行即可
Function.prototype.myApply = function (context){
var context = context || window
context.fn = this
//判断是否有第二个参数,有则展开
var result = arguments[1]? context.fn(...arguments[1]) : context.fn()
delete context.fn
return result
}
三、bind
bind和其他两个方法类似,只是会返回一个函数,可以通过bind实现函数柯里化
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
var _this = this
var args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
四、new
- 新生成了一个对象
- 链接到原型
- 绑定到this
- 返回新对象
function create() {
// 创建一个空的对象
let obj = new Object()
// 获得构造函数
let Con = [].shift.call(arguments)
// 链接到原型
obj.__proto__ = Con.prototype
// 绑定 this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result === 'object' ? result : obj
}