关于js中字符串replace方法的第二参数为function时,参数的顺序问题分析

最近在研究NODEjs,在看leo老师的教程的时候看到这种js的高级用法,相信很多人也和我又同感,这种用法中,调用函数的参数顺序和正则表达式中分组圆括号的顺序有何种联系呢?下面我们一起探究一下。
先看一个简单的例子:

var reg = /\/((\d+)(\w+))/g;     //匹配斜杠后面跟随多个数字和单词的情况
var s = '/23w';
s = s.replace(reg,function(){
  for(var i=0;i<arguments.length;i++){
     console.log('(arg' + i + ')' + arguments[i]);
  }
  return 'x';
});
console.log(s);
运行结果:
D:\nodejs>node reg.js
(arg0)/23w
(arg1)23w
(arg2)23
(arg3)w
(arg4)0
(arg5)/23w
x
当正则表达式增加一个'|'匹配时,比如:
var reg = /\/((\d+)(\w+))|\/(\w+)/g;
此时运行的结果为:
D:\nodejs>node reg.js
(arg0)/23w
(arg1)23w
(arg2)23
(arg3)w
(arg4)undefined
(arg5)0
(arg6)/23w
x
关于参数的顺序问题:
从以上测试的结果可以看到:
arg0:整个匹配的结果,这里是\/((\d+)(\w+))|\/(\w+)
arg1:最外层括号的匹配结果,这里是23w,也就是((\d+)(\w+))的匹配结果
arg2:内层匹配结果中从左至右第一个匹配结果,这里是23,也就是(\d+)的匹配结果
arg3:内层匹配结果中从左至右第二个匹配结果,这里是w,也就是(\w+)的匹配结果
arg4:加入'|'匹配后面的括号也要作为参数,这里是(\w+),但没有匹配,所以为undefined
arg5:目标字符串和正则表达式中第一次匹配的索引,这里是0
arg6:目标字符串

再来看一个复杂的例子:(这个例子是leo老师教程中的例子,leo老师看到了别生气大笑
// 函数的功能是将一个形如"/article/:id/*/:name"的目标字符串中的":xxx"和"*"替换为“(.*)”
function pathRegexp (routeStr){
     routeStr = routeStr.replace(/\?(.*)$/,'')
                        .replace(/((\*{1}(?=\/))|(\*{1}(?=$)))/g,"(.*)")
                        .replace(/((:(.*?(?=\/)))|(:(.*(?=$))))/g,function(){
                        
                          for(var i=0;i<arguments.length;i++){
                             console.log('(arg' + i + ')' + arguments[i]);
                          }
                        
                          return '(.*)';
                        })
                        .replace(/\//g,'\\\/');
     var reg = new RegExp(routeStr + '$');
     return reg;

 var path_regexp = pathRegexp("/article/:id/*/:name");
 console.log("path_regexp:" + path_regexp);


运行结果为:
D:\nodejs>node reg.js
(arg0):id
(arg1):id
(arg2):id
(arg3)id
(arg4)undefined
(arg5)undefined
(arg6)9
(arg7)/article/:id/(.*)/:name
(arg0):name
(arg1):name
(arg2)undefined
(arg3)undefined
(arg4):name
(arg5)name
(arg6)18
(arg7)/article/:id/(.*)/:name
path_regexp:/\/article\/(.*)\/(.*)\/(.*)$/
前三个参数都是一样的,按照上面的分析,我们可以分析如下:
arg0:整个匹配的结果
arg1:((:(.*?(?=\/)))|(:(.*(?=$)))匹配的结果,:id
arg2:(:(.*?(?=\/)))匹配的结果,:id
arg3:(.*?(?=\/))匹配的结果,id
arg4:(:(.*(?=$))的结果,undefined
arg5:(.*(?=$)的匹配结果,undefined
arg6:第一个':'出现的位置,9
arg7:整个目标字符串

第二轮:name的匹配读者自己去分析。

leo老师的网站:http://jsera.net/book/gyTCIRi5zx可以去看看哈



### URLSearchParams `get` 方法返回 `null` 的原因分析 当使用 JavaScript 中的 `URLSearchParams` 对象,如果调用其 `get` 方法返回 `null`,通常是因为以下几个原因之一: 1. **参数名不存在于查询字符串中** 如果指定的键(key)未存在于当前的查询字符串中,则 `get` 方法会返回 `null`。这表明该键尚未被添加到 `URLSearchParams` 实例中[^2]。 2. **初始化数据为空或格式错误** 当创建 `URLSearchParams` 对象,如果传递的初始值为空或者不符合预期格式(如空字符串、非法字符),则可能导致无法正确解析参数,从而使得后续调用 `get` 方法失败并返回 `null`[^2]。 3. **多次重复操作覆盖原有值** 使用 `set` 或者重新赋值的方式可能会意外替换掉之前的某个特定键对应的值,进而影响之后通过 `get` 获取的结果为 `null`。 --- ### 解决方案 #### 方案一:确认参数已正确定义 在向 `URLSearchParams` 添加新参数之前,请确保这些参数确实存在且有效。可以通过显式的条件判断来验证这一点: ```javascript const params = new URLSearchParams(); if (someCondition && someValue !== undefined) { params.append("paramName", someValue); } console.log(params.get("paramName")); // 应该不会得到 null ``` #### 方案二:检查初始化输入的有效性 对于从外部来源接收的数据,在将其作为 `URLSearchParams` 构造函数的一部分前先做适当清理和校验工作非常重要。例如处理可能包含多余空白或其他干扰项的情况: ```javascript let queryString = " key=value "; // 注意前后有空格 queryString = queryString.trim(); // 移除首尾多余的空格 const safeParams = new URLSearchParams(queryString.replace(/\s+/g, '')); // 进一步移除内部所有空格 console.log(safeParams.get("key")); // 正确输出 value 而非 null ``` #### 方案三:避免不必要的重写行为 谨慎管理对同一个键的操作顺序以防无意间抹去已有记录。比如下面的例子展示了如何安全更新而不是完全替代现有条目: ```javascript const existingParams = new URLSearchParams("foo=bar"); existingParams.set("baz", "qux"); // 新增一项而非修改 foo console.assert(existingParams.get("foo") === "bar", "`foo` should still be present."); ``` #### 方案四:调试工具辅助排查问题根源 利用现代浏览器开发者控制台中的网络面板(Network Tab),观察实际发出请求所携带的具体 query string 是否符合预期;另外也可以借助 console 日志打印中间状态便于定位具体环节出了差错的地方。 --- ### 示例代码片段展示正确做法 以下是综合考虑以上几点的一个完整例子演示如何构建以及读取 URL 查询参数而不出错的情形: ```javascript function createSafeUrlQuery(baseUri, queryParamsObj){ let searchParams = new URLSearchParams(); Object.entries(queryParamsObj).forEach(([key,value])=>{ if(value != null && typeof value !=='undefined'){ searchParams.append(key,String(value)); } }); return `${baseUri}?${searchParams.toString()}` } // Usage Example: try{ const urlWithQueries = createSafeUrlQuery("/example-endpoint",{id:"123",name:"",status:null}); console.log(urlWithQueries); // 输出 "/example-endpoint?id=123" }catch(err){ console.error(`Error creating URL: ${err.message}`); } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值