锋言锋语

NferZhuang的自留地

一道JS面试题-20180801

题目

let a = [
 { one: 1, two: 2 },
 { one: 3, two: 4 },
 { one: 5, two: 6 }
];

对数组a进行运算,要求得到结果:{ one: 9, two: 12 }

解答

最简单的思路,遍历数组并进行成员相加,代码如下:

let sum = { one: 0, two: 0 };
for(let i = 0; i < a.length; i++) {
    sum.one += a[i].one;
    sum.two += a[i].two;
}
console.log(sum);

迭代1

上面的代码中,通过索引i去查找元素不如直接遍历数组中的元素,即使用forEach替换for,代码修改如下:

let sum = { one: 0, two: 0 };
a.forEach(item => {
    sum.one += item.one;
    sum.two += item.two;
})
console.log(sum);

迭代2

上面的代码,运行时没有任何问题,但是考虑一下:如果成员属性多了一个怎么办,比如:{ one: 1, two: 2, three, 3 }?

因此,在代码中hardcodeonetwo是非常不好的习惯,代码修改如下:

let sum = {};
a.forEach(item => {
    Object.keys(item).forEach(key => {
        if (sum[key] === undefined) sum[key] = 0;
        sum[key] += item[key];
    });
})
console.log(sum);

迭代3

其实针对这种累加场景,ES5增加了reduce函数:

reduce() 方法对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值。

使用reduce函数重写:

let sum = a.reduce((pre, curr) => {
    Object.keys(curr).forEach(key => {
        if (pre[key] === undefined) pre[key] = 0;
        pre[key] = pre[key] + curr[key];
    });
    return pre;
}, {})
console.log(sum);

迭代4

使用三目运算符重写Object.keys(curr).forEach()中的代码:

let sum = a.reduce((pre, curr) => {
    Object.keys(curr).forEach(key => {
        pre[key] = pre[key] ? pre[key] + curr[key] : curr[key];
    });
    return pre;
}, {})
console.log(sum);

for VS forEach

for是js中的一个流程控制关键字,而forEach是数组对象的一个方法:

forEach 方法按升序为数组中含有效值的每一项执行一次callback 函数,那些已删除(使用delete方法等情况)或者未初始化的项将被跳过(例如在稀疏数组上)。callback 函数会被依次传入三个参数:当前项的值、当前项的索引和数组对象本身。

从MDN上的描述可以看到,使用forEach有以下几个优势:

  • 更有语义化
  • 在稀疏数组上效率更高
  • 更方便的得到当前项的值(for循环还需要通过[]运算符取值)
  • 减少不必要的变量声明,比如下述代码:
Object.keys(curr).forEach(key => {})

const keys = Object.keys(curr);
for (let i = 0; i < keys.length; i++) {
    // do something with keys[i]
}

undefined?

undefined是JavaScript内置类型之一,可以使用typeof来返回其类型的字符串值:

typeof undefined === 'undefined' // true
  • 对于一个未初始化的变量,其值为undefined
var a;
a === undefined // true
  • 使用一个不存在(未声明)的变量,会先抛出ReferenceError异常:
try {
    b === undefined
} catch(err) {
    console.log(err) // ReferenceError: b is not defined
}
  • 对不存在(未声明)的变量使用typeof来检查,却可以正常执行并返回undefined值:
typeof b === 'undefined' // true
  • 对于对象中不存在的属性,其值也为undefined:
var obj = {};
obj.a === undefined // true

总结

最终代码如下:

let a = [
 { one: 1, two: 2 },
 { one: 3, two: 4 },
 { one: 5, two: 6, three: 7 }
];

let sum = a.reduce((pre, curr) => {
    Object.keys(curr).forEach(key => {
        pre[key] = pre[key] ? pre[key] + curr[key] : curr[key];
    });
    return pre;
}, {})
console.log(sum);
文 / nfer
LEAVE A REPLY

loading