1.手写new
function myNew() {
// 1.用new Object() 的方式新建了一个对象 obj
const obj = new Object();
// 2.取出第一个参数,就是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数
const constructor = [].shift.call(arguments);
// 3.将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性
obj.__proto__ = constructor.prototype;
// 4.使用 apply执行构造函数,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性
const res = constructor.apply(obj, arguments);
// 5.因为构造函数可能有返回值, 且返回值只有引用类型才能生效 返回
return typeof res === "object" ? res : obj;
}
复制代码
2.手写call、apply
Function.prototype.myCall = function (context) {
// this 参数可以传 null,当为 null 的时候,视为指向 window
context = context || window;
// 将函数设为对象的属性
context.fn = this;
// 获取函数的参数
// call 是 ES3 的方法,用 eval 方法拼成一个函数
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push("arguments[" + i + "]");
}
// 执行函数 context.fn()
// 这里 args 会自动调用 Array.toString() 这个方法。
var result = eval("context.fn(" + args + ")");
// 删除该函数
delete context.fn;
// 返回值
return result;
};
复制代码
Function.prototype.myApply = function (context, arr) {
// this 参数可以传 null,当为 null 的时候,视为指向 window
context = context || window;
// 将函数设为对象的属性
context.fn = this;
// 获取函数的参数
arr = arr.length ? arr : [];
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push("arr[" + i + "]");
}
// 执行函数 context.fn()
// 这里 args 会自动调用 Array.toString() 这个方法。
var result = eval("context.fn(" + args + ")");
// 删除该函数
delete context.fn;
// 返回值
return result;
};
复制代码
3、手写bind
Function.prototype.myBind = function (context) {
// 绑定的必须是函数
if (typeof this !== "function") {
throw new Error(
"Function.prototype.bind - 尝试被绑定的对象是不可调用的"
);
}
// 获取执行函数
var self = this;
// 获取myBind函数从第二个参数到最后一个参数
var args = Array.prototype.slice.call(arguments, 1);
// 空函数 用来中转
var fNOP = function () {};
// bind返回的函数也可以传入参数,因此要将两次的参数合并起来
// bind返回的函数可以作为构造函数,此时bind绑定的this会失效,但传入的参数依然生效
var fBound = function () {
// 这个时候的arguments是指bind返回的函数传入的参数
var bindArgs = Array.prototype.slice.call(arguments);
// this instanceof fNOP 如果为true 则此时是将bind返回的函数当做构造函数使用,即 new fBound(), 将绑定函数的 this 指向该实例
// this instanceof fNOP 如果为false, 则作为普通函数时,this 指向 window,将绑定函数的 this 指向 context
// args.concat(bindArgs) 将参数拼接
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
};
// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
// 这里不直接使用 fBound.prototype = this.prototype 原因是修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype
// 这个时候,我们可以通过一个空函数来进行中转
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
// 返回
return fBound;
};
复制代码
4、手写Promise
class MP {
static PENDING = 'PENDING'; // 等待状态
static FULFILED = 'FULFILED'; // 成功状态
static REJECTED = 'REJECTED'; // 失败状态
constructor(exectour) {
this.value = null;
this.status = MP.PENDING;
// 还没有resolve或者reject的时候,在then的回调函数中将回调函数压入callbacks中
this.callbacks = [];
try {
exectour(this.resolve.bind(this), this.rejected.bind(this));
} catch (error) {
this.rejected(error);
}
}
resolve(value) {
if (this.status !== MP.PENDING) return;
this.status = MP.FULFILED;
this.value = value;
setTimeout(() => {
// 异步执行
this.callbacks.forEach((callback) => {
callback.onFulfilled(value);
});
});
}
rejected(value) {
if (this.status !== MP.PENDING) return;
this.status = MP.REJECTED;
this.value = value;
setTimeout(() => {
this.callbacks.forEach((callback) => {
callback.onRejected(value);
});
});
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = () => this.value; // 值穿透
}
if (typeof onRejected !== 'function') {
onRejected = () => this.value;
}
const promise = new MP((resolve, rejected) => {
// 等待状态
if (this.status === MP.PENDING) {
this.callbacks.push({
onFulfilled: (v) => {
try {
this.parse(promise, onFulfilled(v), resolve, rejected);
} catch (error) {
rejected(error);
}
},
onRejected: (v) => {
try {
this.parse(promise, onRejected(v), resolve, rejected);
} catch (error) {
rejected(error);
}
},
});
}
// 成功状态
if (this.status === MP.FULFILED) {
setTimeout(() => {
try {
this.parse(promise, onFulfilled(this.value), resolve, rejected);
} catch (error) {
rejected(error);
}
});
}
// 失败状态
if (this.status === MP.REJECTED) {
setTimeout(() => {
try {
this.parse(promise, onRejected(this.value), resolve, rejected);
} catch (error) {
rejected(error);
}
});
}
});
return promise;
}
// 公共方法
parse(promise, value, resolve, rejected) {
if (promise === value) {
throw new TypeError('Chaining cycle detected for promise');
}
try {
const res = value;
if (res instanceof MP) {
res.then(resolve, rejected);
} else {
resolve(res);
}
} catch (error) {
rejected(Error);
}
}
static resolve(value) {
return new MP((resolve, reject) => {
if (value instanceof MP) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static rejected(value) {
return new MP((resolve, rejected) => {
if (value instanceof MP) {
value.then(resolve, rejected);
} else {
rejected(value);
}
});
}
static all(promises) {
const values = [];
let i = 0;
return new MP((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(
(value) => {
i++;
values[index] = value;
if (i === promises.length) {
resolve(values);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new MP((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
}
}
复制代码
参考链接