一道面试题引发的思考

起因

今天跟一位程序员朋友日常聊天,聊到了一道面试题:

请用JS实现一个函数InsertItemToArray,
函数接受三个参数:要插入元素的数组、要插入的新元素、新元素所在的位置(arr, item, index),
往原数组arr的index位置插入一个新的元素item,index之后的元素索引依次后移,并返回插入新元素后的新数组。

要求:不允许用splice,slice。

这道题读完题目后,惯性思路就是写一个for循环,比如:

const InsetItemToArray = (arr, item, index) => {
  const resultArr = [];
  for(let i = 0; i < arr.length + 1; i++){
    if (i < index){
      resultArr.push(arr[i]);
    } else if (i > index) {
      resultArr.push(arr[i - 1]);
    } else {
      resultArr[i] = item;
    }
  }
  return resultArr;
}

InsetItemToArray([1,2,3], 'a', 1);

// [1, 'a', 2, 3]

或者换个思路:

const InsetItemToArray = (arr, item, index) => {
  const resultArr = [...arr];
  for(let i = arr.length; i > index; i--){
    resultArr[i] = arr[i - 1];
  }
  resultArr[index] = item;
  return resultArr;
}

InsetItemToArray([1,2,3], 'b', 1);

// [1, 'b', 2, 3]

以上都是比较常用且不用花太多思考时间的写法。

转折

这时候突然觉得,这道题其实可以用解构赋值的模式匹配来实现。

我们知道,es6的解构赋值是可以这样写的:

const arr = [1, 2, 3, 4, 5];
const [ , ,...resultArr] = arr;

// resultArr =>  [3, 4, 5]

那我们可以把返回结果看成是两个部分:

  • 第一部分是headArr,包含原数组arr中索引值小于index的元素和即将插入的新元素item
  • 第二部分是footArr,包含原数组arr中索引值大于或等于index的元素

最后将两个部分拼在一起,即是要返回的新数组了。

我们先来看怎么得到footArr

// 错误示例
const GetFootArr = (arr, item, index) => {
    const placeArr = new Array(index);
    const [...placeArr, ...footArr] = arr;
    return footArr;
}
// 控制台抛出一个错误:Uncaught SyntaxError: Rest element must be last element

奇怪了,让我们对比一下结果:

// 正常解构
const arr = [1, 2, 3, 4, 5];
const [ , ,...resultArr] = arr;

// resultArr =>  [3, 4, 5]


// 报错
const arr = [1, 2, 3, 4, 5];
const placeArr = new Array(2);
const [...placeArr, ...resultArr] = arr;

// Uncaught SyntaxError: Rest element must be last element

这时候打印placeArr

console.log(placeArr);
// [empty × 2]

打印[...palceArr]

console.log([...placeArr]);
// [undefined, undefined]

我们发现原本用来占位的empty都变成了undefined

结论

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。

就像刚才打印placeArr得到的结果都是empty一样。

但是要注意:

空位并不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false

上面代码说明,第一个数组的 0 号位置是有值的,第二个数组的 0 号位置没有值。

扩展运算符(...)是会将空位转为undefined。

[...['a',,'b']]
// [ "a", undefined, "b" ]

除了扩展运算符,entries()keys()values()find()findIndex()都会将空位处理成undefined

// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]

// keys()
[...[,'a'].keys()] // [0,1]

// values()
[...[,'a'].values()] // [undefined,"a"]

// find()
[,'a'].find(x => true) // undefined

// findIndex()
[,'a'].findIndex(x => true) // 0

而数组解构赋值的模式匹配,并不能匹配undefined作为变量名。所以placeArr就不能被正常的赋值。

关于数组空位的解释,可以参考阮一峰老师的ECMAScript 6 入门 - 数组的扩展
这里不做多的引申。

PS

既然解构赋值的思路行不通,但是我们仍旧可以按照headArrfootArr的思路来解这道题,只需换一种写法。

比如:

const InsetItemToArray = (arr, item, index) => {
  const headArr = arr.filter((_, i) => i < index);
  const footArr = arr.filter((_, i) => i >= index);
  return [ ...headArr, item, ...footArr];
}

InsetItemToArray([1,2,3], 'c', 2);

// [1, 2, 'c', 3]

这样一来我们就得到了正确的结果了。

完。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 转自:产品经理从0到1 之前面了几家公司,感受到了不同产品总监迥异的面试风格,有聊实的,有聊虚的,有单聊业务的,也...
    萌丸1014阅读 404评论 0 3
  • 搜狐面试题:有12个球,外形都一样,其中有一个质量和其他的不一样,给你一架天平,请问最少称几次可以把那个不同的球找...
    junhey阅读 541评论 0 0
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,145评论 0 13
  • 在送南瓜去托班前一周的某个晚上,我很焦虑,非常焦虑,焦虑的睡不着觉。 南瓜两岁零九个月,一直是姥姥和奶奶轮流带。今...
    个人成长教练周育楠阅读 388评论 1 3
  • 把一棵黄金的银杏 劈成一扇门 把路的终点与蝴蝶相连 拾起洞穴的壁画 放入你胳膊 在火的背面 雕刻你的脸 于大雪中 ...
    我是不是蝎大人阅读 206评论 0 0