手写代码
声明
整个知识库涉及的资料一部分为自主收集整理,一部分来源于网络收集,如有侵权请联系我
手写 new 操作符
new 操作符在 JavaScript 中用于创建一个用户定义的对象类型的实例。它的工作步骤如下:
- 首先创建了一个新的空对象
- 设置原型,将对象的原型设置为函数的
prototype对象。 - 让函数的
this指向这个对象,执行构造函数的代码(为这个新对象添加属性) - 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
javascript
function myNew(obj, ...args) {
// 1. 创建一个新的空对象
// 2. 将这个新对象的原型指向构造函数的 prototype 属性
const newObject = Object.create(obj.prototype)
// 3. 将构造函数内部的 this 绑定到这个新对象上,并执行构造函数的代码
const result = obj.apply(newObject, args);
// 4. 如果构造函数返回一个对象,则返回该对象;否则,返回新创建的对象
return result instanceof Object ? result : obj;
}手写 call 函数
call 函数的实现原理步骤如下:
- 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window。
- 处理传入的参数,截取第一个参数后的所有参数。
- 将函数作为上下文对象的一个属性。
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性。
- 返回结果。
javascript
Function.prototype.myCall = function(context) {
// 1. 判断调用对象是否为函数
if (typeof this !== 'function') {
throw new TypeError('Error');
}
// 2. 判断上下文对象是否存在,不存在则设置为window
context = context || window;
// 3. 处理传入的参数,截取第一个参数后的所有参数
const args = [...arguments].slice(1)
// 4. 将函数设为对象的属性
// 用Symbol是为了避免属性名冲突
const fn = Symbol();
context[fn] = this;
// 5. 调用函数并传入参数
const result = context[fn](...args);
// 6. 删除该属性
delete context[fn];
// 7. 返回结果
return result;
}手写 apply 函数
apply 函数的实现原理步骤如下:
- 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 apply 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window。
- 将函数作为上下文对象的一个属性。
- 判断参数值是否传入。
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性。
- 返回结果。
javascript
Function.prototype.myApply = function(context) {
// 1. 判断调用对象是否为函数
if (typeof this !== 'function') {
throw new TypeError('Error');
}
// 2. 判断上下文对象是否存在,不存在则设置为window
context = context || window;
// 3. 将函数设为对象的属性
// 用Symbol是为了避免属性名冲突
const fn = Symbol();
context[fn] = this;
// 4. 调用函数并传入参数
// 5. 使用上下文对象来调用这个方法
const result = arguments[1] ? context[fn](...arguments[1]) : context[fn]();
// 6. 删除该属性
delete context[fn];
// 7. 返回结果
return result;
}手写 bind 函数
bind 函数的实现原理步骤如下:
- 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 bind 等方式调用的情况。
- 保存当前函数的引用,获取其余传入参数值。
- 创建一个函数返回
- 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
javascript
Function.prototype.myBind = function(context) {
// 1. 判断调用对象是否为函数
if (typeof this !== 'function') {
throw new TypeError('Error');
}
// 2. 保存当前函数的引用,获取其余传入参数值
const fn = this;
const args = [...arguments].slice(1);
// 3. 创建一个返回函数
return function Fn() {
// 根据调用方式,传入不同绑定值
// 当作为构造函数使用,this指向实例,此时结果为true,将绑定函数的this指向该实例
// 当作为普通函数使用,this指向window,此时结果为false,将绑定函数的this指向context
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
}
}手写 Promise
javascript
// 定义 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
// 初始化状态
this.status = PENDING;
// 存储成功或失败的值
this.value = undefined;
// 存储失败的原因
this.reason = undefined;
// 存储成功后的回调函数
this.onFulfilledCallbacks = [];
// 存储失败后的回调函数
this.onRejectedCallbacks = [];
// 定义 resolve 函数
const resolve = (value) => {
// 只能由 pending 状态转换为 fulfilled 状态
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 执行成功后的回调函数
this.onFulfilledCallbacks.forEach(callback => callback(this.value));
}
};
// 定义 reject 函数
const reject = (reason) => {
// 只能由 pending 状态转换为 rejected 状态
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 执行失败后的回调函数
this.onRejectedCallbacks.forEach(callback => callback(this.reason));
}
};
// 执行 Promise 的 executor 函数
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 如果状态是 fulfilled,立即执行 onFulfilled
if (this.status === FULFILLED) {
onFulfilled(this.value);
}
// 如果状态是 rejected,立即执行 onRejected
if (this.status === REJECTED) {
onRejected(this.reason);
}
// 如果状态是 pending,将回调函数添加到对应的队列中
if (this.status === PENDING) {
onFulfilled && this.onFulfilledCallbacks.push(onFulfilled);
onRejected && this.onRejectedCallbacks.push(onRejected);
}
// 返回新的 Promise 以实现链式调用
return this;
}
}