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

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

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

  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 是基于作用域的, 是可预测的.(可参考与作用域相关的闭包、内存泄漏、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;
}
复制代码

创建包含N个空对象的数组相关推荐

  1. js 对象及空对象或数组及空数组的判断与比较

    工作中经常会使用到,这里记录一下 判断是不是对象: let obj = {}; Object.prototype.toString.call(obj) == "[object Object] ...

  2. NumPy — 创建全零、全1、空、arange 数组,array 对象类型,astype 转换数据类型,数组和标量以及数组之间的运算,NumPy 数组共享内存

    NumPy 简介 一个用 python 实现的科学计算包.包括: 1.一个强大的 N 维数组对象 Array : 2.比较成熟的(广播)函数库: 3.用于整合 C/C++ 和 Fortran 代码的工 ...

  3. 如何检查数组是否包含JavaScript中的对象?

    In this article, we will look at various methods to check if an array includes an object in JavaScri ...

  4. JavaScript判断对象是否为空对象或空数组

    1. 判断一个变量是对象还是数组 首先判断一个变量是对象还是数组,不能使用typeof来判断,因为不管是对象还是数组,使用typeof得到的都是"object". 可以使用Obje ...

  5. JavaScript数组对象教程–如何使用JS数组方法创建,更新和遍历对象

    On average I work with JSON data 18 times a week. And I still need to google for specific ways to ma ...

  6. 常用创建空对象创建对象方法var obj = {};其他几种方法你知道吗

    (1)var obj = {}; //创建空对象 (2)var obj = Object.create(null); obj.toString //undefined var obj = Object ...

  7. js中判断空数组和空对象的方法

    复习的时候做一些学习的笔记总结. javascript的值的类型: 原始值:number.string.boolean.undefined.null.symbol(ES6).bigint(ES10) ...

  8. “空对象 {}” 与 “空数组 []” 的相加问题(详解)

    本文旨在让读者能更加清晰地了解 "空对象 {}" 与 "空数组 ()" 相加(eg:"[] + []" ."[] + {}&quo ...

  9. js 判断是否为空对象,或者空数组

    以下例子考虑这个变量为undefine和null的情况. 空对象: if(obj && Object.keys(obj).length>0){ console.log('空对象' ...

最新文章

  1. HDU 4418 高斯消元法求概率DP
  2. PyQt5显示一个空白的窗口
  3. 16.Hadoop架构再探讨第2部分
  4. Qt QWidget实现手势缩放和平移(一)
  5. 使用vue-amap
  6. 关于HTTPS的七个误解
  7. spring mvc学习(10):eclipse的环境前maven配置
  8. 宜信开源|微服务任务调度平台SIA-TASK入手实践
  9. 如何把握好 transition 和 animation 的时序,创作描边按钮特效...
  10. 最新cs1.6服务器ip地址,CS1.6 IP地址大全(死亡奔跑等)
  11. 浅谈个人对项目管理的理解
  12. 有关人工智能方面的调研报告
  13. 自适应布局-使用css3函数clac()
  14. 免费版网络验证系统的全自动发卡功能
  15. 计算机桌面基本设置操作包括哪些,电脑技巧入门操作有哪些
  16. 【EXCEL VBA】字符函数
  17. Java-多线程讲解(2)
  18. python爬取豆瓣电影信息_Python爬虫入门 | 爬取豆瓣电影信息
  19. 解决JS中出现的兼容性问题
  20. eclipse 32位换成64位 maven tomcat svn 集成

热门文章

  1. 王者荣耀英雄铭文及出装
  2. 使用java通过固定的excel模板自动生成数据库表的ddl建表语句
  3. 基于云开发的答题活动小程序v2.0-用云开发的聚合能力实现从题库中随机出题功能
  4. win10屏幕快照快捷键_如何在Windows 8和10中更改默认屏幕快照文件夹的位置
  5. LeetCode刻意练习25--买卖股票的最佳时机
  6. 工具:PsTools-windows问题定位系列小工具
  7. Python处理重复、缺失值
  8. rocketmq 实战问题汇总
  9. Qt4.8类继承关系图(全网最全)
  10. 信息检索与分析 - 课程总结