hand write
🔈

hand write

Tags
Published
Author
 
  1. 防抖
    1. // 防抖 // 只执行最后一次 const debounce = (fn, delay) => { let timer = null; return function (...args) { const ctx = this; if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn.apply(ctx, ...args); }, delay); }; };
  1. 节流
    1. function throttle(fn, delay) { let lastTime = 0; return function (...args) { const ctx = this; const now = new Date().getTime(); if (now - lastTime > delay) { fn.apply(ctx, ...args); lastTime = now; } }; }
      知识点
      1. js 中如何声明不定长的参数
        1. function f(...args) { let [a, b, c] = args; console.log(a); // 输出:'a' console.log(b); // 输出:'b' console.log(c); // 输出:'c' } f('a', 'b', 'c'); //或者 function exampleFunction() { console.log(arguments[0]); // 输出:1 console.log(arguments[1]); // 输出:2 console.log(arguments[2]); // 输出:3 } exampleFunction(1, 2, 3);
      1. call bind apply 的区别
        1. //call: 改变 this 指向,并且立即执行,返回原函数的执行结果。 //apply:同 call,只是接受一个数组参数。 //bind:改变 this 指向,返回一个函数,调用这个函数时,会改变 this 指向。 function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'John' }; // 使用 call greet.call(person, 'Hello', '!'); // 输出:"Hello, John!" // 使用 apply greet.apply(person, ['Hello', '!']); // 输出:"Hello, John!" // 使用 bind const greetPerson = greet.bind(person); greetPerson('Hello', '!'); // 输出:"Hello, John!"
           
  1. call
    1. Function.prototype.call = function (ctx, ...args) { // if (typeof this !== 'function') { throw new TypeError('Not callable'); } // 这里 this 就是原来的函数 const fn = this || window; // 改变 this 指向,怎么改变呢,用传进来的 ctx.fn // 所以需要把原函数 fn 变为 ctx 的一个 属性 // 使用 symbol 是为了防止重复 const fnSymbol = Symbol(); ctx[fnSymbol] = fn; const result = ctx[fnSymbol](...args); delete ctx[fnSymbol]; return result; };
  1. apply
    1. fn.apply(yd, [1, 2]); Function.prototype.myApply = function (ctx, argsList) { // 校验参数,增加健壮性 ctx = ctx || window || global; argsList = argsList || []; if (!Array.isArray(argsList)) { throw new TypeError('参数不是数组'); } // code const fn = this; if (typeof fn !== 'function') { throw TypeError('不是函数'); } const symbol = Symbol(); ctx[symbol] = fn; // 要把 argsList 解构 const result = ctx[sym](...argsList); delete ctx[symbol]; return result; };
  1. bind
    1. Function.prototype.myBind = function (context, ...args) { // 确保调用myBind的是一个函数 if (typeof this !== 'function') { throw new TypeError('Bind must be called on a function'); } // 拿到函数本身 var self = this; // 绑定函数也可能使用new关键字调用,需要处理这种情况。所以需要一个中间函数来实现原型链继承。 var fNOP = function () {}; // 返回一个新函数 var fBound = function (...bindArgs) { // 当用new调用绑定函数时,this的值应该是新创建的实例对象 var finalArgs = args.concat(bindArgs); // 预设参数和后续调用时传递的参数拼接 return self.apply(this instanceof fNOP ? this : context, finalArgs); }; // 中间函数的原型指向函数的原型 if (this.prototype) { fNOP.prototype = this.prototype; } // 修改返回函数的原型为中间函数的实例,保证原型链不变 fBound.prototype = new fNOP(); return fBound; };
       
  1. 拷贝
    1. 浅拷贝
    2. JavaScript 中的浅拷贝指的是创建一个新对象,并将原对象的每个属性值复制到新对象中。如果属性值是基本类型,则复制值本身;如果属性值是复杂类型(如对象或数组),则复制引用而不是实际的对象。这意味着如果原对象中的属性值是对象或数组,新对象和原对象将共享这些属性值的引用。
      function shallowCopy(obj) { // 只拷贝对象 if (typeof obj !== 'object' || obj == null) { return obj; } // 根据obj是数组还是对象,新建一个数组或对象 var copy = obj instanceof Array ? [] : {}; // 遍历对象的key,将每个key的值都赋给copy对象 for (var key in obj) { // 确保属性是对象本身拥有的,而不是继承自其原型链 if (obj.hasOwnProperty(key)) { copy[key] = obj[key]; } } return copy; } // 示例 var originalObj = { a: 1, b: { c: 2 }, d: [3, 4], }; var copiedObj = shallowCopy(originalObj); console.log(copiedObj); // { a: 1, b: { c: 2 }, d: [3, 4] } var copiedObj = Object.assign({}, originalObj); var copiedObj = { ...originalObj };
       
      深拷贝
      实现深拷贝的目的是创建一个新对象,并递归复制原对象的所有属性值,不仅仅是第一层属性。如果属性值是基本数据类型,复制值本身;如果属性值是引用数据类型(例如对象或数组),则递归复制所有子对象,从而实现完全独立的副本。
      // 深拷贝 // 要递归 // 要解决循环引用的问题 const deepCopy = function (obj, hash = new WeakMap()) { // hash 是为了解决循环引用的问题 if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj === 'object') { if (hash.has(obj)) return hash.get(obj); const cloneObj = Array.isArray(obj) ? [] : {}; hash.set(obj, cloneObj); for (let k in obj) { if (obj.hasOwnProperty(k)) { cloneObj[key] = deepCopy(obj, hash); } } return cloneObj; } else { return obj; } }; // JSON 序列化与反序列化 。不能处理函数、undefined、循环引用。 const dCopy = JSON.parse(JSON.stringify(obj));
       
       
  1. 发布订阅(简单版)
// 发布订阅 // 订阅,发布,取消订阅,只执行一次 class PubSub { constructor() { // 简单点,只针对单个属性 this.subscribers = []; } subscribe(cb) { if (cb instanceof Function) { this.subscribers.push(cb); } } ubSubscribe(cb) { if (cb) { const index = this.subscribers.indexOf(cb); this.subscribers.splice(index, 1); } else { this.subscribers = []; } } publish(data) { this.subscribers.forEach((cb) => { cb(data); }); } once(cb) { const execOnce = (data) => { cb(data); this.ubSubscribe(cb); }; this.subscribe(execOnce); } }
 
  1. promise(简单版)