深拷贝(包含Symbol, 环)
JSON.parse/JSON.stringify
#
递归实现 (该方法容易爆栈)
function deepClone (source, hash=new WeakMap()) {
// 第一步:判断是否为对象
if (!isObject(source)) return source
// 第二步:判断是否为环
if (hash.has(source)) return hash.get(source)
// 以上都不满足
let target = Array.isArray(source) ? [...source] : {...source}
hash.set(source, target)
Reflect.ownKeys(target).forEach(key => {
if (isObject(source[key])) {
target[key] = deepClone(source[key], hash)
} else {
target[key] = source[key]
}
})
return target
}
广度优先遍历实现
function cloneDeep(x) {
const root = {}
const loopList = [{
parent: root,
key: undefined,
data: x,
}]
while(loopList.length) {
// 广度优先
const node = loopList.pop()
const parent = node.parent
const key = node.key
const data = node.data
// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
let res = parent
if (typeof key !== 'undefined') {
res = parent[key] = {}
}
for(let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({ parent: res, key: k, data: data[k], })
} else {
res[k] = data[k]
}
}
}
}
return root
}
防抖
function debounce(fn, delay) {
let timer = null;
return function() {
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(this, arguments);
}, delay)
}
}
立即执行版本:
function debounce(fn, delay, immediate) {
let timer;
return function(){
clearTimeout(timer);
if(immediate){
const callNow = !timer;
timer = setTimeout(function(){
timer = null;
}, delay)
if(callNow) {
fn.apply(this, arguments)
};
} else {
timer = setTimeout(function(){
fn.apply(this, arguments)
}, delay)
}
}
}
适用于:resize,搜索,点击按钮,DOM元素的拖拽等
节流
1. 时间戳
function throttle (fn, delay) {
let pre = Date.now()
return function() {
let current = Date.now()
if(current - pre >= delay) {
fn.apply(this, arguments)
pre = Date.now()
}
}
}
2. 时间戳 + 定时器
function throttle(fn, delay) {
let start = Date.now()
let timer = null
return funtion () {
let current = Date.now()
let remaining = delay - (current - start)
cleartTimeout(timer)
if(remaining <= 0) {
fn.apply(this, arguments)
start = Date.now()
} else {
timer = setTimeout(fn, remaining)
}
}
}
适用于:scroll事件,
reduce
用法:reduce(callback, initValue)
Array.prototype.my_reduce = (callback, ...args) => {
let start = 0
let pre
if(args.length > 0) {
pre = args[0]
} else {
pre = this[0]
start = 1
}
for (let i = start
pre = callback(pre, this[i], i, this)
}
return pre
}
数组扁平化
let ary = [1, [2, 3, [4, 5, [6, 6, 7, 8, [10]]]]];
function a0(ary) {
let str = ary.join(',');
let newAry = str.split(',');
let ret = newAry.map(item => {
return parseInt(item)
});
return ret;
}
console.log(a0(ary))
function a1(ary) {
let res = [];
for (let index = 0; index < ary.length; index++) {
if (Array.isArray(ary[index])) {
res = res.concat(a1(ary[index]));
} else {
res.push(ary[index]);
}
}
return res;
}
console.log(a1(ary))
function a2(ary) {
let res = ary.reduce((pre, item) => {
if (Array.isArray(item)) {
return pre.concat(a2(item));
} else {
return pre.concat(item);
}
}, [])
return res;
}
console.log(a2(ary))
function a3(ary) {
while (ary.some(item => Array.isArray(item))) {
ary = [].concat(...ary);
}
return ary;
}
console.log(a3(ary))
console.log(ary.flat(40))
数组去重
let ary = [1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 66, 7, 8, 8, 8, 7, 5, 3]
// 方法一:
console.log([...new Set(ary)])
// 方法二:
function a1(ary) {
let res = []
for (let i = 0
if (!res.includes(ary[i])) {
res.push(ary[i])
}
}
return res
}
console.log(a1(ary))
// 方法三:
function a2(ary) {
let res = []
let obj = {}
for (let i = 0
if (obj[ary[i]]) {
obj[ary[i]] += 1
}else {
obj[ary[i]] = 1
res.push(ary[i])
}
}
return res
}
console.log(a2(ary))
// 方法四:
function a3(ary) {
let res = []
for (let i = 0
if (res.indexOf(ary[i]) < 0) {
res.push(ary[i])
}
}
return res
}
console.log(a3(ary))
// 方法五:
function a4(ary) {
let res = []
res = ary.filter((item, index) => {
return ary.indexOf(item) === index
})
return res
}
console.log(a4(ary))
new
new 操作符所做的事情
1. 创建一个空的简单JavaScript对象(即`{}`);
2. 链接该对象(即设置该对象的构造函数)到另一个对象 ;
3. 将步骤1新创建的对象作为`this`的上下文 ;
4. 如果该函数没有返回对象,则返回`this`。
function create(){
let Con = [].shift.call(arguments);
let obj = Object.create(Con.prototype);
let res = Con.apply(obj, arguments);
return res instanceof Object? res : obj;
}
instanceof
function my_instanceof = function(L, R) {
let Lv = L.__proto__
let Rv = R.prototype
while(true) {
if(Lv === Rv) {
return true
}
if( Lv === null ) {
return false
}
Lv = Lv.__proto__
}
}
快排
function qucklySort(ary) {
if (ary.length < 2) return ary
let middleIndex = parseInt(ary.length / 2)
let middleValue = ary.splice(middleIndex, 1)[0]
let left = []
let right = []
for (let index = 0
if (ary[index] > middleValue) {
right.push(ary[index])
} else {
left.push(ary[index])
}
}
return [...qucklySort(left), middleValue, ...qucklySort(right)]
}
优化:
function qucklySort2(ary, left, right) {
if (left < right) {
let pos = left - 1
for (let index = left
let posV = ary[right]
if (ary[index] <= posV) {
pos++
let temp = ary[pos]
ary[pos] = ary[index]
ary[index] = temp
}
}
qucklySort2(ary, left, pos - 1)
qucklySort2(ary, pos + 1, right)
}
return ary
}
冒泡
function bubbleSort(ary) {
for (let index = 0
let flag = true
for (let k = 0
if (ary[k] > ary[k + 1]) {
flag = false
[ary[k], ary[k + 1]] = [ary[k + 1], ary[k]]
}
}
if (flag) {
return
}
}
return ary
}
forEach
arr.forEach(cabllback)
Array.prototype.my_forEach = function(callback) {
for(let index = 0
callback(this[index], index, this)
}
}
map
map(callback)
Array.prototype.my_map = funtion (callback) {
let res = []
for(let index = 0
res.push(callback(this[index], index, this))
}
return res
}
二分查找
let ary = [1, 3, 3121, 6, 0, 31, 4, 2, 12, 53, 7, 434, 8, 9]
function binary(ary, target) {
let len = ary.length
if (len === 0) return -1
ary.sort((a, b) => a - b)
let low = 0
let high = len - 1
while (low <= high) {
let middleIndex = Math.floor((high + low) / 2)
if (ary[middleIndex] === target) {
return "存在"
} else if (ary[middleIndex] < target) {
low = middleIndex + 1
} else if (ary[middleIndex] > target) {
high = middleIndex - 1
} else {
return '不存在'
}
}
}
Object.create
function create(o){
let F = function(){}
F.prototype = o
let obj = new F()
return obj
}
call,apply,bind
call
Function.prototype.my_call = function(obj, ...args) {
obj.fn = this
let res = obj.fn(...args)
delete obj.fn
return res
}
apply
Function.prototype.my_apply = function(obj, ary) {
obj.fn = this
let res
if(ary && ary.length > 0) {
res = obj.fn(...ary)
} else {
res = obj.fn()
}
delete obj.fn
return res
}
bind
Function.prototype.my_bind = function(obj, ...args) {
obj.fn = this
return function (){
const newArr = args.concat(...arguments)
let res = obj.fn(...newArr)
delete obj.fn
return res
}
}
promise
promise.finally
finally(callback) {
return this.then(
value => Promise.resolve(callback()).then(() => value),
reason => Promise.resolve(callback()).then(() => {throw reason })
)
}
promise.race
race(promiseArr) {
return new Promise((resolve, reject) => {
for(let item of promiseArr) {
Promise.resolvue(item).then(
value => resolve(value),
err => reject(err)
)
}
})
}
promise.all
all(promiseArr) {
let index = 0
let res = []
return new Promise((resolve, reject) => {
promiseArr.forEach((item, index) => {
Promise.resolve(item).then(
val => {
index++
res[index] = val
if(index === promiseArr.length) {
reslove(res)
}
},
err => {
reject(err)
}
)
})
})
}
柯里化
add(1)(2)(3)(4)(5).toStrng();
function add(){
let args = Array.prototype.slice.call(arguments);
let _innerAdd = function(){
args.push(...arguments);
return _innerAdd;
}
_innerAdd.toString = function(){
return args.reduce((a,b) => a+b);
}
return _innerAdd;
}
compose函数
function compose(...args1) {
return function (...args2) {
if(args1.length === 0) {
return args2
}
if(args1.length === 1) {
return args1[0](...args2)
}
return args1.reduce(function(pre, next) => {
return Array.isArray(pre) ? next(...pre) : next(pre)
}, args2)
}
}
const fn1 = x => x+10
const fn2 = x => x-10
const fn3 = x => x*10
const fn4 = x => x/10
let res = compose(fn1,fn2,fn3,fn4)(20)
console.log(res)
filter
filter(callback)
Array.prototype.my_filter = function(callback) {
let res = []
for(let index = 0
callback(this[index], index, this) && res.push(this[index])
}
return res
}
LRU(最近最少使用)
let LRUcache = function(capacity) {
let cache = new Map();
this.capacity = capacity;
}
LRUcache.prototype.get = function(key) {
if (this.cache.has(key)) {
let temp = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, temp);
return temp
}
return -1;
}
LRUcache.prototype.set = function(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
}
sleep函数
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
归并排序
使用setTimeout模拟setInterval
let timer = null
function interval(fn ,wait) {
let interv = function(){
fn.call(null)
timer = setTimeout(interv, wait)
}
timer = setTimeout(interv, wait)
}
rem的实现原理
function setRem () {
let doc = document.documentElement
let width = doc.getBoundingClientRect().width
ler rem = width / 7.5
doc.style.fontSize = rem
}
window.addEventLinstener('resize', setRem())
将金额转换为千分位写法
function money2String(money) {
let moneyStr = money.toString()
let moneyAry = moneyStr.split('')
let res = []
while (moneyAry.length > 3) {
res.unshift(moneyAry.splice(moneyAry.length - 3, 3))
}
res.unshift(moneyAry)
let s = res.map((item) => {
return item.join('')
})
return s.join(',')
}
数组find
数组from
数组findIndex
数组some
数组every