Simonzhangs' blog Simonzhangs' blog
首页
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • JS设计模式总结
  • 《Vue》
  • 《React》
  • 《TypeScript 从零实现 axios》
  • TypeScript
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • apple music
  • extension
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Simonzhangs

前端学习探索者
首页
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • JS设计模式总结
  • 《Vue》
  • 《React》
  • 《TypeScript 从零实现 axios》
  • TypeScript
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • apple music
  • extension
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JS基础

    • typeof与instanceof
    • JS变量声明的六种方式
    • this指向
    • ==和===运算符区别
    • Promise基础
    • JS异步发展
  • 基础
  • 内置对象
  • 面向对象
  • 异步操作
  • DOM
  • 事件
  • 浏览器模型
  • JS常见高级函数
    • 1. 节流函数
    • 2. 防抖函数
    • 3. 深拷贝
    • 5. 大数之和
    • 6. 扁平化数组
    • 7. 保证对象数据不可修改
  • 《JavaScript教程》笔记
simonzhangs
2022-04-16
目录

JS常见高级函数

# 1. 节流函数

在规定的一个单位时间内,事件只能触发一次;如果单位内触发多次函数,只有一次生效。

function throttle(func, ms) {
  let timer = null;
  return function () {
    let that = this;
    let args = arguments;
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        func.apply(that, args);
      }, ms);
    }
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2. 防抖函数

在事件被触发后 n 秒内再执行回调,如果 n 秒内再次触发,则重新计时。

function debounce(func, ms) {
  let timer = null;
  return function () {
    let that = this;
    let args = arguments;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(that, args);
    }, ms);
  };
}
1
2
3
4
5
6
7
8
9
10
11

# 3. 深拷贝

对于数组、对象等类型时引用类型,变量标识符存储的指针指向堆中的对象,需要深拷贝赋值。

function copy(obj) {
  let newObj = null;
  if (typeof obj == "object" && typeof obj !== null) {
    newObj = obj instanceof Array ? [] : {};
    for (let i in obj) {
      newObj[i] = copy(obj[i]);
    }
  } else {
    newObj = obj;
  }
  return newObj;
}
1
2
3
4
5
6
7
8
9
10
11
12

更加严谨的写法:

function deepClone(obj={}){
  if(tyoeof obj !== 'object') { return obj;}

  let result = {};
  if(obj instanceof Array || Object.prototype.toString().call(obj) === '[object Arrray]') { result = [];}
  for(const key in obj) {
    if(obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key]);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
  1. 手写 Promise.all
function PromiseAll(arr) {
  // 将可迭代对象转换成一个数组
  let promises = Array.from(arr);
  const data = [];
  let index = 0,
    len = promises.length;
  return new Promise((resolve, reject) => {
    for (let i in promises) {
      // 需要并发执行,需要先resolve执行每个promise,再then
      Promise.resolve(promises[i])
        .then((res) => {
          // 不要用push,用下标存储,保证输出的顺序
          data[i] = res;
          if (++index === len) {
            resolve(data);
          }
        })
        .catch((err) => {
          reject(err);
        });
    }
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

扩展:手写 Promise.race:

function promiseRace(iterator) {
  const promises = Array.from(iterator);
  return new Promise((resolve, reject) => {
    for (const i in promises) {
      Promise.resolve(promises[i])
        .then((res) => resolve(res))
        .catch((err) => reject(err));
    }
  });
}
1
2
3
4
5
6
7
8
9
10

手写 Promise.allSettled:

const myPromiseAllSettled(iterator) {
  return new Promise((resolve, reject) => {
    if(!Array.isArray(iterator)) {
      return reject(new Error('params is not an iteraor Array'))
    }
    let res = [],count = 0;
    for(let i=0;i<iterator.length;i++) {
      Promise.resolve(iterator[i]).then(value => {
        res[i] = {status: fulfilled, value};
      }).catch(err => {
        res[i] = {status:reject,err};
      }).finally(() => {
        count++;
        if(count === iterator.length) {
          resolve(res);
        }
      })
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 5. 大数之和

尽量避免采用 BigInt 类型,比如说 QQ 好像就不支持,一般采用通用方法。

function add(a, b) {
  let n = Math.max(a.length, b.length);
  a = a.padStart(n, 0);
  b = b.padStart(n, 0);

  let carry = 0;
  let res = "";
  for (let i = n - 1; i >= 0; i--) {
    let t = parseInt(a[i]) + parseInt(b[i]) + carry;
    carry = Math.floor(t / 10);
    t = t % 10;
    res = t + res;
  }
  if (carry === 1) {
    res = "1" + res;
  }
  return res;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 6. 扁平化数组

const flat = arr => arr.flat();

const flat = arr => arr.reduce((a,b) => Array.isArray(b) ? [...a,...flat(b)] : [...a,b],[]);

// 指定深度
const flat = (arr, dep = 1) => {
  if(dep > 0) {
    return arr.reduce((a,b) => Array.isArray(b) ? [...a,...flat(b,dep-1)] : [...a,b], []);
  }else {
    return arr;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 7. 保证对象数据不可修改

const定义的变量是常量,如果定义的是基本类型数据,则变量指向的内存地址中存储的就是该值,不可修改;但是如果是对象类型的话,变量中存储的是指针,该指针指向存储的数据,此时就只能保证指针是固定的,指向的数据还是可以改变的,如何保证复合类型的值不可修改呢?可以使用Object.freeze()方法。

const constantize = obj => {
  Object.freeze(obj);
  Object.keys(obj).forEach(key => {
    if(typeof obj[key] === 'object') {
      constantize(obj[key]);
    }
  })
}
1
2
3
4
5
6
7
8

参考链接:

  • 单行代码就能实现的 JavaScript 实用程序 (opens new window)
  • Favorite JavaScript Utilities in single line of code! No more! (opens new window)
  • 数组多维转一维度(扁平化)的6种方法 (opens new window)
编辑 (opens new window)
上次更新: 2022/06/16, 10:52:37
浏览器模型

← 浏览器模型

最近更新
01
一些有意思的类比
06-16
02
the-super-tiny-compiler解析
06-06
03
计算机编译原理总概
06-06
更多文章>
Theme by Vdoing | Copyright © 2021-2022
蜀ICP备2021023197号-2
Simonzhans | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
  • 飙升榜
  • 新歌榜
  • 云音乐民谣榜
  • 美国Billboard榜
  • UK排行榜周榜