2024年前端各大公司都考了那些手写题(附带代码)

throw new TypeError(“promises must be an array”)

}

let result = []

let count = 0

promises.forEach((promise, index) => {

promise.then((res)=>{

result[index] = res

count++

count === promises.length && resolve(result)

}, (err)=>{

reject(err)

})

})

})

}

实现 promise.finally

考察频率: (⭐⭐⭐⭐⭐)

Promise.prototype.finally = function (cb) {

return this.then(function (value) {

return Promise.resolve(cb()).then(function () {

return value

})

}, function (err) {

return Promise.resolve(cb()).then(function () {

throw err

})

})

}

实现promise.allSettled

考察频率: (⭐⭐⭐⭐)

function allSettled(promises) {

if (promises.length === 0) return Promise.resolve([])

const _promises = promises.map(

item => item instanceof Promise ? item : Promise.resolve(item)

)

return new Promise((resolve, reject) => {

const result = []

let unSettledPromiseCount = _promises.length

_promises.forEach((promise, index) => {

promise.then((value) => {

result[index] = {

status: ‘fulfilled’,

value

}

unSettledPromiseCount -= 1

// resolve after all are settled

if (unSettledPromiseCount === 0) {

resolve(result)

}

}, (reason) => {

result[index] = {

status: ‘rejected’,

reason

}

unSettledPromiseCount -= 1

// resolve after all are settled

if (unSettledPromiseCount === 0) {

resolve(result)

}

})

})

})

}

实现promise.race

考察频率: (⭐⭐⭐)

Promise.race = function(promiseArr) {

return new Promise((resolve, reject) => {

promiseArr.forEach(p => {

Promise.resolve§.then(val => {

resolve(val)

}, err => {

rejecte(err)

})

})

})

}

来说一下如何串行执行多个Promise

参考代码[2]

promise.any

Promise.any = function(promiseArr) {

let index = 0

return new Promise((resolve, reject) => {

if (promiseArr.length === 0) return

promiseArr.forEach((p, i) => {

Promise.resolve§.then(val => {

resolve(val)

}, err => {

index++

if (index === promiseArr.length) {

reject(new AggregateError(‘All promises were rejected’))

}

})

})

})

}

resolve

Promise.resolve = function(value) {

if(value instanceof Promise){

return value

}

return new Promise(resolve => resolve(value))

}

reject

Promise.reject = function(reason) {

return new Promise((resolve, reject) => reject(reason))

}

🐳 Array篇 前端开发博客


数组去重

考察频率: (⭐⭐⭐⭐⭐)

使用双重 forsplice

function unique(arr){

for(var i=0; i<arr.length; i++){

for(var j=i+1; j<arr.length; j++){

if(arr[i]==arr[j]){

//第一个等同于第二个,splice方法删除第二个

arr.splice(j,1);

// 删除后注意回调j

j–;

}

}

}

return arr;

}

使用 indexOfincludes 加新数组

//使用indexof

function unique(arr) {

var uniqueArr = []; // 新数组

for (let i = 0; i < arr.length; i++) {

if (uniqueArr.indexOf(arr[i]) === -1) {

//indexof返回-1表示在新数组中不存在该元素

uniqueArr.push(arr[i])//是新数组里没有的元素就push入

}

}

return uniqueArr;

}

// 使用includes

function unique(arr) {

var uniqueArr = [];

for (let i = 0; i < arr.length; i++) {

//includes 检测数组是否有某个值

if (!uniqueArr.includes(arr[i])) {

uniqueArr.push(arr[i])//

}

}

return uniqueArr;

}

sort 排序后,使用快慢指针的思想

function unique(arr) {

arr.sort((a, b) => a - b);

var slow = 1,

fast = 1;

while (fast < arr.length) {

if (arr[fast] != arr[fast - 1]) {

arr[slow ++] = arr[fast];

}

++ fast;

}

arr.length = slow;

return arr;

}

sort 方法用于从小到大排序(返回一个新数组),其参数中不带以上回调函数就会在两位数及以上时出现排序错误(如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序。两位数会变为长度为二的字符串来计算)。

ES6 提供的 Set 去重

function unique(arr) {

const result = new Set(arr);

return […result];

//使用扩展运算符将Set数据结构转为数组

}

Set 中的元素只会出现一次,即 Set 中的元素是唯一的。

使用哈希表存储元素是否出现(ES6 提供的 map)

function unique(arr) {

let map = new Map();

let uniqueArr = new Array();  // 数组用于返回结果

for (let i = 0; i < arr.length; i++) {

if(map.has(arr[i])) {  // 如果有该key值

map.set(arr[i], true);

} else {

map.set(arr[i], false);   // 如果没有该key值

uniqueArr.push(arr[i]);

}

}

return uniqueArr ;

}

map 对象保存键值对,与对象类似。但 map 的键可以是任意类型,对象的键只能是字符串类型。

如果数组中只有数字也可以使用普通对象作为哈希表。

filter 配合 indexOf

function unique(arr) {

return arr.filter(function (item, index, arr) {

//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素

//不是那么就证明是重复项,就舍弃

return arr.indexOf(item) === index;

})

}

这里有可能存在疑问,我来举个例子:

const arr = [1,1,2,1,3]

arr.indexOf(arr[0]) === 0 // 1 的第一次出现

arr.indexOf(arr[1]) !== 1 // 说明前面曾经出现过1

reduce 配合 includes

function unique(arr){

let uniqueArr = arr.reduce((acc,cur)=>{

if(!acc.includes(cur)){

acc.push(cur);

}

return acc;

},[]) // []作为回调函数的第一个参数的初始值

return uniqueArr

}

数组扁平化

考察频率: (⭐⭐⭐)

参考代码[3]

forEach

考察频率: (⭐⭐⭐)

Array.prototype.myForEach = function (callbackFn) {

// 判断this是否合法

if (this === null || this === undefined) {

throw new TypeError(“Cannot read property ‘myForEach’ of null”);

}

// 判断callbackFn是否合法

if (Object.prototype.toString.call(callbackFn) !== “[object Function]”) {

throw new TypeError(callbackFn + ’ is not a function’)

}

// 取到执行方法的数组对象和传入的this对象

var _arr = this, thisArg = arguments[1] || window;

for (var i = 0; i < _arr.length; i++) {

// 执行回调函数

callbackFn.call(thisArg, _arr[i], i, _arr);

}

}

reduce

考察频率: (⭐⭐⭐)

Array.prototype.myReduce = function(callbackFn) {

var _arr = this, accumulator = arguments[1];

var i = 0;

// 判断是否传入初始值

if (accumulator === undefined) {

// 没有初始值的空数组调用reduce会报错

if (_arr.length === 0) {

throw new Error(‘initVal and Array.length>0 need one’)

}

// 初始值赋值为数组第一个元素

accumulator = _arr[i];

i++;

}

for (; i<_arr.length; i++) {

// 计算结果赋值给初始值

accumulator = callbackFn(accumulator,  _arr[i], i, _arr)

}

return accumulator;

}

map

Array.prototype.myMap = function(callbackFn) {

var _arr = this, thisArg = arguments[1] || window, res = [];

for (var i = 0; i<_arr.length; i++) {

// 存储运算结果

res.push(callbackFn.call(thisArg, _arr[i], i, _arr));

}

return res;

}

filter

Array.prototype.myFilter = function(callbackFn) {

var _arr = this, thisArg = arguments[1] || window, res = [];

for (var i = 0; i<_arr.length; i++) {

// 回调函数执行为true

if (callbackFn.call(thisArg, _arr[i], i, _arr)) {

res.push(_arr[i]);

}

}

return res;

}

every

Array.prototype.myEvery = function(callbackFn) {

var _arr = this, thisArg = arguments[1] || window;

// 开始标识值为true

// 遇到回调返回false,直接返回false

// 如果循环执行完毕,意味着所有回调返回值为true,最终结果为true

var flag = true;

for (var i = 0; i<_arr.length; i++) {

// 回调函数执行为false,函数中断

if (!callbackFn.call(thisArg, _arr[i], i, _arr)) {

return false;

}

}

return flag;

}

some

Array.prototype.mySome = function(callbackFn) {

var _arr = this, thisArg = arguments[1] || window;

// 开始标识值为false

// 遇到回调返回true,直接返回true

// 如果循环执行完毕,意味着所有回调返回值为false,最终结果为false

var flag = false;

for (var i = 0; i<_arr.length; i++) {

// 回调函数执行为false,函数中断

if (callbackFn.call(thisArg, _arr[i], i, _arr)) {

return true;

}

}

return flag;

}

find/findIndex

Array.prototype.myFind = function(callbackFn) {

var _arr = this, thisArg = arguments[1] || window;

// 遇到回调返回true,直接返回该数组元素

// 如果循环执行完毕,意味着所有回调返回值为false,最终结果为undefined

for (var i = 0; i<_arr.length; i++) {

// 回调函数执行为false,函数中断

if (callbackFn.call(thisArg, _arr[i], i, _arr)) {

return _arr[i];

}

}

return undefined;

}

indexOf

function indexOf(findVal, beginIndex = 0) {

if (this.length < 1 || beginIndex > findVal.length) {

return -1;

}

if (!findVal) {

return 0;

}

beginIndex = beginIndex <= 0 ? 0 : beginIndex;

for (let i = beginIndex; i < this.length; i++) {

if (this[i] == findVal) return i;

}

return -1;

}

实现sort

参考代码[4]

🌊 防抖节流前端开发博客


实现防抖函数debounce

考察频率: (⭐⭐⭐⭐⭐)

function debounce(func, wait, immediate) {

var timeout, result;

var debounced = function () {

var context = this;

var args = arguments;

if (timeout) clearTimeout(timeout);

if (immediate) {

// 如果已经执行过,不再执行

var callNow = !timeout;

timeout = setTimeout(function(){

timeout = null;

}, wait)

if (callNow) result = func.apply(context, args)

}

else {

timeout = setTimeout(function(){

result = func.apply(context, args)

}, wait);

}

return result;

};

debounced.cancel = function() {

clearTimeout(timeout);

timeout = null;

};

return debounced;

}

实现节流函数throttle

考察频率: (⭐⭐⭐⭐⭐)

// 第四版

function throttle(func, wait, options) {

var timeout, context, args, result;

var previous = 0;

if (!options) options = {};

var later = function() {

previous = options.leading === false ? 0 : new Date().getTime();

timeout = null;

func.apply(context, args);

if (!timeout) context = args = null;

};

var throttled = function() {

var now = new Date().getTime();

if (!previous && options.leading === false) previous = now;

var remaining = wait - (now - previous);

context = this;

args = arguments;

if (remaining <= 0 || remaining > wait) {

if (timeout) {

clearTimeout(timeout);

timeout = null;

}

previous = now;

func.apply(context, args);

if (!timeout) context = args = null;

} else if (!timeout && options.trailing !== false) {

timeout = setTimeout(later, remaining);

}

};

return throttled;

}

⛲ Object篇


能不能写一个完整的深拷贝

考察频率: (⭐⭐⭐⭐⭐)

const getType = obj => Object.prototype.toString.call(obj);

const isObject = (target) => (typeof target === ‘object’ || typeof target === ‘function’) && target !== null;

const canTraverse = {

‘[object Map]’: true,

‘[object Set]’: true,

‘[object Array]’: true,

‘[object Object]’: true,

‘[object Arguments]’: true,

};

const mapTag = ‘[object Map]’;

const setTag = ‘[object Set]’;

const boolTag = ‘[object Boolean]’;

const numberTag = ‘[object Number]’;

const stringTag = ‘[object String]’;

const symbolTag = ‘[object Symbol]’;

const dateTag = ‘[object Date]’;

const errorTag = ‘[object Error]’;

const regexpTag = ‘[object RegExp]’;

const funcTag = ‘[object Function]’;

const handleRegExp = (target) => {

const { source, flags } = target;

return new target.constructor(source, flags);

}

const handleFunc = (func) => {

// 箭头函数直接返回自身

if(!func.prototype) return func;

const bodyReg = /(?<={)(.|\n)+(?=})/m;

const paramReg = /(?<=().+(?=)\s+{)/;

const funcString = func.toString();

// 分别匹配 函数参数 和 函数体

const param = paramReg.exec(funcString);

const body = bodyReg.exec(funcString);

if(!body) return null;

if (param) {

const paramArr = param[0].split(‘,’);

return new Function(…paramArr, body[0]);

} else {

return new Function(body[0]);

}

}

const handleNotTraverse = (target, tag) => {

const Ctor = target.constructor;

switch(tag) {

case boolTag:

return new Object(Boolean.prototype.valueOf.call(target));

case numberTag:

return new Object(Number.prototype.valueOf.call(target));

case stringTag:

return new Object(String.prototype.valueOf.call(target));

case symbolTag:

return new Object(Symbol.prototype.valueOf.call(target));

case errorTag:

case dateTag:

return new Ctor(target);

case regexpTag:

return handleRegExp(target);

case funcTag:

return handleFunc(target);

default:

return new Ctor(target);

}

}

const deepClone = (target, map = new WeakMap()) => {

if(!isObject(target))

return target;

let type = getType(target);

let cloneTarget;

if(!canTraverse[type]) {

// 处理不能遍历的对象

return handleNotTraverse(target, type);

}else {

// 这波操作相当关键,可以保证对象的原型不丢失!

let ctor = target.constructor;

cloneTarget = new ctor();

}

if(map.get(target))

return target;

map.set(target, true);

if(type === mapTag) {

//处理Map

target.forEach((item, key) => {

cloneTarget.set(deepClone(key, map), deepClone(item, map));

})

}

if(type === setTag) {

//处理Set

target.forEach(item => {

cloneTarget.add(deepClone(item, map));

})

}

// 处理数组和对象

for (let prop in target) {

if (target.hasOwnProperty(prop)) {

cloneTarget[prop] = deepClone(target[prop], map);

}

}

return cloneTarget;

}

参考博客[5]

实现new

考察频率: (⭐⭐⭐⭐)

function createObject(Con) {

// 创建新对象obj

// var obj = {};也可以

var obj = Object.create(null);

// 将obj.proto -> 构造函数原型

// (不推荐)obj.proto = Con.prototype

Object.setPrototypeOf(obj, Con.prototype);

// 执行构造函数,并接受构造函数返回值

const ret = Con.apply(obj, [].slice.call(arguments, 1));

// 若构造函数返回值为对象,直接返回该对象

// 否则返回obj

return typeof(ret) === ‘object’ ? ret: obj;

}

继承

考察频率: (⭐⭐⭐⭐)

原型链继承
借用构造函数(经典继承)
组合继承
原型式继承
寄生式继承
寄生组合式继承
Class实现继承(补充一下)

class Animal {

constructor(name) {

this.name = name

}

getName() {

return this.name

}

}

class Dog extends Animal {

constructor(name, age) {

super(name)

this.age = age

}

}

参考代码[6]

实现object.create

function newCreate(proto, propertiesObject) {

if (typeof proto !== ‘object’ && typeof proto !== ‘function’) {

throw TypeError('Object prototype may only be an Object: ’ + proto)

}

function F() { }

F.prototype = proto

const o = new F()

if (propertiesObject !== undefined) {

Object.keys(propertiesObject).forEach(prop => {

let desc = propertiesObject[prop]

if (typeof desc !== ‘object’ || desc === null) {

throw TypeError('Object prorotype may only be an Object: ’ + desc)

} else {

Object.defineProperty(o, prop, desc)

}

})

}

return o

}

🚂 Function篇


call

考察频率: (⭐⭐⭐⭐)

Function.prototype.myCall = function (thisArg) {

thisArg = thisArg || window;

thisArg.func = this;

const args = []

for (let i = 1; i<arguments.length; i++) {

args.push(‘arguments[’+ i + ‘]’)

}

const result = eval(‘thisArg.func(’ + args +‘)’)

delete thisArg.func;

return result;

}

bind

考察频率: (⭐⭐⭐⭐)

Function.prototype.sx_bind = function (obj, …args) {

obj = obj || window

const fn = Symbol()

obj[fn] = this

const _this = this

const res = function (…innerArgs) {

console.log(this, _this)

if (this instanceof _this) {

this[fn] = _this

thisfn

delete this[fn]

} else {

objfn

delete obj[fn]

}

}

res.prototype = Object.create(this.prototype)

return res

}

apply

考察频率: (⭐⭐⭐⭐)

Function.prototype.myApply = function (thisArg, arr) {

thisArg = thisArg || window;

thisArg.func = this;

const args = []

for (let i = 0; i<arr.length; i++) {

args.push(‘arr[’+ i + ‘]’)

}

const result = eval(‘thisArg.func(’ + args +‘)’)

delete thisArg.func;

return result;

}

实现柯里化

考察频率: (⭐⭐⭐)

参考代码[7]

实现链式调用

参考代码[8]

偏函数

参考代码[9]

🌍 ajax 与 jsonp


考察频率: (⭐⭐⭐)

实现ajax

function ajax({

url= null,

method = ‘GET’,

dataType = ‘JSON’,

async = true}){

return new Promise((resolve, reject) => {

let xhr = new XMLHttpRequest()

xhr.open(method, url, async)

xhr.responseType = dataType

xhr.onreadystatechange = () => {

if(!/1\d{2}$/.test(xhr.status)) return;


  1. 23 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值