JavaScript中with语句的替代方案及String正则方法详解

作者:半夏时间:2026-10-21 18:53:02浏览:332

本文探讨JavaScript中with语句的性能瓶颈及严格模式下的禁用问题,并提供基于正则替换的模拟实现方案。同时详细解析String原型上的split、match、search等正则相关方法的参数行为、捕获组影响及返回值差异,帮助开发者规避常见陷阱并提升代码质量。

with 语法及其替代方案

with 语法

在代码中,需要执行一个特定的函数逻辑。


 function computeExpression(exp, scope) {
 try {
  with (scope) {
   return eval(exp);
  }
 } catch (e) {
  console.error('ERROR', e);
 }
}

该函数要求在指定的 scope 作用域内执行,这具体意味着什么?

例如:


scope = {a:10,b:5};
exp = a*b;

假设要求计算结果为 15,在常规情况下,通常需要借助 with 语法来实现这一目标。

然而:

JavaScript 解释器在运行 with 块时,需要检查其中的变量是否属于 with 包含的对象。这一过程会显著降低 with 语句的执行速度,并导致 JavaScript 代码难以被引擎优化。

此外,在严格模式(strict mode)中,with 语法是被明确禁用的。

由于我使用 ES6 语法编写该库,且默认启用了严格模式,因此无法直接使用 with。为了解决这一问题,我自行模拟了一个与 with 等效的语法实现。

首先查看相关代码实现。


function replaceWith(scopeName, exp) {
 exp = " " + exp.trim();
 let quickRegex = /([\s\+\-\*\/%&\|\^!\*~]\s*?)([a-zA-Z_$][a-zA-Z_$0-9]*?)/g;
 exp = exp.replace(quickRegex, (a, b, c) => {
  return b + scopeName + '.' + c;
 });
 return exp;
}

代码首先去除表达式首尾的空格,为了与后续处理逻辑保持一致,在字符串开头显式添加一个空格。

接着使用正则表达式匹配类似 "t.e==0 ? f : d" 形式的表达式,从中提取变量名作为 c,将运算符符号提取为 b。

进行初步测试。

with 语法及其替代方案

此时已能返回处理后的表达式,进一步改造代码,使表达式直接在内部执行。


function replaceWith(scope, exp) {
 exp = " " + exp.trim();
 let quickRegex = /([\s\+\-\*\/%&\|\^!\*~]\s*?)([a-zA-Z_$][a-zA-Z_$0-9]*?)/g;
 exp = exp.replace(quickRegex, (a, b, c) => {
  return b + 'scope.' + c;
 });
 let func = new Function("scope", "return " + exp);
 return func(scope);
}

再次进行测试验证。

with 语法及其替代方案

至此功能实现。

中间的正则表达式编写可能不够完善,存在其他不严密之处,欢迎读者补充指正。

String 原型上的正则方法

String 原型上的正则方法

许久未编写大量代码,看到 Sring.prototype.split(//); 这个正则表达式时,发现分割符号也被添加到了返回数组中,对此感到惊讶。随后查阅 MDN 文档学习,并在此做整理补充。

String.prototype.split(separator,[limit])

separator:指定用来分割字符串的字符(串)。separator 可以是字符串或正则表达式。如果忽略 separator,则返回包含整个字符串的数组。如果 separator 是一个空字符串,则 str 会被转换为由原字符串中每个字符组成的数组。

limit:一个整数,用于限定返回的分割片段数量。split 方法仍然会分割每一个匹配的 separator,但返回的数组只会截取最多 limit 个元素。

当找到 separator 时,separator 会从字符串中被移除,子字符串存入返回的数组中。如果忽略 separator 参数,返回的数组仅包含一个元素,即原字符串。若 separator 为空字符串,str 将被转换为由字符组成的数组。

注意:

Note: 当字符串为空时,split 返回一个包含一个空字符串的数组,而不是一个空数组。

如果 separator 是一个正则表达式,且包含捕获括号(capturing parentheses),则每次匹配到 separator 时,捕获括号匹配的结果将会插入到返回的数组中。


var myString = "hello world";
var splits = myString.split(();

console.log(splits);

输出示例:

["hello world"]


var myString = "Hello 1 word. Sentence number 2.";
var splits = myString.split(/(\d)/);

console.log(splits);

输出示例:

Hello ,1, word. Sentence number ,2,.

String.prototype.replace()

此方法在前文已有所涉及,此处不再赘述。

String.prototype.match(Regex)

当字符串匹配到正则表达式(regular expression)时,match() 方法会提取匹配项。

如果正则表达式没有 g 标志,返回结果与 RegExp.exec(str) 相同。此外,返回的数组拥有一个额外的 input 属性,包含原始字符串。另外,还拥有一个 index 属性,表示匹配结果在原字符串中的索引(从 0 开始)。


"1aef2af3ef4 5".match(/[a-z]*(\d)/)

输出示例:

["1", "1"]

如果正则表达式包含 g 标志,则该方法返回一个包含所有匹配结果的数组。如果没有匹配到,则返回 null。

注意,如果添加 g 标志,则分组信息将不再保留在返回数组中。


"1aef2af3ef4 5".match(/[a-z]*(\d)/g)

输出示例:

["1", "aef2", "af3", "ef4", "5"]

String.prototype.search(Regex)

search() 方法执行查找操作,检查字符串对象是否与一个正则表达式匹配。

如果匹配成功,则 search() 返回正则表达式在字符串中首次匹配项的索引。否则,返回 -1。

其行为类似于正则表达式的 test 方法。


"aeg56".search(/[a-z]\d+/)

输出示例:

2

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

作者最新文章