资讯专栏INFORMATION COLUMN

30秒就能理解的 Javascript 代码片段 --- Array篇

fox_soyoung / 3422人阅读

摘要:而这个秒就能理解的代码片段,摒弃了许多不必要的代码,只实现了最核心的部分,不像和那样,考虑参数边界值问题,例如,参数的类型是否符合预期等。使用根据断言函数对数组进行过滤,返回条件为真值的对象。

之前翻译过一篇文章,《我喜欢的5个编程技巧》,里面的一个技巧是借鉴一个网站的代码片段,好奇的小手点下链接后,发现是一个有 47000 多star的仓库,30-seconds-of-code。

仓库的名字就让我很惊讶,30秒就能理解一段代码,有点不可思议。看了每个方法实现的代码都不长,很简短,最复杂的也不过是4、5行代码,的确没有标题党的嫌疑,满满的干活。

处理的类型还很丰富,有Array、Browser、Date、Function、Math、Node、Object、String、Type、Utility。要了解更多,戳这里。

这就是一个工具函数库呀。

此时让我想到了 lodash.jsunderscore.js,用过这两个函数式编程的库,对提供的方法肯定不陌生。它们主要是以函数作为主要载体的编程方式,用函数去拆解、抽象的表达式,每个函数封装特定的功能,作用域局限在函数内部,形成闭包,不对外界产生副作用。

相信也有很多人阅读过它们的源码,每个函数很简短,考虑到兼容性,基本都用原生的方式实现,不会调用一些规范中最新推出的方法。如果能够精读它们,对自己的编程能力会有更高的提升,能够掌握很多的技巧。有时你可能只是想快速的了解一个方法大致的实现原理,但要去看源码的话,还是会有一些门槛。

而这个30秒就能理解的代码片段,摒弃了许多不必要的代码,只实现了最核心的部分,不像 lodash.jsunderscore.js 那样,考虑参数边界值问题,例如,参数的类型是否符合预期等。默认情况下,都是按照传递符合预期的参数处理。

如果要把这个库用在自己的项目中,没有对参数的判断是非常糟糕的一件事。但不想引 lodash.jsunderscore.js 这样大的库文件,想自己实现一个简洁的方法快速使用,那么这个库会对你实现自己的方法具有指导意义。不考虑兼容问题的话,你可以直接拷贝这个库的代码片段,加上对参数边界的处理就直接能用。

再有一点,这个库之所以简短,能够让你在30秒就理解,主要是能用规范提供的最新方法就用,不再很费劲的自己实现一套,全都调用了原生提供的方法,包括 ES6 的方法。每个方法都是独立的,可独立测试,独立运行,和其他的方法互不牵扯,极大的降低了阅读时找各种方法会被打断思路的烦恼。

当然,如果你想阅读 lodash.jsunderscore.js 的源码,先阅读这个库会很有帮助,它排除了许多不必要的干扰让你很清晰很明确的get到核心的实现方式。

之前也有人翻译过,但都很早,大约2年前了,作者最新最近更新的方法都没有。而且仓库中不止提供 javascript 的方法,还有 css react 的简短代码,还有其他语言的。基于自己学习的目的,同时也让更多人掌握这些方法的实现方式,决定翻译成中文。

仓库地址:https://github.com/WYseven/30-seconds-of-code。感兴趣的,可以给个 star 哦!

目前已完成数组方法的翻译,点击查看 https://wyseven.github.io/30-seconds-of-code/。其他方法也在持续的更新中。。。

我不建议你闷着头一口气读完,然后头昏眼花的不知道自己看了什么。而是建议你在闲暇之余,工作空隙,断断续续,一天看几个就够了,权当做工作累了休憩时当做消遣来看。

因为篇幅的原因,以下随机选择了10个方法,你看简单不简单。

chunk
deepFlatten
flatten
initialize2DArray
union
mapObject
pull
reducedFilter
xProd
chunk

将数组分块成指定大小的较小数组。

使用 array.from() 创建一个新的数组,该数组的长度就是将要生成的块(chunk)的个数。
使用 array.prototype.slice() 将新数组的每个元素映射为一个长度为 size 的块(chunk)。
如果原始数组不能被平均分割,那么最后的块(chunk)将包含剩余的元素。

const chunk = (arr, size) =>
    Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
    arr.slice(i * size, i * size + size)
);
chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]
deepFlatten

深度平铺一个数组。

使用递归。
使用 array. prototype.concat() 和空数组( [] ),结合 spread 操作符("...")将数组平铺。
递归平铺数组中的每个元素。

const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
flatten

将数组展平到指定的深度。

使用递归,为每个深度级别 depth 递减 1。 使用 Array.prototype.reduce()Array.prototype.concat() 来合并元素或数组。 基本情况下,depth 等于 1 停止递归。 省略第二个参数,depth 只能平铺到 1 层(单层平铺) 的深度。

const flatten = (arr, depth = 1) =>
    arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
initialize2DArray

初始化一个给定行数和列数,以及值的二维数组。

使用 array.prototype.map() 生成 h 行,其中每一行都是长度为 w 的新数组。如果没有提供值 val,则默认为 null

const initialize2DArray = (w, h, val = null) =>
    Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
initialize2DArray(2, 2, 0); // [[0,0], [0,0]]
union

返回两个数组的并集,相同的元素只出现一次。

基于 ab 创建一个 Set 对象,返回转换后的数组。

const union = (a, b) => Array.from(new Set([...a, ...b]));
union([1, 2, 3], [4, 3, 2]); // [1,2,3,4]
mapObject

使用一个函数将数组的值映射到对象,在键值对中,原始值作为键,映射值作为值。

使用一个匿名的内部函数作用域来声明一个 undefined 的内存空间,使用闭包来存储返回值。 使用一个新的 Array 来存储带有函数映射的数组和一个逗号运算符来返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。

const mapObject = (arr, fn) =>
  (a => (
    (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
  ))();
const squareIt = arr => mapObject(arr, a => a * a);
squareIt([1, 2, 3]); // { 1: 1, 2: 4, 3: 9 }
offset

将指定数量的元素移动到数组的末尾。

两次使用 Array.prototype.slice() 来获取指定索引之后的元素和指定索引之前的元素。
使用展开操作符(...)将两个数组合成一个数组。
如果 offset 为负数,元素将从结束移动到开始位置。

const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
offset([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2]
offset([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3]
pull

改变原始数组,过滤掉指定的值。

使用 Array.prototype.filter()array.prototype.include() 过滤指定的值。
使用 Array.prototype.length = 0 通过将数组的长度重置为0来清空数组,并使用 array.prototype.push() 把提取的值重新填充数组。

(对于不改变原始数组的代码片段,请参阅 without)

const pull = (arr, ...args) => {
  let argState = Array.isArray(args[0]) ? args[0] : args;
  let pulled = arr.filter((v, i) => !argState.includes(v));
  arr.length = 0;
  pulled.forEach(v => arr.push(v));
};
let myArray = ["a", "b", "c", "a", "b", "c"];
pull(myArray, "a", "c"); // myArray = [ "b", "b" ]
reducedFilter

根据条件过滤一个对象数组,同时过滤掉未指定的键。

使用 array.prototype.filter() 根据断言函数 fn 对数组进行过滤,返回条件为真值(truthy)的对象。
在经过过滤后的数组上,使用 array.prototype.map()array.prototype.reduce() 过滤掉在 keys 参数中未提供的键。

const reducedFilter = (data, keys, fn) =>
  data.filter(fn).map(el =>
    keys.reduce((acc, key) => {
      acc[key] = el[key];
      return acc;
    }, {})
  );
const data = [
  {
    id: 1,
    name: "john",
    age: 24
  },
  {
    id: 2,
    name: "mike",
    age: 50
  }
];

reducedFilter(data, ["id", "name"], item => item.age > 24); // [{ id: 2, name: "mike"}]
xProd

将两个数组的每个元素两两进行组合,组合出所有的可能对存在数组中,返回一个存在所有可能性对的数组。

使用 Array.prototype.reduce(), Array.prototype.map()Array.prototype.concat() 从两个数组的元素中生成所有可能的对,并将它们保存在一个数组中。

const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
xProd([1, 2], ["a", "b"]); // [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]

看完后,是不是觉得实现特简洁特简单?

看完后,给个 star 哦!仓库地址:https://github.com/WYseven/30...。

如果对你有帮助,请关注【前端技能解锁】:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106152.html

相关文章

  • 【资源集合】 ES6 元编程(Proxy & Reflect & Symbol)

    摘要:理解元编程和是属于元编程范畴的,能介入的对象底层操作进行的过程中,并加以影响。元编程中的元的概念可以理解为程序本身。中,便是两个可以用来进行元编程的特性。在之后,标准引入了,从而提供比较完善的元编程能力。 导读 几年前 ES6 刚出来的时候接触过 元编程(Metaprogramming)的概念,不过当时还没有深究。今天在应用和学习中不断接触到这概念,比如 mobx 5 中就用到了 Pr...

    aikin 评论0 收藏0
  • 30秒一个知识点】Adapter

    摘要:给定一个函数,返回一个闭包,该闭包将所有输入收集到一个数组接受函数中。返回一个可变参数的闭包,在应用其他参数前,先把第一个以外的其他参数作为第一个参数。 showImg(https://segmentfault.com/img/remote/1460000018406951?w=1400&h=600); 本系列翻译自开源项目 30-seconds-of-code这是一个非常优秀的系列,...

    邹立鹏 评论0 收藏0
  • 写技术博客那点事

    摘要:从现在开始,养成写技术博客的习惯,或许可以在你的职业生涯发挥着不可忽略的作用。如果想了解更多优秀的前端资料,建议收藏下前端英文网站汇总这个网站,收录了国外一些优质的博客及其视频资料。 前言 写文章是一个短期收益少,长期收益很大的一件事情,人们总是高估短期收益,低估长期收益。往往是很多人坚持不下来,特别是写文章的初期,刚写完文章没有人阅读会有一种挫败感,影响了后期创作。 从某种意义上说,...

    ddongjian0000 评论0 收藏0
  • 写技术博客那点事

    摘要:从现在开始,养成写技术博客的习惯,或许可以在你的职业生涯发挥着不可忽略的作用。如果想了解更多优秀的前端资料,建议收藏下前端英文网站汇总这个网站,收录了国外一些优质的博客及其视频资料。 前言 写文章是一个短期收益少,长期收益很大的一件事情,人们总是高估短期收益,低估长期收益。往往是很多人坚持不下来,特别是写文章的初期,刚写完文章没有人阅读会有一种挫败感,影响了后期创作。 从某种意义上说,...

    NSFish 评论0 收藏0
  • 30秒可以理解有用js代码片段

    摘要:相当于的使用返回一个函数,返回一个调用原始函数的。你可以省略来使用窗口的默认值。第一个最左边的函数可以接受一个或多个参数其余的功能必须是一元的。使用删除任何空字符串。如果是位数的颜色代码,则先转换为位数字版本。转颜色将的值转换为颜色代码。 原文基础上增加了其它方法以及注释等,进行了小幅度修改,便于阅读注意箭头函数有无{}会影响是否需要再return 原文地址 Adapter 适配器,以...

    phoenixsky 评论0 收藏0

发表评论

0条评论

fox_soyoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<