本文介绍: 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支), 拷贝第一层级的对象属性或数组元素,如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。

一. 实现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进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注