分类目录归档:前端开发

阅读清单 #3

最近使用 Storybook 搭了个环境测试组件,为了一个简单的功能愣是四处翻文档和源码折腾了一下午才搞定。再也不想用 Webpack 了。🙃

发表在 前端开发 | 标签为 | 一条评论

阅读清单 #2

不知不觉五一小长假已过半,上个月部门作了很大的结构调整,我的团队成员构成也更加丰富,大家快乐又忙碌。最近认真阅读的文章比较少,先发一小部分吧。最近给我的 Mac Pro(2013)换上了 LG UltraFine 4K,真香呐!😁

发表在 前端开发 | 标签为 | 一条评论

阅读清单 #1

最近受疫情影响一直在远程办公,很多项目推进节奏都有所放缓,也有更多时间专注看文章。过去 10 年一直都在坚持每天的技术文章阅读,有段时间也专门写周刊分享给组里的成员,以后有精力的话会整理在这里。 继续阅读

发表在 前端开发 | 标签为 | 留下评论

在 MacOS 下捕获模拟器中发出的网络请求

最近在做一个 React Native 项目遇到了一个小问题:安装 react-native-cookiemanager 后,如何测试 cookie 是否设置成功并随请求发送,同时不影响 React Native 本地编译服务的连接(即不影响远程 JS Debug、热刷新等功能)。 使用 Charles 全局代理捕获网络请求 单纯的使用 Charles 抓包,需要给模拟器或测试机指定代理到本机 IP 的 8888 端口。这样虽然可以捕获请求,但也导致热刷新无法连接本地开发服务器。之后我尝试使用 Charles 全局代理来抓包,结果发现依然不能捕获 Genymotion 里的请求。网上搜了一下,还是需要在模拟器系统里设置网络代理到 10.0.3.2:8888,这样一来就跟 Charles 本身代理无异了。 使用 Wireshark 捕获网络请求 后来同事建议直接用 Wireshark,虽然有点大炮打蚊子但还是轻松地解决了我的需求。 在 Wireshark 里设置想抓取的域名/IP 以及接口就可以了。 捕获到请求后,右键选择「追踪流」-「HTTP 流」。 然后就会弹一个新窗口展示了请求的完整信息。此时已经可以看到请求时的 cookie 等信息了。 这样我就可以一边开发一边测试了,而不需要频繁切代理。需要注意的是 Wireshark 如果在配置不佳的机器(如单位的 iMac)上使用,如果开启捕获后不关掉,时间久了可能会卡死。所以抓完包即时关掉,随用随开。 使用 Debookee 捕获网络请求 同样是同事推荐的应用,之前没用过。这个是付费的,但是界面简洁很多。打开后开启捕获,然后左边直接切换到 HTTP 请求就行了。 每条请求点箭头展开就能查看详细信息,非常方便。 遗憾的是免费版功能有限制,开一会儿捕获的数据就「打码」展示了,此时重开一下就好。舍不得花 $29.90 买,所以忍了。 相关下载 Charles($50):官网 Wireshark(免费):官网 Deebookee($29.90起):官网 -- EOF --

发表在 前端开发 | 标签为 , , , | 一条评论

[译]ES6 中你应该知道的 Numbers 用法

本文翻译自:What You Should Know About Numbers in ES6 JavaScript 在 JavaScript 中,数据类型 Number 被应用在很多地方。自 ES6 起,Number 有了大量地改进来帮助开发者提升开发效率。下面是 ES6 为我们带来的几个新特性。 二进制与八进制直接量 对新人来讲,开发者现在能够在 ES6 中使用前缀来表达不同的数字系统。 表达二进制数字使用 0b 前缀,使用 00 前缀表达八进制数字(译注:都是数字 0)。 Number.isNaN Number.isNaN 与它的全局函数不同。它不会在比较前通过 Number(value) 作数字类型转换。 只有数值确实是 NaN 时 Number.isNaN 才会返回真。 蛋疼的是 typeof NaN === 'number',所以 typeof NaN === 'number' 并不能精准地告诉你值是否是一个数字。它只告诉你该值属于数字,也包括了 NaN。 因此更精确的判断方式是: typeof value === 'number' && !Number.isNaN(value) 当然,其它处理数字是否被错误描述的方式包括 Number(x) === x 将只在数字时返回 true。 Number.isFinite Number.isFinite 同样与全局的 isFinite 有些区别,Number.isFinite 不会在计算前通过 Number(value) 作数字类型转换。 例如,非数字在类型转换时会等于 0(Number(null) === 0)。 这种情况下 Number.isFinite 更高级一些。 Number.isInteger 这是 ES6 的新功能,它可以检测一个数字是否是整数。不需要用 Number(value) 作类型转换,非数字例如 null 会直接返回 false。 Number.parseInt, Number.parseFloat Number.parseInt 和 Number.parseFloat 跟他们的全局函数表现一毛一样。 Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER 它们表述了在 JavaScript 的实现里,可以安全使用的最大/最小数值。它由 IEEE 浮点限制(IEEE 754)在 2⁵³-1。 当然,最小安全整数是最大值的负值。要记住电脑在内存里是如何存储数字的。 Number.isSafeInteger Number.isSafeInteger 直接返回提供的值是否位于上面的最大/最小值之间。 Number.EPSILON 在 JavaScript 里,当浮点数在系统里不能被精确描述时会触发取整误差。例如,.1 加 .2 不等于 .3! Number.EPSILON 提供了一个可接受的误差范围用来计算(译注:Number.EPSILON 属性表示数字 1 和在 JavaScript 里大于 1 的最小数值之间的差值,详见 MDN)。所以可以用来检测计算误差是否处于可接受的范围,就像这样: 在 ES6 中,Numbers 有了长足的进步,并且仍有不少进步的空间,像这样的增强也帮助 ES6 变的比以往的 JavaScript 版本更优秀。(卧槽,这就忽然写结束语了?好 TM 突然!) -- EOF --

发表在 前端开发 | 标签为 , , | 留下评论

使用 Media Query 检测设备 Reduced Motion 设置

最近在看《Smooth Scrolling and Accessibility1 》这篇文章时,发现在 Safari 10.1 中增加了一个好玩的访问性检测——Reduced Motion2,因此可以通过特性检测区分并对一些配置较差或主动开启「减弱动态效果」的用户进行体验优化。 开启「减弱动态效果」 「减弱动态效果」设置无论在 MacOS 还是 iOS 里都隐藏的比较深: MacOS:进入「系统偏好设置」-「辅助功能」-「显示器」,开启「减弱动态效果」;3 iOS:进入「设置」-「通用」-「辅助功能」-「减弱动态效果」,开启选项。4 开启「减弱动态效果」可以有效地降低 MacOS/iOS 系统糟糕的晕眩效果性能开销,从而达到系统更流畅的功效。 特性检测 Reduced Motion 功能的检测关键词是 prefers-reduced-motion,使用 CSS Media Query 就可以针对开启「减弱动态效果」的用户进行页面性能优化: @keyframes ambient { // Keyframes for an ambient animation that is purely decorative. } .background { animation: ambient 10s infinite alternate; } @media (prefers-reduced-motion) { // Disable the non-essential animations. .background { animation: none; } } 使用 JavaScript 则是使用 matchMedia 检测,还能监听改变事件: var motionQuery = window.matchMedia('(prefers-reduced-motion)'); if (motionQuery.matches) { /* reduce motion */ } motionQuery.addListener( handleReduceMotionChanged ); 用 Safari 查看下面的演示,按照上面的切换方式来观察不同。 See the Pen Reduce Motion Media Query Example by Eric Bailey (@ericwbailey) on CodePen. 使用场景 因为这是 MacOS/iOS 独有的设置,所以目前也只有在 Safari 里可以一用。这个功能非常适合为低配置设备的用户以及追求性能的用户做体验优化,因为很多用户会开启「减弱动态效果」来在旧设备上提升系统流畅度。 比如我的博客背景有一个大的 Canvas,很多人反映说访问时风扇狂啸,那么就可以在检测到开启「减弱动态效果」时主动关闭一些无关紧要的动画从而提升用户的体验。 如果碰巧你用的不是 MacBook,那么你应该去买一个:-P -- EOF -- Smooth Scrolling and Accessibility ↩︎ Reduced Motion Media Query ↩︎ macOS Sierra: Reduce screen motion ↩︎ Reduce screen motion on your iPhone, iPad, or iPod touch ↩︎ Update 2019.04.25:自 Chrome 74 起,也支持该特性检测了。

发表在 前端开发 | 标签为 , , , | 2 条评论

使用 BEM 的几个注意事项

最近在做新的博客主题,又恰巧在整理 HTML 中为元素命名方面的心得,就借机重温了一下 BEM 文档。或许是太久没看官方文档,我发现 BEM 如今已经延伸到了 Web 开发实践的范畴,而不再是一个单纯的命名规范。好坏不谈,总结一下注意事项。 命名规则 过去的 BEM 语法冗长丑陋,期间也经历了几种方式(现在依然共存): /* 旧:破折号式 */ .block-name {} .block-name__element-name {} .block-name__element-name--modifier-name {} /* 旧:驼峰式 */ .blockName {} .blockName--modifierName {} .blockName__elementName--modifierName {} 而现在的命名规则主要是对修饰符的连接符做了调整——破折号改为单下划线链接: .block-name {} .block-name__element-name_modifier-name {} 如何使用块与元素 如果一个区域可以复用且不依赖其它组件,则可作为一个块(Block)。 如果一个区域不能拿到外部单独使用,那么就应该作为一个元素(Element)。 元素不能单独使用,只能作为块的一部分使用。元素不能包含元素,因为这样做会妨碍块内部元素位置的层级调整。 <!-- 错误范例 --> <form class="search-form"> <div class="search-form__content"> <!-- 应该使用: search-form__input 或 search-form__content-input --> <input class="search-form__content__input"> <!-- 应该使用:search-form__button 或 search-form__content-button --> <button class="search-form__content__button">搜索</button> </div> </form> 如果一个元素可以继续分解,则可使用「元素 + 块」混合的方式另起一个空间,下面会单独介绍。 修饰符的改进 修饰符(Modifier)用来修饰块或元素的外表、状态或行为。修饰符不能单独使用,而且必须绑定在对应的块或元素上,不能混搭。 <button class="button button_active">...</button> 现在除了布尔值修饰符,还可以使用 Key-value 形式。 一般来讲,如果修饰符的值可有可无(disabled、readonly 等,有则是 true,没有则是 false),那么可以省略修饰符的值。 如果修饰符的值可以有多种状态,则使用 Key-value 形式。 另外,因为修饰符的连接符从 -- 变成了 _,所以并不像过去那么丑陋了。 /* 使用布尔值表示状态(禁用、可见、聚焦等) */ .btn_disabled {} .header__search-form_focused {} /* 使用 Key-value 表示选项(尺寸、主题、类型等) */ .btn_size_s {} .search-form_theme_dark {} .menu__item_type_text {} 为什么修饰符一定要包含块名或元素名? 每一个块都会建立独立的命名空间,可以有效的减少命名冲突; 显式说明修饰符所对应的块或元素,防止混淆; 代码搜索更加准确方便; 不包含块名或元素名,使用修饰符就必须使用组合选择器(.btn.disabled),这会增加样式权重使其难以覆盖。 使用混合拆分样式 在 BEM 中,位置和布局样式通过父级块来进行设置。这就需要通过混合(Mix)组合块与元素,组合多个实体(块、元素、修饰符都被称作 BEM 实体)的表现与样式,同时不耦合代码。 <!-- header 块 --> <div class="header"> <!-- `search-form` 块混合 header 块的 `search-form` 元素 --> <div class="search-form header__search-form"></div> </div> 上面的例子通过混合的方式把位置样式从块中剥离,然后就可以在 .header__search-form {} 中设置表单的位置或浮动等样式,从而保持了 search-form 块的样式独立,对其完整样式代码进行了解耦。这并不陌生——在传统命名方式中,我们经常通过嵌套的方式(.header .search-form)对局部样式进行调整。但这样做会改变选择器的权重。在 BEM 的思想中,保持选择器扁平和低权重是一个准则。 因此,在使用 BEM 时需要格外注意遵循它的工作方式: 不在块里设置位置、布局相关的样式,只设置基本样式; 通过混合的方式,在作为父级块的元素时设置布局样式; 适时拆分元素为独立的块,解耦样式并形成新的命名空间。 避免组合使用标签与类选择器 在 CSS 中使用 tag 一直不是一个好的实践,但在有些时候却难以避免。唯一需要注意的是 a.btn 是无法被 .btn_active 覆盖的。因此组合使用标签与类选择器时要格外注意。当然,最好还是避免使用。 适时使用嵌套选择器 很多人说 BEM 是「禁止嵌套」的,这不完全准确。BEM 只是建议尽量保持嵌套层级越低越好。因为 CSS 的权重问题很多人处理不好,最终恶果就是不停的嵌套和为了增加权重而进行的无意义嵌套和 !important,这无疑增加了代码的耦合。 在你需要通过块状态对内部元素进行调整时,使用嵌套是很好的选择: .btn_active .btn__text {} .search-form_foucsed .search-form__input {} .nav_theme_dark .nav__item {} 块不一定是一个视觉上的区块 在批量设置多个样式时,可以使用混合的方式建立一个纯样式抽象的「块」。此时块不对应页面上具体的一块区域,而是代表一组抽象样式。 <article class="article text"></article> <footer class="footer"> <div class="copyright text"></div> </footer> 上面的例子把 .text 作为一个单独的文本样式块,用来声明特定的一种文字设置。 .text { font-family: Arial, sans-serif; font-size: 14px; color: #000; } 同理,页面整体布局、栅格系统等,都可以作为单独的块来设置。 开放/关闭原则 任何 HTML 元素都应遵循向修饰符开放并拒绝改变的原则。换句话说,就是一个 HTML 元素应该便于通过修饰符对齐进行样式覆盖,但是不应该频繁对其本身进行修改,因为每次改动都将影响到所有元素。 切换到 BEM 式 CSS 把 DOM 模型扔到一边,学习创造块。 不要使用 ID 选择器和标签选择器。 最小化选择器嵌套。 使用 class 命名约定来避免命名冲突,确保选择器名称具备自解释性。 用块、元素和修饰符的方式工作。 把可能会改变的 CSS 样式属性从块挪到修饰符里去。 使用混合。 把代码拆分成独立的部分从而更容易的使用单独的块。 重复使用块。 总结 使用 BEM 的好处有很多: 自解释性很强,看到即看懂。 强制 「块--元素_修饰符」结构,命名重复可能性大大降低,有效地防止了样式污染问题。 抽象核心样式,通过修饰符的方式减少代码复制。 提供良好的扩展性。 而且现在 BEM 除了针对 CSS 的方案,在 JavaScript、文件解构上也有了充分设计。按照官方的姿态,BEM 已经不应再作为 SMACSS 或 OOCSS 的类比,而是接近 Web Components 的产品,同时提供了完整的针对项目的构造方案。 我个人还是更喜欢把它当做一个单纯的 CSS 命名方案来看待,因为在组件化开发的方面,现在有很多更好的方案可供选择。另外 BEM 也不是万能灵药,它虽然解决了命名冲突、权重混乱等问题,但在模块组织上并不是特别清晰,借鉴一些 SMACSS 中的思想会让你的项目更加清晰有条理。 光说不练假把式,在接下来的新主题中就会用 BEM + SMACSS 来操练一番。 -- EOF --

发表在 前端开发 | 标签为 , , | 留下评论

[译] 6 种 JavaScript 展开操作符的绝妙使用

David Walsh 写的一篇关于展开操作符和剩余操作符的文章。 继续阅读

发表在 前端开发 | 标签为 , , | 留下评论

使用 .toLocaleString() 轻松实现多国语言价格数字格式化

最近在项目中遇到了多语言价格格式化的需求(即 $2399 => $2,399 的转换)。在过去做大陆站时显然是没有这种需求的,因为千位分隔符(group separator)是为了方便快速看懂大数字位数,根据英语的千位分位方式(千、百万、十亿、万亿)而设置的。中文虽然国标规定四位以内的整数可以不分节,但所有主流网站对更大的数字也都没有进行数字分节。因为千位分隔符对中国人来说本身就是没有卵用的东西,中文即便使用数字分位,也是万位分位方式(万、亿、兆)。 那么用代码对数字进行格式化,显然不是逢三位加逗号这么简单。比如印度在数字分位符号上的处理,就堪称业界奇葩: 印度的数字读法用“拉克”(十万)和“克若尔”(千万),数字标法用不对称的数位分离,即小数点左侧首先是三位分隔,然后继续向左都是两位分隔。如:三千万(3 克若尔)会写成 3,00,00,000。 —— 维基百科 简单的暴利处理无法满足多语言支持,此时使用 Number.prototype.toLocaleString() 进行数字格式化处理再好不过。 使用 .toLocaleString() 在 JavaScript 中,数字对象的 .toLocaleString() 方法如果不传参数,则采用宿主环境的系统语言进行分位处理。 var price = 1024; price.toLocaleString(); // => "1,024" 使用 locales 参数 在 ECMA-402 标准的实现中,增加了.toLocaleString() 方法对 locales 的支持,语法为 numObj.toLocaleString([locales [, options]]),locales 参数接收 BCP 47 语言标签格式的字符串或数组。 那么将数字强制转化为印度格式就变的简单: var price = 1669999; price.toLocaleString('en-IN'); // => "16,69,999" 这样就可以轻松处理多语言的自动格式化了,只要根据 <html lang="en-IN"> 中的 lang 属性动态读取就可以了。 var price = 1669999; var lang = document.querySelector('html').getAttribute('lang'); price.toLocaleString(lang); // 中文页面下 => "1,669,999" 使用 options 参数 如果仅仅是做到多语言自动格式化数字,显然还不够细腻。通过 .toLocaleString() 方法的 options 参数,可以做到转化至相应语言的货币格式。 在我的项目之前的实现中,多国语言的货币符号是通过模板渲染时读取配置文件完成转换的。如果使用.toLocaleString()  展示或加工展示所有货币数字,则无需这一步骤: var price = 2499; price.toLocaleString('en-IN', { style: 'currency', currency: 'INR' }); // => "₹ 2,499.00" 如果不想要显示末尾的小数「.00」,只要设置一下最小分位 minimumFractionDigits 即可(默认是 2): var price = 2499; price.toLocaleString('en-IN', { style: 'currency', currency: 'INR', minimumFractionDigits: 0 }); // => "₹ 2,499" 这样一个完美的价格格式化功能就完成了。options 对象参数接收一系列样式属性,常用的有: style:可选值为 decimal(小数)、currency(货币)或 percent(百分比); currency:设置为货币样式时使用的符号,支持列表在这里; useGrouping:布尔值,是否显示数字分位。 关于 locales 参数和 options 参数支持的其它属性,例如上面使用的 minimumFractionDigits,可以查阅 MDN,我刚把最新的英文版翻译了一遍。 兼容性 所有现代浏览器都支持 locales 参数,因此在移动端使用是安全无痛的。桌面端的支持则是 IE11 及以上。 另外,如果想在后端直接对不同页面直接输出对应的货币符或者做分位转换等操作,只要用 node.js 做一个转换就行了。 想到这里,我已经忍不住要萌萌哒了,去优化我们的工作流啦。JavaScript,FTW! 相关链接 MDN: Number.prototype.toLocaleString() MDN: Intl.NumberFormat 维基百科:小数点 为何数字分隔符三位一隔? -- EOF --

发表在 前端开发 | 标签为 , | 留下评论

[译] JavaScript 数组方法:变异 vs. 非变异

本文翻译自:JavaScript Array Methods: Mutating vs. Non-Mutating JavaScript 提供了许多方式去增加、删除和替换数组中的元素,有些会作用到原数组本身,有些则不是——它们会返回一个新数组。 接下来,我会分别列举如何使用变异或非变异方法来实现这三个操作。文章末尾还会展示如何通过非变异方法 array.map() 来遍历数组并转化其中的元素。 虽然在这我没有列举一个详尽的列表,但是下面基本包含了数组所有的基础操作方式。 注意:接下来的内容中,当需要使用非变异方法时,我会使用 const 来声明数组,否则会用 let。尽管你可以改变一个用 const 声明的数组而且也不会抛错,但我还是喜欢用 const 显式地告诉大家这个值不会改变。 警告:看这篇文章的时候,要特别留意它们的区别: array.splice() 会改变原始数组,而 array.slice() 则不会改变原始数组。 增加元素:变异方法 为数组增加元素的变异方法是 array.push() 和 array.unshift()。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingAdd = ['a', 'b', 'c', 'd', 'e']; mutatingAdd.push('f'); // ['a', 'b', 'c', 'd', 'e', 'f'] mutatingAdd.unshift('z'); // ['z', 'a', 'b', 'c', 'd', 'e'] 上面的代码: array.push() 增加一个元素到数组末尾 array.unshift() 增加一个元素到数组开头 增加元素:非变异方法 有两个办法可以在不改变原始数组的情况下增加元素。 第一个是 array.concat()。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.concat('f'); // ['a', 'b', 'c', 'd', 'e'. 'f'] console.log(arr1); // ['a', 'b', 'c', 'd', 'e'] 第二个方法需要借助 JavaScript 的展开运算符。展开运算符是数组前的三个点(...)。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = [...arr1, 'f']; // ['a', 'b', 'c', 'd', 'e', 'f'] const arr3 = ['z', ...arr1]; // ['z', 'a', 'b', 'c', 'd', 'e'] 向上面这样使用展开运算符时,将会从原数组中拷贝所有元素放到新的数组中。 在第 5 行,我们从 arr1 取得了所有元素的拷贝,然后放到了新数组中,最后把 'f' 放在末尾。 在第 6 行,过程与上面一样,只不过新元素 'z' 放在了数组中其它元素的前面。 删除元素:变异方法 为数组删除元素的变异方法是 array.pop() 和 array.shift()。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; mutatingRemove.pop(); // ['a', 'b', 'c', 'd'] mutatingRemove.shift(); // ['b', 'c', 'd'] 上面的代码: array.pop() 删除数组中的最末的元素 array.shift() 删除数组中开头的元素 array.pop() 和 array.shift() 方法都返回被删除的元素。所以你可以抓取删除的元素并存到一个变量上。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; const returnedValue1 = mutatingRemove.pop(); console.log(mutatingRemove); // ['a', 'b', 'c', 'd'] console.log(returnedValue1); // 'e' const returnedValue2 = mutatingRemove.shift(); console.log(mutatingRemove); // ['b', 'c', 'd'] console.log(returnedValue2); // 'a' 还可以用 array.splice() 来删除数组中的多个元素。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; mutatingRemove.splice(0, 2); // ['c', 'd', 'e'] 这里的 mutatingRemove.splice(0, 2) 使用了两个参数(也可以是多个参数,下面还会再提到它)。 第一个参数是 splice 的起始索引位置。 第二个参数是想要删除的数量。 在上面的例子里,从 mutatingRemove 数组中删除了两个(第二个参数)元素,删除的元素起始于索引 0(第一个参数)。 就像 array.pop() 和 array.shift() 一样,array.splice() 方法同样返回被删除的元素。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; let returnedItems = mutatingRemove.splice(0, 2); console.log(mutatingRemove); // ['c', 'd', 'e'] console.log(returnedItems) // ['a', 'b'] 删除元素:非变异方法 JavaScript 中的 array.filter() 方法会从原数组中创建一个新数组,但是这个新数组只包含符合特定要求的元素。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.filter(a => a !== 'e'); // ['a', 'b', 'd', 'f'] // OR const arr2 = arr1.filter(a => { return a !== 'e'; }); // ['a', 'b', 'd', 'f'] 上面的代码中,条件是「!== 'e'」,所以新数组(arr2)跟原始数组类似,只是仅包含符合「 !== 'e'」条件的元素。 *一些箭头函数的特性: 在单行箭头函数(第 5 行)中,「return」关键字是隐式存在的,所以不需要显式写出来。 但是,在多行箭头函数(第 7~9 行)中,你需要显式的返回一个值。 另一种删除数组元素的非变异方法是使用 array.slice()(不要跟 array.splice() 搞混了)。 array.slice() 接受两个参数。 第一个参数是开始拷贝的起始索引位置。 第二个参数是拷贝结束的索引位置。结束位置的元素并不会包含进去(前开后闭)。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.slice(1, 5) // ['b', 'c', 'd', 'e'] const arr3 = arr1.slice(2) // ['c', 'd', 'e'] 上面的第 4 行(const arr2 = arr1.slice(1, 5)),arr2 是由自 arr1 的索引 1 起,到 5 之前(例如索引 4)的元素拷贝而来。 第 5 行(const arr3 = arr1.slice(2))是一种常见的方式。如果使用 array.slice() 没有传入第二个参数,那么该方法会从传入的索引起一直拷贝到数组结束。 替换元素:变异方法 如果你知道要替换的元素索引,那么可以直接用 array.splice() 去替换。 所以,我们需要至少三个参数来完成它。 第一个参数是开始替换的索引位置。 第二个参数是想要删除的元素个数。 第三个之后的参数是想要插入到数组中的元素。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingReplace = ['a', 'b', 'c', 'd', 'e']; mutatingReplace.splice(2, 1, 30); // ['a', 'b', 30, 'd', 'e'] // OR mutatingReplace.splice(2, 1, 30, 31); // ['a', 'b', 30, 31, 'd', 'e'] 第 4 行(mutatingReplace.splice(2, 1, 30))将 'c' 替换为 30。 第 6 行(mutatingReplace.splice(2, 1, 30, 31))删除了 'c',然后又插入了 30 和 31 两个元素。 替换元素:非变异方法 我们可以使用 array.map() 来创建一个新数组,同时我们还能检查每一个元素或者按照特定要求来替换元素。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e'] const arr2 = arr1.map(item => { if(item === 'c') { item = 'CAT'; } return item; }); // ['a', 'b', 'CAT', 'd', 'e'] 上面的代码基于 arr1 创建了一个新数组,并把所有的 'c' 都替换成了 'CAT'。 通过 array.map() 转换数据 array.map()是一个强大的方法,可以在不影响原始数据的前提下做数据转换。 // since we will not be mutating, // use const const origArr = ['a', 'b', 'c', 'd', 'e']; const transformedArr = origArr.map(n => n + 'Hi!'); // ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!'] // OR const transformedArr = origArr.map(n => { return n * 2; })// ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!'] console.log(origArr); // ['a', 'b', 'c', 'd', 'e']; // orignal array is intact -- EOF --

发表在 前端开发 | 标签为 , , | 留下评论