博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
创建包含N个空对象的数组
阅读量:6618 次
发布时间:2019-06-25

本文共 4808 字,大约阅读时间需要 16 分钟。

在给对象设置属性时, 如果对象不存在很容易报错.

有些场景, 在对对象数组处理时, 设置对象属性前判断对象是否存在. 与其这样, 还不如直接初始化为空对象数组.

本文主要涉及到一些容易忽略的知识点:

  1. Array.prototype.fill() 的使用.
  2. 简单类型和复杂类型赋值/复制、传参的区别.
  3. 空单元数组的弊端.
  4. 箭头函数中的 returnthis.
  5. Function.prototype.apply() 的非常规使用.

9个考生就来了6个


考试时, 每个考生都有自己位置. 考生对照着可以很容易在考场里找到自己的座位.秉着公平、公正、公开的原则, 考生被稀疏地散布在考场的各个角落.复制代码

假设考场 3 ✖️3 排列, 考生的信息:

[{
"row":1,"col":1,"name":"Ada"}, {
"row":3,"col":3,"name":"Aaron"}, {
"row":1,"col":2,"name":"Aditi"}, {
"row":3,"col":2,"name":"Aditi"}, {
"row":1,"col":3,"name":"Aditi"}, {
"row":3,"col":1,"name":"Abbott"}]复制代码

将考场位置做成一个表格, 对考生位置按排统计, 来标注考生出勤情况.

[{
"row":1,"col_1":"Ada","col_2":"Aditi","col_3":"Aditi"}, {}, {
"row":3,"col_3":"Aaron","col_2":"Aditi","col_1":"Abbott"}]复制代码

(为嘛没有第二排? 自知考不过, 缺考了呗?) 开发中, 对原始数据进行处理是一件很平常的事. so, 这个数据的处理应该很简单...吧?

Array(3).fill({}) 试一波


如何初始化空对象数组?

原始数据是以学生个体的信息存储展示的, 现在则按排为单位对数据进行处理. 理所当然的会想到先初始化三个空对象数组.

let studentRow = Array(3).fill({})// > studentRow// [ {}, {}, {} ]复制代码

动作很快姿势很帅. 不过, 这样真的可以么? 长得倒是像那么一回事, 可实际上完全行不通. Array.prototype.fill() 的用法是, 指定某个值来填充数组.

也就是说, {} 在 studentRow 里复制了三次. 如果是简单类型值倒也罢了, 但是换做复杂类型值, 修改每一个 {} , 都会影响其它的 {}. 因为它们都是对同一个对象的引用.

let studentRow = Array(3).fill({});studentRow[0].name = 'tony';// > studentRow// [ { name: 'tony' },//   { name: 'tony' },//   { name: 'tony' } ]// 等同于let obj = {};let studentRow = Array(3).fill(obj);// > studentRow// {obj, obj, obj}studentRow[0].name = 'tony';// > studentRow// [ { name: 'tony' },//   { name: 'tony' },//   { name: 'tony' } ]复制代码

知识点:

  • 将一个值赋予变量时, 解析器必须确定这个值是基本类型值还是复杂类型值.
  • 当是复杂类型值时, 变量里保存的是该复杂类型值在堆中的一个指针. 复制的是变量的指针, 操作的却是实际的对象.

Array(3)map(() => {}) 结合有问题


Array(3).fill({}) 行不通. 那么, Array(3).map(() => {})?

如果说 Array(3).fill({}) 不可行, 是因为三个空对象是对同一个对象的引用. 那么我们就设法返回三个不同的空对象.

let studentRow = Array(3).map(() => {});// > studentRow// [ <3 empty items> ]复制代码

结果很失望, 这个表达式就干了两件事, Array(3)map(() => {}). 所以问题很好排查.

let arr = Array(3);// > arr// [ <3 empty items> ]复制代码

对于数组中并不存在的单元, map() 也是束手无策.

我说: 肚里要有货?

肚里没货, 我们就造一些. Array.prototype.fill() 又有出头之日了.

let studentRow = Array(3).fill(undefined);// > studentRow// [ undefined, undefined, undefined ]复制代码

警告:

  • 如若一个数组没有任何单元, 但它的 length 属性中却显示有单元数量, 这样奇特的数据结构会导致一些怪异的行为. 我们将包含至少一个 “空单元” 的数组称之为 “稀疏数组”. undefined 单元非 “空单元”.

  • 永远不要创建和使用空单元数组.

箭头函数中的 return


你以为 Array(3).fill(undefined).map(() => {}) 就完事了? 图样图森破 ?

let studentRow = Array(3).fill(undefined).map(() => {});// > studentRow// [ undefined, undefined, undefined ]复制代码

哦, 我知道了, 你没有 return 啊

额, 这和 return 没有关系. 不信你可以加一个试试? 其实, {} 在这里被视作语法块了, 没有任何意义. 可恨就可恨在, 它和空对象长得一摸一样. 既然这样, 那我们就不用字面量定义一个空对象了.

let studentRow = Array(3).fill(undefined).map(() => Object.create(null));studentRow[0].name = 'tony';// > studentRow// [ { name: 'tony' }, {}, {} ]复制代码

这样就达到初始化对象数组的目的了. 可是, Array(3).fill(undefined).map(() => {}) 为什么行不通, 如何补救?

规避问题在某种意义上不等于解决问题.

{...} 里面的代码会被解析为一系列语句. {} 也因此不能达到我们预期的结果. 所以, 我们可以用 (...){} 包装成表达式, 即 ({}).

let studentRow = Array(3).fill(undefined).map(() => ({}));studentRow[0].name = 'tony';// > studentRow// [ { name: 'tony' }, {}, {} ]复制代码

知识点:

  • 若函数体的表达式个数多于一个, 或者函数题包含非表达式语句的时候才需要用 {...} 包裹.

  • 如果只有一个表达式, 并且省略了 {...} 的话, 则附加一个隐式 return. 若在块体内需要指定返回值, 则需要明确的 return.

  • 箭头函数提供了简练的语法, 但不是普通函数的替代品. 箭头函数的主要设计目的是改变 this 的行为. 普通函数内的 this 是动态绑定, this 指向谁取决于调用者. 而箭头函数里的 this 是基于作用域的, 是可预测的.(可参考).

令人绝望的Array.prototype.fill()


你以为结束了, 其实才刚刚开始

这是真正的开始, 没看错, 是的, 我们之前所做的可能都是无用功.

是的, IE 是魔鬼. 费尽了周折, 才发现一切都是徒劳. 难道就这么放弃了?

'放弃'能吃么? 能吃就吃了它, 啥? 不能吃?!? 提它作甚!!!

Array.prototype.fill() 方便之处就是能够简便填充数组. 此法不行, 另寻他法.

Function.prototype.apply() 了解一下


Function.prototype.apply() 入参有两个. 第一个参数是 函数方法 的调用者, 第二个参数是 函数方法 的入参(要区分入参和入参的不同). 函数方法 的入参可以是数组也可以是类数组. 我们的目的就是填充数组, 所以我们要在类数组上做文章. 就拿 console.log 做例子?. (直接复制我之前的博客内容?).

function log_1(arg) {console.log(arg)}log_1(1);log_1(1,2,3);// 1// 1// 改造下function log_2() {    const log = console.log;    log.apply(null, arguments)}log_2(1);log_2(1, 2, 3)// 1// 1 2 3复制代码

这是 Function.prototype.apply() 使用的方法. 如果我们把 log_2 里的 arguments 换成 {length: 3}

function log_2() {    const log = console.log;    log.apply(null, {
length: 3})}log_2()// undefined undefined undefined复制代码

{length: 3}[undefined, undefined, undefined] 在传入 apply(null;...) 后, 在参数的处理上, 最后的结果是一样的. 那么, Array(3).fill(undefined).map(() => ({})) 可改造成

let studentRow = Array.apply(null, {
length: 3}).map(() => ({}));studentRow[0].name = 'tony';// > studentRow// [ { name: 'tony' }, {}, {} ]复制代码

在这里 Array 作为普通函数调用, 以上等同于

let studentRow = Array(undefined, undefined, undefined);// > studentRow// [ undefined, undefined, undefined ]复制代码

收尾


只是初始化一个空对象数组, 结果整出这么多幺蛾子. 处理数据其实就那么几行代码. 大致长这模样

function handleData(params) {    const studentRow = Array.apply(null, {
length: 3}).map(() => ({})); params.forEach(item => { studentRow[item.row-1][`row`] = item.row; studentRow[item.row-1][`col_${item.col}`] = item.name; }) return studentRow;}复制代码

转载地址:http://csupo.baihongyu.com/

你可能感兴趣的文章
Android:percent 布局
查看>>
数据库主键
查看>>
Examples For PLSQL Cursors - Explicit, Implicit And Ref Cursors
查看>>
javaweb学习总结(三十八)——事务
查看>>
史上最全的Unity面试题(持续更新总结。。。。。。) 包含答案的Unity面试题...
查看>>
Android -- 仿淘宝广告条滚动
查看>>
swift 数据存储
查看>>
使用apidoc 生成Restful web Api文档——新手问题与解决方法
查看>>
写一本书和找一本书
查看>>
hdu1010 Tempter of the Bone(DFS+剪枝)
查看>>
SSH——增删改的实现一
查看>>
js这些代码你都不会,你还有什么好说的!!!
查看>>
Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
查看>>
第6章7节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-注入按键事件实例...
查看>>
用mount挂载远程服务器网络硬盘
查看>>
Qt的Script、Quick、QML的关系与总结
查看>>
vue 路由demo
查看>>
Nexus设备升级5.0方法
查看>>
最简单 NDK 样例
查看>>
No.4 PyQt学习(页面跳转)
查看>>