手写题
1. forEach
Array.prototype.forEach = function (callback) {
for (let i = 0, len = this.length; i < len; i++) {
callback(this[i], i, this);
}
};
2. map
Array.prototype.map = function (callback) {
let arr = [];
for (let i = 0, len = this.length; i < len; i++) {
arr.push(callback(this[i], i, this));
}
return arr;
};
3. filter
Array.prototype.filter = function (callback) {
let result = [];
for (let i = 0, len = this.length; i < len; i++) {
if (callback(this[i])) {
result.push(this[i]);
}
}
return result;
};
4. some
Array.prototype.some = function (callback) {
for (let i = 0, len = this.length; i < len; i++) {
if (callback(this[i])) {
return true;
}
}
return false;
};
5. every
Array.prototype.every = function (callback) {
for (let i = 0, len = this.length; i < len; i++) {
if (!callback(this[i])) {
return false;
}
}
return true;
};
6. find
Array.prototype.find = function (callback) {
for (let i = 0, len = this.length; i < len; i++) {
if (callback(this[i])) {
return this[i];
}
}
};
7. findIndex
Array.prototype.findIndex = function (callback) {
for (let i = 0, len = this.length; i < len; i++) {
if (callback(this[i])) {
return i;
}
}
return -1;
};
8. fill
Array.prototype.fill = function (value) {
let result = [];
for (let i = 0, len = this.length; i < len; i++) {
result.push(value);
}
return result;
};
9. reduce
Array.prototype.reduce = function (callback, initValue) {
let preValue = initValue || this[0];
let i = initValue ? 0 : 1;
for (len = this.length; i < len; i++) {
preValue = callback(preValue, this[i], i, this);
}
return preValue;
};
10. flat(depth)
Array.prototype.flat = function (depth) {
let result = this;
while (depth > 0) {
result = [].concat(...result);
depth = depth - 1;
// 没有数组则不等depth减为0就退出循环
if (result.every((item) => !Array.isArray(item))) {
break;
}
}
return result;
};
11. Object.is
Object.prototype.is = function (obj1, obj2) {
// 处理NaN的情况
if (obj1 !== obj1) {
return obj1 + '' === obj2 + '';
}
// 处理+0 和 -0的情况
if (obj1 === 0) {
return obj1 / 1 === obj1 / 2;
}
return obj1 === obj2;
};
12. Object.create
function objectCreate(proto) {
function Fn() {}
Fn.prototype = proto;
return new Fn();
}
14. instanceof
// 主要是判断obj是否出现在instance的原型链上
function instanceOf(instance, obj) {
let proto = instance.__proto__;
while (proto) {
if (proto === obj.prototype) {
return true;
}
proto = proto.__proto__;
}
return false;
}
15. new 操作符
function myNew(fn, ...args) {
if (typeof fn !== 'function') {
throw new TypeError('fn必须是函数类型');
}
let result = Object.create(fn.prototype);
fn.call(result, ...args);
return result;
}
16. call
Function.prototype.call = function (context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('必须是函数类型才能调用call');
}
context = context || window;
context.fn = this;
result = context.fn(...args);
delete context.fn;
return result;
};
17. apply
Function.prototype.apply = function (context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('必须是函数类型才能调用apply');
}
context = context || window;
context.fn = this;
const result = context.fn([...args]);
delete context.fn;
return result;
};
18. bind
bind 在 call 的基础上实现比较简单,如下:
Function.prototype.bind = function (context, ...args) {
const self = this;
return function (...args2) {
return self.call(context, ...args, ...args2);
};
};
19. debounce
function debounce(fn, wait) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.call(this, ...args);
}, wait);
};
}
20. throttle
function throttle(fn, wait) {
let lastTime = 0;
return function (...args) {
let nowTime = Date.now();
if (nowTime - lastTime > wait) {
fn.call(this, ...args);
lastTime = nowTime;
}
};
}
21. cloneDeep
function cloneDeep(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
result[key] = cloneDeep(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
22. 函数柯里化
function currying(fn, ...args) {
return function (...args2) {
let argsAll = [...args, ...args2];
return argsAll.length >= fn.length ? fn.call(this, ...argsAll) : currying.call(this, fn, ...argsAll);
};
}
或
function currying(fn, ...args) {
return args.length >= fn.length ? fn(...args) : currying.bind(null, fn, ...args);
}
23. 寄生组合继承
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log('说话');
};
// 下面是寄生组合继承的代码,Student继承自Person
function Student(name, age, height) {
Person.call(this, name, age);
this.height = height;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
24. Promise
/**
* 构造函数
* @param {function} executor 执行器函数,有两个函数类型的参数:resolve, reject
*/
function Promise(executor) {
const self = this;
self.status = PENDING;
self.data = undefined; // 用来保存Promise的结果
self.callbacks = []; // 用来保存回调函数对象数组,每一项的结构为{ onResolved, onRejected }
function resolve(value) {
if (self.status !== PENDING) {
// Promise只能执行一次
return;
}
self.status = RESOLVED;
self.data = value;
if (self.callbacks.length > 0) {
// 如果回调函数对象数组不为空,则异步执行每一项的onResolved方法
setTimeout(() => {
self.callbacks.forEach((callbackObj) => {
callbackObj.onResolved(value);
});
});
}
}
function reject(reason) {
if (self.status !== PENDING) {
return;
}
self.status = REJECTED;
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach((callbackObj) => {
callbackObj.onRejected(reason);
});
});
}
}
try {
executor(resolve, reject); // 一旦创建,立即执行
} catch (err) {
// 如果出现异常,则将该异常作为失败的结果
reject(err);
}
}
/**
* then()方法,返回一个新Promise, 新Promise的执行结果取决于上一个Promise的返回值
* 1. 如果抛出异常,新Promise的执行结果rejected, reason为抛出的异常
* 2. 如果返回值是Promise, 新Promise的执行结果为上一个Promise的执行结果
* 3. 如果返回值是非Promise, 新Promise的执行结果resolved, value为返回值
* @param {function} onResolved Promise执行成功的回调,异步回调,接收一个参数value(Promise执行成功的结果)
* @param {function} onRejected Promise执行失败的回调,异步回调,接收一个参数reason(Promise执行失败的结果)
*/
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : (value) => value;
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason;
};
const self = this;
return new Promise((resolve, reject) => {
function handle(callback) {
try {
let result = callback(self.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (self.status === RESOLVED) {
setTimeout(() => {
handle(onResolved);
});
} else if (self.status === REJECTED) {
setTimeout(() => {
handle(onRejected);
});
} else if (self.status === PENDING) {
self.callbacks.push({
onResolved: () => handle(onResolved),
onRejected: () => handle(onRejected)
});
}
});
};
25. Promise.all
/**
* Promise.all
* @param {array} promiseList promise列表
* @returns 返回一个Promise:若都成功,则返回所有promise结果的数组,若有一个失败则为失败的结果
*/
Promise.all = function (promiseList) {
let resultList = [];
let count = 0;
return new Promise((resolve, reject) => {
promiseList.forEach((item) => {
const promise = item instanceof Promise ? item : Promise.resolve(item);
promise.then((value) => {
count++;
resultList.push(value);
if (count === promiseList.length) {
resolve(resultList);
}
}, reject);
});
});
};
26. Promise.race
/**
* Promise.race
* @param {array} promiseList promise列表
* @returns 返回一个promise,结果为最先执行完 promise 的结果
*/
Promise.race = function (promiseList) {
return new Promise((resolve, reject) => {
promiseList.forEach((item) => {
const promise = item instanceof Promise ? item : Promise.resolve(item);
promise.then(resolve, reject);
});
});
};
27. Promise.allSettled
/**
* Promise.allSettled
* @param {array} promiseList promise列表
* @returns 返回一个promise,结果为所有promise都执行完的结果
*/
Promise.allSettled = function (promiseList) {
let resultList = [];
let count = 0;
return new Promise((resolve, reject) => {
promiseList.forEach((item) => {
const promise = item instanceof Promise ? item : Promise.resolve(item);
promise
.then(
(value) => {
count++;
resultList.push({
status: 'fulfilled',
value
});
},
(reason) => {
count++;
resultList.push({
status: 'rejected',
reason
});
}
)
.then(() => {
if (count === promiseList.length) {
resolve(resultList);
}
});
});
});
};
28. Promise.any
/**
* Promise.any
* @param {array} promiseList promise列表
* @returns 返回一个promise,如果有一个成功就返回成功的结果,都不成功则reject,reason为AggregateError: All promises were rejected
*/
Promise.any = function (promiseList) {
let count = 0;
return new Promise((resolve, reject) => {
promiseList.forEach((item) => {
const promise = item instanceof Promise ? item : Promise.resolve(item);
promise
.then(resolve, () => {
count++;
})
.then(() => {
if (count === promiseList.length) {
reject('AggregateError: All promises were rejected');
}
});
});
});
};
29. 实现 ajax 请求
function ajax(url, method, data, success, error) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
success(xhr.responseText);
} else {
error(xhr.status);
}
}
};
xhr.open(method, url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
}
// 接口请求示例
ajax(
'/api/login',
'POST',
{ username: 'Tom', password: '123456' },
function (response) {
console.log('登录成功:' + response);
},
function (status) {
console.log('登录失败:' + status);
}
);
30. 使用 Promise 封装 ajax 请求
const ajaxPromise = (url, method, data) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
}
};
xhr.open(method, url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
});
};