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

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;

if(xhr.readyState === 4) {

let result = xhr.responseText

resolve(result)

}

}

xhr.onerror = (err) => {

reject(err)

}

xhr.send()

})

}

实现jsonp

const jsonp = ({ url, params, callbackName }) => {

const generateUrl = () => {

let dataSrc = ‘’

for (let key in params) {

if (params.hasOwnProperty(key)) {

dataSrc += ${key}=${params[key]}&

}

}

dataSrc += callback=${callbackName}

return ${url}?${dataSrc}

}

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

const scriptEle = document.createElement(‘script’)

scriptEle.src = generateUrl()

document.body.appendChild(scriptEle)

window[callbackName] = data => {

resolve(data)

document.removeChild(scriptEle)

}

})

}

🛫 ES6篇


实现set

class Set {

constructor() {

this.items = {};

this.size = 0;

}

has(element) {

return element in this.items;

}

add(element) {

if(! this.has(element)) {

this.items[element] = element;

this.size++;

}

return this;

}

delete(element) {

if (this.has(element)) {

delete this.items[element];

this.size–;

}

return this;

}

clear() {

this.items = {}

this.size = 0;

}

values() {

let values = [];

for(let key in this.items) {

if(this.items.hasOwnProperty(key)) {

values.push(key);

}

}

return values;

}

}

实现 map

function defaultToString(key) {

if(key === null) {

return ‘NULL’;

} else if (key === undefined) {

return ‘UNDEFINED’

} else if (Object.prototype.toString.call(key) === ‘[object Object]’ || Object.prototype.toString.call(key) === ‘[object Array]’) {

return JSON.stringify(key);

}

return key.toString();

}

class Map {

constructor() {

this.items = {};

this.size = 0;

}

set(key, value) {

if(!this.has(key)) {

this.items[defaultToString(key)] = value;

this.size++;

}

return this;

}

get(key) {

return this.items[defaultToString(key)];

}

has(key) {

return this.items[defaultToString(key)] !== undefined;

}

delete(key) {

if (this.has(key)) {

delete this.items[key];

this.size–;

}

return this;

}

clear() {

this.items = {}

this.size = 0;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。

《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里免费领取

前端面试题宝典

前端校招面试题详解

otype.toString.call(key) === ‘[object Array]’) {

return JSON.stringify(key);

}

return key.toString();

}

class Map {

constructor() {

this.items = {};

this.size = 0;

}

set(key, value) {

if(!this.has(key)) {

this.items[defaultToString(key)] = value;

this.size++;

}

return this;

}

get(key) {

return this.items[defaultToString(key)];

}

has(key) {

return this.items[defaultToString(key)] !== undefined;

}

delete(key) {

if (this.has(key)) {

delete this.items[key];

this.size–;

}

return this;

}

clear() {

this.items = {}

this.size = 0;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-edIuUk51-1713437543093)]

[外链图片转存中…(img-QIBr24iO-1713437543094)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-OfSmtOoz-1713437543094)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-iVO3ZIAN-1713437543094)]

最后

整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。

《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里免费领取

[外链图片转存中…(img-fiy45gX3-1713437543095)]

[外链图片转存中…(img-O4LCHQVS-1713437543095)]

[外链图片转存中…(img-TqyCyXkl-1713437543095)]


  1. 23 ↩︎

  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值