文章目录
一. 实现call, apply, bind方法
相同点:它们的共同点是都可以修改函数
不同点:this 指向第一个是传参方式不同: call 和 bind 是列表传参,apply是数组或伪数组传参 第二个是执行机制不同:call 和 apply 是立即执行,bind 不会立即执行而是生成一个修改 this之后的新函数
Function.prototype.myCall = function(context) {
if(typeof this !== 'function') {
throw new Error('type error')
}
let args = [...arguments].slice(1)
context = context || window
context.fn = this
let result = context.fn(...args)
delete context.fn
return result
}
Function.prototype.myApply = function(context) {
if(typeof this !== 'function') {
throw new Error('type error')
}
let arrParams = arguments[1] || []
context = context || window
context.fn = this
let result = context.fn(...arrParams)
delete context.fn
return result
}
Function.prototype.myBind = function(context) {
if(typeof this !== 'function') {
throw new Error('Error')
}
let args = [...arguments].slice(1),
fn = this
return function Fn() {
return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
}
}
二. 防抖节流函数
2.1 概念
防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
2.2 使用场景
2.3 实现
// 基础版
function debbounce(fn, delay) {
let timer
return function(...args) {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
// 防抖函数第一次点击直接执行
function debounce(fn, delay, immediate) {
let timer
return function(...args) {
if(timer) clearTimeout(timer)
if(immediate) {
let firstRun = !timer
if(firstRun) {
fn.apply(this, args)
}
timer = setTimeout(() => {
timer = null
}, delay)
} else {
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
}
// 时间戳写法
function throller(fn, delay) {
let time
return function() {
let now = Date.now()
if(now - time > delay) {
fn.call(this, arguments)
time = now
}
}
}
// 定时器写法
function throller(fn, delay) {
let timer = null
return function(...args) {
if(!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
})
}
}
}
三. lodash.get的实现
function lodashGet(object, path, defaultValue) {
let obj = object
if(typeof path === 'string') {
const reg = /[^[]""''.]+/g
path = path.match(reg)
}
for(let key of path) {
if(!obj) {
return defaultValue
}
obj = obj[key]
}
return obj
}
const object = { a: [{ b: { c: 3 } }] }
console.log(lodashGet(object, 'a[0]["b"]["c"]'))
//=> 3
console.log(lodashGet(object, "a[0].b.c"))
//=> 3
console.log(lodashGet(object, 'a[0]["b"]["c"]'))
//=> 10086
console.log(lodashGet(object, "a[100].b.c", 10086))
四. 深浅拷贝的实现
4.1 概念
浅拷贝:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支), 拷贝第一层级的对象属性或数组元素,
递归拷贝所有层级的对象属性和数组元素
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
4.2 实现方法
浅拷贝的实现方法:
- Object.assign
- 扩展运算符
- Array.prototype.slice
- Array.prototype.concat
- lodash的clone方法
- 手写实现
深拷贝的实现方法:
- JSON.parse(JSON.stringfy())
- lodash实现
- 手写实现
4.3 手写实现
浅拷贝:
function shallowClone(source) {
let target = {};
for(let i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
深拷贝:
const obj = {
re: /hello/,
f() {},
date: new Date(),
map: new Map(),
list: [1, 2, 3],
a: 3,
b: 4,
};
function deepClone(source, cache = new WeakMap()) {
if(typeof source !== 'object') {
return source
}
if(cache.has(source)) {
return cache.get(source)
}
let res = new source.constructor()
cache.set(source, res)
if(source instanceof Array) {
source.forEach((v) => {
res.push(deepClone(v, cache))
})
} else if (source instanceof Map) {
for(const [k, v] of source) {
res.set(k, deepClone(v, cache))
}
} else if (source instanceof Set) {
for(const v of source) {
res.add(deepClone(v, cache))
}
} else if (Object.prototype.toString.call(source) == '[object Object]') {
for(const key in source) {
res[key] = deepClone(source[key], cache)
}
} else {
res = new source.constructor(source)
}
return res
}
const newObj = deepClone(obj);
console.log(newObj);
五. flat拍平实现
function flatten(arr, depth) {
if(!depth) return arr
let res = []
for(let i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i], --depth))
} else {
res.push(arr[i])
}
}
return res
}
console.log(flatten([1, 2, 3, [4, [5, 6]]], 1));
function flatten(arr, depth) {
while(arr.some(item => Array.isArray(item) && depth)) {
arr = [].concat(...arr)
depth--
}
return arr
}
console.log(flatten([1, 2, 3, [4, [5, 6]]], 1));
function flatten(arr, depth = 1) {
if (depth === 0) return arr;
return arr.reduce(
(a, b) => a.concat(Array.isArray(b) ? flatten(b, depth - 1) : b),
[],
);
}
console.log(flatten([1, 2, 3, [4, [5, 6]]], 1));
function flatten(arr) {
return arr.toString().split(',').map(item => parseInt(item))
}
console.log(flatten([1, 2, 3, [4, [5, 6]]]));
六. 手写实现LRU算法
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (!this.cache.has(key)) {
return -1;
}
const temp = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, temp);
return temp;
}
put(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);
}
}
七. 实现once方法,只执行一次
function once(f) {
let result;
let revoked = false;
return (...args) => {
if (revoked) return result;
const r = f(...args);
revoked = true;
result = r;
return r;
};
}
八. 对字符串进行压缩编码
//=> a4b3c2
encode("aaaabbbcc");
//=> a4b3a4
encode("aaaabbbaaaa");
//=> a2b2c2
encode("aabbcc");
function encode(str) {
let count = 1
prev = ''
res = ''
for(const v of str) {
if(v == prev) {
count++
} else {
res += `${count}${prev}`
count = 1
}
prev = v
}
res +=`${count}${prev}`
return res
}
console.log(encode('aaabbc'));
原文地址:https://blog.csdn.net/qq_63299825/article/details/135911628
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_63347.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!