js多层对象数组合并_JS⾯试之数组对象解构
数组解构:
将 destructuringArray([1, [2, 3], 4], “[a, [b], c]”) => {a: 1, b: 2, c: 4}
// 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}
const targetArray = [1, [2, 3], 4];
const formater = "[a, [b], c]";
const destructuringArray = (values, keys) => {
try {
const obj = {};
if (typeof keys === 'string') {
keys = JSON.place(/\w+/g, '"$&"'));
}
const iterate = (values, keys) =>
keys.forEach((key, i) => {
if(Array.isArray(key)) iterate(values[i], key)
else obj[key] = values[i]
})
iterate(values, keys)
return obj;
} catch (e) {
<(e.message);
}
}
对象解构
实现⼀个get函数,使得下⾯的调⽤可以输出正确的结果
const obj = { selector: { to: { toutiao: "FE Coder"} }, target: [1, 2, { name: 'byted'}]};
get(obj, 'utiao', 'target[0]', 'target[2].name');
// [ 'FE Coder', 1, 'byted']
乍眼⼀看,这不就是实现⼀个⽅法吗?看上去好像很简单。所以我就开始写了第⼀个版本。思想其实很简单,遍历传进来的参数,使⽤split将每⼀个参数分隔开,然后遍历取值,最终返回结果。
function get(data, ...args) {
return args.map((item) => {
const paths = item.split('.');
let res = data;
paths.map(path => res = res[path]);
return res;
})
}
const obj = {
selector: {typeof array
to: {
toutiao: "FE Coder"
}
},
target: [1, 2, {
name: 'byted'
}]
};
function get(obj, ...list) {
return list.map((item) => {
return item.split(".").reduce((a = {}, b) => {
if(/\[([0-9])\]/g.test(b)){
var c=/(\w+)\[([0-9])\]/g.exec(b)
return a[c[1]]&&a[c[1]][c[2]]
}
return a[b]
}, obj)
})
}
get(obj, 'utiao', 'target[0]', 'target[2].name','zhangsan.lisi[3].name')
console.log(get(obj, 'utiao', 'target[0]', 'target[2].name','zhangsan.lisi[3].name'));
⼀运⾏,果不其然,报错了。 后来仔细看了⼀下提供的测试代码,发现居然有target[0]这种东西。。居然还带了个数组索引。 冷静分析⼀下,对于后⾯带了个索引的类型,⽐如'target[0]',我们肯定是要特殊对待的。所以,我们⾸先得先识别到这种特殊的类型,然后再对它进⾏额外处理。
这个时候,很快的就可以想到使⽤正则表达式来做这个事情。为什么呢?因为像这种带有索引的类型,他们都有⼀个特⾊,就是有固定的格式:[num],那么我们只需要能构造出可以匹配这种固定格式的正则,就可以解决这个问题。
对于这种格式,不难想到可以⽤这个正则表达式来做判断:/[[0-9]+]/gi,可是我们还需要将匹配值取出来。这个时候查了下正则表达式的⽂档(⽂档点击这⾥),发现有⼀个match⽅法,可以返回匹配成功的结果。那么就让我们来做个测试:
const reg = /\[[0-9]+\]/gi;
const str = "target[123123]";
const str1 = "target[]"
if (st(str)) {
console.log('test success');
}
if (!st(str1)) {
console.log('test fail');
}
const matchResult = str.match(reg);
console.log(matchResult); // ["[123123]"]
诶,我们现在已经到了解决这种问题的⽅法,那让我们赶紧来继续改进下代码。
function get(data, ...args) {
const reg = /\[[0-9]+\]/gi;
return args.map((item) => {
const paths = item.split('.');
let res = data;
paths.map((path) => {
if (st(path)) {
const match = path.match(reg)[0];
/
/ 将target[0]⾥的target储存到cmd⾥
const cmd = place(match, '');
// 获取数组索引
const arrIndex = place(/[\[\]]/gi, '');
res = res[cmd][arrIndex];
} else {
res = res[path];
}
});
return res;
});
}
const obj = { selector: { to: { toutiao: "FE Coder"} }, target: [1, 2, { name: 'byted'}]};
console.log(get(obj, 'utiao', 'target[0]', 'target[2].name'));
写完赶紧运⾏⼀下,完美,输出了正确的结果了。那么到这⾥就结束了?
改进
可是总感觉有点不妥,感觉事情没有那么简单。⼀般来说,⾯试题除了考验你解决问题的能⼒之外,可能还考验着你思考问题的全⾯性、严谨性。像上⾯那种写法, 如果⽤户传⼊了⼀个不存在的path链或者⼀些其他特殊情况,就可能导致整个程序crash掉。想下调⽤⽅式, 即使你传⼊了错误的path,他也可以帮你做处理,并且返回⼀个undefined。因此,我们还需要完善这个⽅法。
function get(data, ...args) {
const reg = /\[[0-9]+\]/gi;
return args.map((item) => {
const paths = item.split('.');
let res = data;
paths.map(path => {
try {
if (st(path)) {
const match = path.match(reg)[0];
const cmd = place(match, '');
const arrIndex = place(/[\[\]]/gi, '');
res = res[cmd][arrIndex];
} else {
res = res[path];
}
} catch (err) {
<(err);
res = undefined;
}
});
return res;
});
}
在这⾥,我们对每⼀个path的处理进⾏了try catch处理。若出错了,则返回undefined。哇,这样看起来就⽐较稳了。
再⽐如说,Function.prototype.bind⽅法⾥(我写了个类似的bind⽅法:仓库),也使⽤了Function来解决⼀些问题(fn.length丢失问题)。说明这个东西还是挺有⽤的,得学习了解⼀波,说不定哪天就⽤到了。
更新
function get(data, ...args) {
return args.map((item) => {
let res = data;
item
.replace(/\[/g, ".")
.replace(/\]/g, "")
.split('.')
.map(path => res = res && res[path]);
return res;
})
}
⽽且这两种⽅式的好处在于,它也可以处理多维数组的情况。
总结
学习完之后,最重要就是要总结,只有总结下来了,知识才是你⾃⼰的。那么我来总结下⽂章想表达的内容:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论