导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

⭐ 什么是防抖?什么是节流?

操作 描述 场景
防抖 频繁去触发一个事件,但是只触发最后一次。以最后一次为准 1、电脑息屏时间,每动一次电脑又重新计算时间
2、input 框变化频繁触发事件可加防抖
3、频繁点击按钮提交表单可加防抖
节流 频繁去触发一个事件,但是只能每隔一段时间触发一次 1、滚动频繁请求列表可加节流
2、技能CD
function debounce(fn, delay) {
  let timer = null;
	return function() {
    if (timer) window.clearTimeout(timer);
  	timer = setTimeout(() => {
    	fn.apply(this, arguments);
      timer = null; // 当一个对象被赋值了null 以后,原来的对象在内存中就处于游离状态,GC 会择机回收该对象并释放内存。因此,如果需要释放某个对象,就将变量设置为null,即表示该对象已经被清空,目前无效状态。
    }, delay);
  }
}

function debounce(fn, delay, triggerNow) {
	let timer = null;
  return function() {
  	if (timer) window.clearTimeout(timer);
    if (triggerNow) {
    	let exec = !timer;
      timer = setTimeout(() => {
      	timer = null;
      }, delay);
      if (exec) {
      	fn.apply(this, arguments);
      }
    } else {
    	timer = setTimeout(() => {
      	fn.apply(this, arguments);
        timer = null;
      }, delay);
    }
  }
}

function throttle(fn, delay) {
	let canUse = true;
  return function() {
    if (canUse) {
    	fn.apply(this, arguments);
      canUse = false;
      setTimeout(() => canUse = true, delay);
    }
  }
}

什么是高阶函数?简单实现一个?

高阶函数:英文叫Higher-order function。JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

// 简单的高阶函数
function add(x, y, f) {
  return f(x) + f(y);
}

//用代码验证一下:
add(-5, 6, Math.abs); // 11

像数组的 map、reduce、filter 这些都是高阶函数

⭐ 什么是函数柯里化?简单实现一个?

柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

// 普通的add函数
function add(x, y) {
    return x + y
}

// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3

好处

// 正常正则验证字符串 reg.test(txt)

// 普通情况
function check(reg, txt) {
    return reg.test(txt)
}

check(/\\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
  return function(txt) {
    return reg.test(txt)
  }
}

var hasNumber = curryingCheck(/\\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false
function sayKey(key) {
  console.log(this[key])
}
const person = {
  name: 'Sunshine_Lin',
  age: 23
}
// call不是科里化
sayKey.call(person, 'name') // 立即输出 Sunshine_Lin
sayKey.call(person, 'age') // 立即输出 23

// bind是科里化
const say = sayKey.bind(person) // 不执行
// 想执行再执行
say('name') // Sunshine_Lin
say('age') // 23

⭐ 手动实现通用柯理化函数

柯理化函数含义:给函数分步传递参数每次传递部分参数并返回一个更具体的函数接收剩下的参数,这中间可嵌套多层这样的接收部分参数的函数,直至返回最后结果

// add的参数不固定,看有几个数字累计相加
function add (a,b,c,d) {
  return a+b+c+d
}
function currying (fn, ...args) {
  // fn.length 回调函数的参数的总和
  // args.length currying函数 后面的参数总和
  // 如:add (a,b,c,d)  currying(add,1,2,3,4)
  if (fn.length === args.length) {
    return fn(...args)
  } else {
    // 继续分步传递参数 newArgs 新一次传递的参数
    return function anonymous(...newArgs) {
      // 将先传递的参数和后传递的参数 结合在一起
      let allArgs = [...args, ...newArgs]
      return currying(fn, ...allArgs)
    }
  }
}
let fn1 = currying(add, 1, 2) // 3
let fn2 = fn1(3)  // 6
let fn3 = fn2(4)  // 10

来源:https://juejin.im/post/6870319532955828231

什么是 compose?简单实现一个?

简单的 compose 函数

const compose = (a , b) => c => a( b( c ) );

例子:统计单词个数

const space = (str) => str.split(' ')
const len = (arr) => arr.length

// 普通写法
console.log(len(space('i am linsanxin'))) // 3
console.log(len(space('i am 23 year old'))) // 5
console.log(len(space('i am a author in juejin'))) // 6

// compose写法
const compose = (...fn) => value => {
  return fn.reduce((value, fn) => {
    return fn(value)
  }, value)
}
const computedWord = compose(space, len)
console.log(computedWord('i am linsanxin')) // 3
console.log(computedWord('i am 23 year old')) // 5
console.log(computedWord('i am a author in juejin')) // 6

JS 中的 MUL 函数?

MUL表示数的简单乘法。在这种技术中,将一个值作为参数传递给一个函数,而该函数将返回另一个函数,将第二个值传递给该函数,然后重复继续。例如:xyz可以表示为

const mul = x => y => z => x * y * z

console.log(mul(1)(2)(3)) // 6

⭐ 手动实现发布订阅

class EventEmitter {
  handlers = {
    // 事件名: eventName: [订阅者1, 订阅者2, ...]
    // e.g. : click: [handler1, handler2, handler3]
  }

  // eventName: click事件/change事件...
  on(eventName, handler, once = false) {
    if (!this.handlers[eventName]) {
      this.handlers[eventName] = [];
    }
    if (!this.handlers[eventName].includes(handler)) {
      this.handlers[eventName].push(handler);
      handler.once = once;
    }
  }
  once(eventName, handler) {
    this.on(eventName, handler, true);
  }
  off(eventName, handler) {
    if (this.handlers[eventName]) {
      this.handlers[eventName] = this.handlers[eventName].filter(h => {
        return h !== handler;
      })
    }
  }
  trigger(eventName) {
    if (this.handlers[eventName]) {
      this.handlers[eventName].forEach(handler => {
        handler.call(this);

        if (handler.once) {
          this.off(eventName, handler);
        }
      });
    }
  }
}

const ev = new EventEmitter();

function handler1() {
  console.log('handler1');
}
function handler2() {
  console.log('handler2');
}
function handler3() {
  console.log('handler3');
}

ev.on('test', handler1);
ev.once('test', handler2);
ev.on('test', handler3);

ev.trigger('test');
ev.trigger('test');

JS 中的设计模式有哪些?

JavaScript 设计模式