JavaScript中奇妙的replace

1、发现问题:

今天在读require.js源代码时,不经意读到这么一段代码:

//If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies.
if (!deps && isFunction(callback)) {
    deps = [];
    //Remove comments from the callback string,
    //look for require calls, and pull them into the dependencies,
    //but only if there are function args.
    if (callback.length) {
        callback
            .toString()
            .replace(commentRegExp, '')
            .replace(cjsRequireRegExp, function (match, dep) {
                deps.push(dep);
            });

        //May be a CommonJS thing even without require calls, but still
        //could use exports, and module. Avoid doing exports and module
        //work though if it just needs require.
        //REQUIRES the function to expect the CommonJS variables in the
        //order listed below.
        deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
    }
}

同样,在sea.js,也读到类似的代码段:

function parseDependencies(code) {
  var ret = []

  code.replace(SLASH_RE, "")
      .replace(REQUIRE_RE, function(m, m1, m2) {
        if (m2) {
          ret.push(m2)
        }
      })

  return ret
}

或许你没曾读过这两个文件,但是这不是我提及问题的重点(如果读者对此感兴趣,可以自己到github上去找源码研究),仔细看两个代码段中,都有使用到我们今天的主角——replace

看replace传入的第一个参数,恩,是我想象的东西——一个正则表达式,但是到我读到第二个参数时,我凌乱了,尽然传入的是一个函数!确实,虽然我以前知道第二个参数可以传入函数,但是奇怪的是,它为什么没有返还值呢?

2、关于replace:

在w3cschool中有这么一段定义:

语法

stringObject.replace(regexp/substr,replacement)
参数 描述
regexp/substr

必需。规定子字符串或要替换的模式的 RegExp 对象。

请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp 对象。

replacement 必需。一个字符串值。规定了替换文本或生成替换文本的函数。

 

很多和我一样的菜鸟大概会被这个描述所蒙蔽,其实当第二个参数传入函数时,我们不仅可以通过函数来动态生成并返还成要替换的文本,此刻的函数中的arguments对象会保存一些很重要的数据,举个小小的例子:

//定义一个检测“=数字”正则表达式和一个测试字符串
var reg = /\=(\d)/g,
    testStr = 'a=1,b=2,c=3,d=3';
//调用testStr的replace函数
testStr.replace(reg, function () {
    //打印arguments对象的详细信息
    console.log(arguments);
});

 

在谷歌控制台下,可以看到如下的测试结果:

JavaScript中奇妙的replace
这个函数被执行了4次,每次执行都代表正则表达成功匹配到了字符子串,那么对应的每次执行的arguments对象里面又存的什么信息呢?

在这里,我们可以看到:

参数1——表示当前匹配到的结果;

参数2——表示匹配到的正则表达式的“组”(也就是当前正则表达式小括号里面内容——这里指“\d”);

参数3——表示匹配到的字符串的索引位置;

参数4——不用多说,就是源字符串自己。

其实,通过网上的搜索,最终可以找到replace最官方、最标准的用法,当然,通过一些资料的查询,这里传入函数的arguments对象,是一个“动态可伸缩的”的,因为我们所使用的正则表达式里面含有多个组,而这里仅仅只有一个组,所以我们“当且仅当”可以看到第二个参数。

那么,我们把正则表达式换成这样又如何呢?

//定义一个检测“=数字”正则表达式和一个测试字符串
var reg = /\=\d/g,
    testStr = 'a=1,b=2,c=3,d=3';
//调用testStr的replace函数
testStr.replace(reg, function () {
    //打印arguments对象的详细信息
    console.log(arguments);
});

显然,如你所愿了:

JavaScript中奇妙的replace

 

3、运用场景:

利用正则表达式的组定义,可以方便地利用这个特性,快速地找到你想要的信息,这是解决js正则表达式不支持“零宽断言”的一个巧妙的方法,正如我给大家举的例子,我们大多时候在验证的时候,想匹配到“=”后面的数字,而不是“=”+[数字]。

回归我们文章开头的代码,了解过AMD编程的童鞋大概都知道CommonJs编程范式,require.js和sea.js在找寻一个模块的工厂函数内的依赖模块id时,将工厂函数转换成了string,并且替换掉注释之后,利用我们今天说所的这个特性,把工厂函数里面的类似require('xxx/xxx')的代码侦测出来,提取出模块id——‘xxx/xxx’,并且存到数组中,最终来形成这个模块依赖其他模块的id集合。(如果不知所云,请点击这里吧https://github.com/amdjs/amdjs-api/wiki/AMD

 

今天来刚到ITEye安家,希望今后能学习更多的web知识,也希望交到更多的喜欢前端的朋友!

你可能感兴趣的:(JavaScript,正则表达式,web前端)