防抖
function debounce(fn, time = 3000) {
let timer = null
return (...args) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.call(undefined, ...args)
timer = null
}, time)
}
}
节流
function throttle(fn, time = 3000) {
let timer = null
return (...args) => {
if (timer) return
timer = setTimeout(() => {
fn.call(undefined, ...args)
timer = null
}, time)
}
}
发布订阅
const eventHub = {
map: {},
on: (name, fn) => {
eventHub.map[name] = eventHub.map[name] || []
eventHub.map[name].push(fn)
},
emit: (name, data) => {
const q = eventHub.map[name]
if (!q) return
q.map(f => f.call(undefined, data))
},
off: (name, fn) => {
const q = eventHub.map[name]
if (!q) return
const index = q.index(fn)
if (index < 0) return
q.splice(index, 1)
}
}
eventHub.on('click', console.log)
eventHub.on('click', console.error)
setTimeout(() => {
eventHub.emit('click', '小刺猬fy')
}, 2000)
还可以用class实现:
class EventHub {
map = {}
on(name, fn) {
eventHub.map[name] = eventHub.map[name] || []
eventHub.map[name].push(fn)
}
emit(name, data) {
const q = eventHub.map[name]
if (!q) return
q.map(f => f.call(undefined, data))
}
off(name, fn) {
const q = eventHub.map[name]
if (!q) return
const index = q.index(fn)
if (index < 0) return
q.splice(index, 1)
}
}
const eventHub = new EventHub()
eventHub.on('click', console.log)
eventHub.on('click', console.error)
setTimeout(() => {
eventHub.emit('click', '小刺猬fy')
}, 2000)
AJAX
const ajax = (methods, url, data, success, fail) => {
let request = new XMLHttpRequest()
request.open(methods, url)
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300 || request.status === 304) {
success(request)
} else {
fail(request)
}
}
}
request.send(data)
}
数组去重
这个答案有很多,以下例举3个解法:
// 1. 使用 Set(面试已经禁止这种了,因为太简单)
var uniq = function (arr = []) {
return Array.from(new Set(arr))
}
// 2. 使用计数排序的思路,缺点是只支持字符串
var uniq = function (arr = []) {
var map = {}
for (let i = 0; i < arr.length; i++) {
let num = arr[i]
if (!map[num]) {
map[num] = true
}
}
return [...Object.keys(map)]
}
// 3. 使用 Map,缺点是兼容性差了一点
var uniq = function (arr = []) {
var map = new Map()
for (let i = 0; i < arr.length; i++) {
let num = arr[i]
if (!map.has[num]) {
map.set(num, true)
}
}
return [...map.keys()]
}
深拷贝
- 用JSON
const b = JSON.parse(JSON.stringify(a))
这个方法有如下缺点:
- 不支持正则、undefined、Date、函数等数据;
- 不支持引用,即环状结构。 所以有了方法2.
- 用递归
function deepClone(source, cache) {
if (!cache) {
cache = new Map()
}
if (source instanceof Object) {
if (cache.get(source)) return cache.get(source) // 检查环
let result
if (a instanceof Function) { // 判断类型
if (a.prototype) {
result = function () {
return source.apply(this, arguments)
}
} else {
result = (...args) => {
return source.call(undefined, ...args)
}
}
} else if (source instanceof Array) { // 判断类型
result = []
} else if (source instanceof Date) { // 判断类型
result = new Date(source - 0)
} else if (source instanceof RegExp) { // 判断类型
result = new RegExp(source.source, source.flags)
} else {
result = {}
}
cache.set(source, result)
for (let key in source) {
if (source.hasOwnProperty(key)) { // 不拷贝原型上的属性
result[key] = deepClone(source[key], cache) // 递归
}
}
return result
}
return source
}
// 以下为测试代码
const a = {
number: 1,
bool: false,
str: 'hi',
empty1: undefined,
empty2: null,
array: [{
name: 'frank',
age: 18
},
{
name: 'jacky',
age: 19
}
],
date: new Date(2000, 0, 1, 20, 30, 0),
regex: /\.(j|t)sx/i,
obj: {
name: 'frank',
age: 18
},
f1: (a, b) => a + b,
f2: function (a, b) {
return a + b
}
}
a.self = a
const b = deepClone(a)
b.self === b // true
b.self = 'hi'
a.self !== 'hi' //true
要点: 1. 递归 2. 判断类型 3. 检查环 4. 不拷贝原型上的属性