今天做了字节的一个笔试题,要求从url
中取出parmas
参数,将他们以键值对的形式存到对象中
还有一些额外的需求,具体的记不清了,只记得下面这些👇
- 当传递重复的
key
时,不额外往对象中加入新的键值对,而是把这个key
对应的val
转换为数组的形式来存储他的多个val
- 当
val
s 是基本数据类型时,要以对应的基本数据类型来存储
# 思路分析
既然是处理一个url
中的params
参数,那我们首先就要拿到params
参数
1️⃣ 可以用正则(但是不容易记),正则是最方便的,但是正则记起来也是真难啊😢
配合replace
使用就可以拿到params
参数,进一步往对象中存储了
let regx = /([^&?=]+)=([^&?=]+)/g;
url.replace(regx, (...args) => {});
2️⃣ 可以发现,正则也是找的?
,因为?
后面就是params
的内容,所以我们可以通过将?
作为一个分割线,把url
分成两部分,后面一部分就是我们要的结果
既然要分割,那就使用split()
👇
let params = str.split("?")[1];
let param = params.split("&");
/*
params: name=itclanCoder&study=css&study=js&study
=react&key=1
param: [ 'name=itclanCoder', 'study=css', 'study=
js', 'study=react', 'key=1' ]
*/
拿到params
参数之后,下一步就是往对象中存储它们了,这一步其实就不难了😄
let baseUrlStr =
"https://coder.itclan.cn?name=itclanCoder&study=css&study=js&study=react&key=1";
// 参数转成对象
function queryString(str) {
let params = str.split("?")[1]; //截取?号后的字符串即name=itclanCoder&study=css
let param = params.split("&"); // 通过&符号进行分割即["name=itclanCoder", "study=css"]
let obj = {}; // 用一个对象存储目标值
for (let i = 0; i < param.length; i++) {
// 循环遍历截取出来的param数组
let paramsA = param[i].split("="); // 通过split,=继续对数组params每一项进行分割,生成数组["name", "itclanCoder"]
let key = paramsA[0]; // 取数组项["name", "itclanCoder"]中第0位,即name
let value = paramsA[1]; // 取数组项["name", "itclanCoder"]中第1位,即itclanCoder
obj[key] = value;
}
return obj;
}
console.log("obj: ", queryString(baseUrlStr));
这时我们就可以写出来一个满足基本要求的方法了
# 💪 额外需求
1️⃣ 相同key
的处理,可以看到上面的例子中,study
是重复赋值的,但是我们一直在覆盖,所以obj
最后只有最后一次的数据
既然要用数组来处理重复数据,那其实就是在往obj
中放对象的时候加了一个判断,obj
是否已经该key
,如果有,再判断是否已经是数组了,如果是数组,就只需要push
当前val
即可,如果不是,就要把obj
里的该key
对应的val
转换成数组形式,然后再push
即可
let baseUrlStr =
"https://coder.itclan.cn?name=itclanCoder&study=css&study=js&study=react&key=1";
// 参数转成对象
function queryString(str) {
// 分割拿到params参数
let params = str.split("?")[1];
console.log("params: ", params);
let param = params.split("&");
console.log("param: ", param);
let obj = {};
for (let i = 0; i < param.length; i++) {
let paramsA = param[i].split("=");
let key = paramsA[0];
let value = paramsA[1];
if (obj[key]) {
// 主要是在这里做了一下处理,判断值是不是一个数组
// 是数组就保留数组,push新的值就可以
// 不是数组就把obj[key]转换为数组的形式 —— [obj[obj[key]]], 再push
obj[key] = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
obj[key].push(value);
} else {
obj[key] = value;
}
}
return obj;
}
console.log("obj: ", queryString(baseUrlStr));
可以看到,此时study
属性就以数组形式存储了
2️⃣ 基本数据类型
这里我的想法就比较简单了,对于Number
,我选择用正则来处理,我的正则比较菜,只会处理正整数(包括0
)的情况,不能处理浮点数
对于Boolean
型的数据,因为只有两种情况,所以我是直接来对比判断的👇
let value = paramsA[1];
let reg = /^\d+$/g;
if (reg.test(value)) {
value = parseInt(value);
}
if (value === "false" || value === "true") {
value = Boolean(value);
}
加了上边这些代码之后,就可以拿到 Number 和 Boolean 类型的数据了
对于undefined
和null
我也是直接判断的,如果大家有更好的方法可以在下面评论嗷~
# 最终版本
let baseUrlStr =
"https://coder.itclan.cn?name=itclanCoder&study=css&study=js&study=react&key=1&test=true";
// 参数转成对象
function queryString(str) {
// 分割拿到params参数
let params = str.split("?")[1];
console.log("params: ", params);
let param = params.split("&");
console.log("param: ", param);
let obj = {};
for (let i = 0; i < param.length; i++) {
let paramsA = param[i].split("=");
let key = paramsA[0];
let value = paramsA[1];
let reg = /^\d+$/g;
if (reg.test(value)) {
value = parseInt(value);
}
if (value === "false" || value === "true") {
value = Boolean(value);
}
if (value === "undefined") {
value = undefined;
}
if (value === "null") {
value = null;
}
if (obj[key]) {
// 主要是在这里做了一下处理,判断值是不是一个数组
// 是数组就保留数组,push新的值就可以
// 不是数组就把obj[key]转换为数组的形式 —— [obj[obj[key]]], 再push
obj[key] = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
obj[key].push(value);
} else {
obj[key] = value;
}
}
return obj;
}
console.log("obj: ", queryString(baseUrlStr));