题目描述
获取 url 中的参数
1.指定参数名称,返回该参数的值 或者 空字符串
2.不指定参数名称,返回全部的参数对象 或者 {}
3.如果存在多个同名参数,则返回数组
示例1
输入
http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key
输出
[1, 2, 3]
解法1:
function getUrlParam(sUrl, sKey) {
var str = sUrl.split('?')[1].split('#')[0].split('&')
var obj = {};
str.forEach(item => {
var [key, value] = item.split('=');
if(obj[key] === void 0){
obj[key] = value;
} else {
obj[key] = [].concat(obj[key], value);
}
});
return sKey === void 0?null:obj[sKey]||null;
}
var sUrl = "http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe";
sKey = "key";
console.log(getUrlParam(sUrl, sKey));
思路:
逐段分割,首先利用?去除前面的协议和域名部分,然后在利用#去除锚部分,剩下的就是需要进行分析的参数部分,本题的核心思想是建立对象,以参数名作为属性,以参数值作为值;得到了锚部分之后,利用=分割为要获取的参数名和参数值,如果是首次获取到该参数名,则直接将对应的参数值赋予,否则进行加入该值;这里一个冷知识,concat合并两个数组,但是这里的obj[key]在首次加入之后却只是一个string类型的值,因此直接使用该方法会得到连接的字符串,所以可以使用上面的方法,每次都建立一个新的数组,然后存入上个版本的obj[key]和vlaue,再与空数组连接,得到一个新数组,最后进行一部判断,sKey是否为空,obj是否为空,虽然输出的是一个存放字符(串)的数组,但是在可以A,我修改了下用Number进行转化,结果超时,这是很让人有疑惑的地方。
解法2:
function getUrlParam(sUrl, sKey) {
var result, sParam = {};
sUrl.replace(/(\?|&)(\w+)=(\w+)/g, function(k0, k3, k1, k2){
console.log(k0, k1, k2, k3);
sParam[k1] === void 0 ? sParam[k1] = k2 : sParam[k1] = [].concat(sParam[k1], k2);
});
console.log(sUrl);
sKey === void 0 || sKey === '' ? result = sParam : result = sParam[sKey] || '';
return result;
}
var sUrl = "http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe";
sKey = "key";
console.log(getUrlParam(sUrl, sKey));
思路:正则表示,再利用replace第二个参数子表达式的语法;首先看正则,第一个是匹配一个?或者&,对应参数部分的每一个参数,然后是参数名任意字符、数字和下划线,再匹配等号,最后匹配参数值,要求和参数名相同,注意需要全局匹配;关于replace第二个参数的说明,W3school给出了解释:
ECMAScript v3 规定,replace() 方法的参数 replacement,可以是函数而不是字符串。在这种情况下,每个匹配都调用该函数,它返回的字符串将作为替换文本使用。该函数的第一个参数是匹配模式的字符串。接下来的参数是与模式中的子表达式匹配的字符串,可以有0 个或多个这样的参数。接下来的参数是一个整数,声明了匹配在 stringObject 中出现的位置。最后一个参数是stringObject 本身。
也就是说,在函数中k0,k1,k2, k3分别代表原字符串,(?|&),(\w+),(\w+),正则表达式是通过()来划分子表达式的,但是这里并未用到(?|&),因此可以列举出来作为之后子表达式的引用,之后的思路与解法一相同。
超时的一发:
var sUrl = “http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe”;
sKey = “key”;
function getUrlParam(sUrl, sKey) {
var arr = [];
while(sUrl.indexOf(sKey) !== -1){
var start = sUrl.indexOf(sKey)+sKey.length+1;
var end = sUrl.indexOf(’&’);
// console.log("strat = ", start);
// console.log("end = ", end);
var str = sUrl.substring(start, end);
//console.log("str = ", str);
arr.push(Number(str));
sUrl = sUrl.slice(sUrl.indexOf(’&’)+1);
//console.log(sUrl);
}
return arr;
}
console.log(getUrlParam(sUrl, sKey));
这里就不做代码引用来误导了,虽然结果相同,但是判定超时,感觉用substring来截取要更好耗时一些,JS的引擎是C++来实现的,底层的算法可能是O(n)的时间复杂度,所以相对于split来说,还是更倾向于前者。