前端八股文之手写系列
面试中常常会遇到同样的问题,大多数面经都将其整理成“面试八股文”以供背诵,尤其是技术乱七八糟一大堆的前端,八股文现象尤为显著
所以面试中击败你的,不光是 985 博士和海龟等精英,还有很多“八股文选手”
本着打不过就加入的原则,本篇文章会持续更新前端八股文系列
快排
这里给出分治+递归的写法
代码比较短,方便记忆
const sort = array => { if (array.length < 2) { return array } const mid = array.splice(Math.floor(array.length / 2), 1)[0] const left = [] const right = [] array.forEach(item => { if (item < mid) { left.push(item) } else { right.push(item) } }) return [...sort(left), mid, ...sort(right)] }
数组扁平化
建议背前 3 个,后面的可以理解下思路(如果面试官问到别的方法的话)
递归(推荐)
元素可以是任意类型
const flatArray = array => { const result = [] array.forEach(item => { if (Array.isArray(item)) { result.push(...flatArray(item)) } else { result.push(item) } }) return result }
循环+concat(推荐)
元素可以是任意类型
const flatArray = array => { while (array.some(item => Array.isArray(item))) { array = [].concat(...array) } return array }
reduce(推荐)
元素可以是任意类型
const flatArray = array => { return [] .concat(array) .reduce( (item, next) => item.concat(Array.isArray(array) ? flatArray(next) : next), [] ) }
toString+split(不推荐)
代码短但是数组元素只能是number
或者同一种类型的基本类型
const flatArray = array => { return array .toString() .split(',') .map(item => Number(item)) }
join+split(不推荐)
优缺点同上,join 也可以转字符串
const flatArray = array => { return array .join(',') .split(',') .map(item => Number(item)) }
JSON+正则(不推荐)
优缺点同上,正则不太好记忆
const flatArray = array => { return JSON.stringify(array) .replace(/(\[|\])/g, '') .split(',') .map(item => Number(item)) }
ES6 自带的 flat(不推荐)
千万别写(就是考你 flat 实现的,你直接调了现成的。。。)
但是要了解一下 ES6 这个新引入的函数
const flatArray = array => { while (array.some(item => Array.isArray(item))) { array = array.flat() } return array }
call、apply、bind
call
- 判断
null
和undefined
时指向全局对象 - 对基本类型装箱:
new Object(...)
Function.prototype._call = function(context) { if (context === undefined || context === null) { context = globalThis } context = new Object(context) context.fn = this const args = [] Array.prototype.forEach.call( Array.prototype.slice.call(arguments, 1), item => args.push(item) ) const result = context.fn(...args) delete context.fn return result }
apply
类似 call 的实现,传参方式不同
Function.prototype._apply = function(context, args) { if (context === undefined || context === null) { context = globalThis } context = new Object(context) context.fn = this const result = context.fn(...args) delete context.fn return context }
bind
简易版
存在问题:返回的函数不能构造器调用(new xxx())
Function.prototype._bind = function(...args) { const fn = this const that = args[0] const bindArgs = args.slice(1) return (...args) => { fn.apply(that, [...bindArgs, ...args]) } }
类似 MDN 的实现
Function.prototype._bind = function(context) { if (typeof this !== 'function') { throw new Error( 'Function.prototype.bind - what is trying to be bound is not callable' ) } const fn = this const args = Array.prototype.slice.call(arguments, 1) const noop = function() {} const result = function() { const bindArgs = Array.prototype.slice.call(arguments) return fn.apply(this instanceof noop ? this : context, args.bindArgs) } noop.prototype = fn.prototype result.prototype = new noop() return result }
数组去重
有很多种思路,这里只列出几种代码较少的
利用 Set
利用 Set 的不可重复特性(ES6)
const unique = array => [...new Set(array)]
利用 Map
将元素设置为 Map 的键再检索(ES6)
const unique = array => { const map = new Map() return array.filter(item => !map.has(item) && map.set(item, 1)) }
reduce
const unique = array => array.reduce((item, next) => item.includes(next) ? item : [...item, next], []) }
ES5 对象
这个方法会将'1'
和1
看做相同
const unique = array => { const map = {} return array.filter(item => !map.hasOwnProperty(item) && (map[item] = 1)) }
防抖、节流
防抖
const debounce = (fn, time) => { let timer = null return function() { clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) }, time) } }
节流
const throttle = (fn, time) => { let flag = true return function() { if (!flag) { return } flag = false setTimeout(() => { fn.apply(this, arguments) flag = true }, time) } }
函数柯里化
实现 add 函数,使得add(1,2,3)
、add(1)(2)(3)
和add(1,2)(3)
都得到正确结果
function add() { const args = [...arguments] function fn() { args.push(...arguments) return fn } fn.toString = function() { return args.reduce((item, next) => item + next) } return fn }
类数组转数组
类数组是指具有 length 属性,但不具有数组方法,索引都为非负整数的对象
Array.from
const trans = Array.from
Array.slice
const transform = likeArray => Array.prototype.slice.call(likeArray)
concat
const transform = likeArray => Array.prototype.concat.apply([], likeArray)
深/浅拷贝
深拷贝
利用 JSON
对函数、undefined
、Symbol
元素无效
const deepCopy = obj => JSON.parse(JSON.stringify(obj))
递归
const deepCopy = obj => { let objNew = Array.isArray(obj) ? [] : {} if (obj && typeof obj === 'object') { for (key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === 'object') { objNew[key] = deepCopy(obj[key]) } else { objNew[key] = obj[key] } } } } return objNew }
浅拷贝
循环判断
const shallowCopy = obj => { let newObj = obj instanceof Array ? [] : {} for (key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key] } } return newObj }
Object.assign
const shallowCopy = obj => Object.assign({}, obj)
链式调用
class Person { constructor() { this._name = '' this._age = 0 } name(name) { this._name = name return this } age(age) { this._age = age return this } } // 使用 let person = new Person().name('王昭君').age(21)
-
JavaScript
-
面试
人人都恨八股文,人人都想精通八股文
博客不错,爱了