JavaScript高级特性:惰性载入、柯里化与正则表达式详解
本文深入解析JavaScript中的高级编程技巧。首先介绍惰性载入函数以优化AJAX请求性能,避免重复判断;接着讲解函数柯里化与级联调用的实现原理及链式调用应用。最后详细阐述正则表达式的创建方式、常用方法(test、exec、match、replace、split)及元字符处理,帮助开发者掌握JS核心高级特性。
JavaScript类模拟与基础
JavaScript语言本身并不包含传统的class概念,但我们可以通过function构造函数来模拟实现类的行为。
惰性载入函数优化
惰性载入函数
例如,我们通常使用以下JavaScript代码来创建AJAX请求对象:
function createXHR () {
var xhr = null;
try{
xhr = new XMLHttpRequest(); // FF、Opera、Safari、IE7
} catch(e) {
handlerError(e);
try{
xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try{
xhr = ActiveXObject('Microsoft.XMLHTTP');
} catch(e) {
xhr = null;
}
}
}
return xhr;
}
function handlerError (err) {
var errXHR = err;
// ...
}
在现代Web开发中,AJAX技术已非常普及,一个网页往往包含大量的AJAX请求。如果每次请求都重新创建XHR对象,会导致频繁的内存分配与释放,进而引发内存泄露问题。我们可以采用惰性载入函数的技术来动态生成并复用XHR对象,从而优化性能。
/* 惰性函数(第二次生效) */
function createXHR () {
var xhr = null;
if (typeof XMLHttpRequest != 'undefined') {
xhr = new XMLHttpRequest();
createXHR = function () {
return new XMLHttpRequest();
}
} else {
try{
xhr = new ActiveXObject('Msxml2.XMLHTTP');
createXHR = function () {
return new ActiveXObject('Msxml2.XMLHTTP');
}
} catch (e){
try{
xhr = new ActiveXObject('Microsoft.XMLHTTP');
createXHR = function () {
return new ActiveXObject('Microsoft.XMLHTTP');
}
} catch (e){
createXHR = function () {
return null;
}
}
}
}
return xhr;
}
通过调用上述方法创建XHR对象后,在第二次及后续调用时,函数将直接返回已创建的XHR实例,无需再次进行兼容性判断,从而提升执行效率。
函数柯里化与级联调用
函数柯里化
函数柯里化(Currying)是一种将接受多个参数的函数转换为接受单一参数(最初函数的第一个参数)的函数,并返回接受余下参数且返回结果的新函数的技术。简而言之,它实现了多个函数参数的合并与逐步求值。例如:
function curry(fn) {
var args = Array.prototype.slice.call(arguments,1); // 取curry的参数并将其变为数组[100]
console.log(args); // [100]
return function () {
var innerArgs = Array.prototype.slice.call(arguments); // 匿名函数的参数列表[1,2]
console.log(innerArgs); // [1,2]
var finalArgs = args.concat(innerArgs); // 合并数组(参数合并)
console.log(finalArgs); // [100,1,2]
return fn.apply(null, finalArgs);
}
}
function add(num1,num2,num3) {
return num1 + num2 + num3;
}
var t = curry(add,100)(1,2);
console.info(t);

级联函数
级联(Chaining)是指一个对象将其所有相关操作连接在一起。如下面的对象示例所示:
// 人:手、腿、嘴
function classPerson(){
this.hand = "";
this.foot = "";
this.leg = "";
}
classPerson.prototype = {
setHand:function(){
this.hand = '大手';
},
setLeg:function () {
this.leg = '长腿欧巴';
},
setMouse:function () {
this.mouse = '樱桃小嘴';
}
}
var person = new classPerson();
person.setHand();
person.setMouse();
person.setLeg();
console.log(person);

我们知道,构建一个完整的人体是一个整体过程(不可能先造手、再造腿、最后造嘴)。现在我们的需求是:一旦实例化“人”这个对象,其所有属性与方法应当一次性就绪。
对上述代码进行简单修改:
function classPerson(){
this.hand = "";
this.foot = "";
this.leg = "";
}
classPerson.prototype = {
setHand:function(){
this.hand = '大手';
return this;
},
setLeg:function () {
this.leg = '长腿欧巴';
return this;
},
setMouse:function () {
this.mouse = '樱桃小嘴';
return this;
}
}
var person = new classPerson();
person.setHand().setMouse().setLeg(); // 调用函数
console.log(person);
我们在每个setter方法中添加了return this,将原有对象返回(避免无返回值的函数执行完后返回undefined)。我们可以惊奇地发现,常用的jQuery链式调用本质上就是一种级联调用:
$(‘#id').show().hide().show().hide().show().hide();
正则表达式详解
JavaScript中的正则表达式
一般来说,//在JavaScript中表示单行注释。但是,一旦我们在斜杠中间加入了内容,例如:/TEST/,它就神奇地变成了正则表达式字面量。
模式串的声明
var patt1 = new RegExp('hello'); // 方式一
var patt2 = /word/; // 方式二
test方法
在获取模式串(正则对象)后,可以调用该方法来匹配字符串,并返回指定值(true或false)。
var patt = /my/;
var str = 'this is my code...';
console.log(patt.test(str)); // true
exec方法
该方法类似于字符串的match方法,但当模式串指定为全局匹配(global)时,两者的表现不同。如果没有匹配到结果,则返回null。
/hello/.exec('oh hello world'); // ["hello"]
以上两个方法都是字符串对象本身的方法,下面的几个方法是字符串对象中有关正则表达式的高级方法。
match方法
用于模式匹配。函数原型是str.match(pattern),将匹配的结果以数组形式返回。
console.log('test 123'.match(/test/g)); // [test]
replace方法
用于字符串替换。注意:该方法会生成一个新的临时字符串副本,原字符串不变。如图所示:

split方法
将字符串按照指定模式拆分成数组。
console.log('Hello world,hello everyone'.split(/\s+/)); // ["Hello", "world,hello", "everyone"]
console.log('Hello world,hello everyone'.split(' ')); // 等效于上面的方法
正则的类型
/pattern/attributes
attributes是可选字符串,常用的属性包括“g”(全局匹配)、“i”(大小写不敏感)和“m”(多行匹配)。
console.log('Hello world,hello everyone'.match(/hEllO/gi)); // 全局查找hello并忽略大小写 ["Hello", "hello"]
在实际开发中,我们可以借助在线正则调试工具来调试我们的正则表达式,这些工具内置了大量常用的正则表达式。如果我们在开发中无法分析出别人编写的正则表达式的含义,可以借助正则分析网站,它们将以有限自动机图解的方式显示匹配过程。

正则中的元字符
正则表达式中的元字符必须进行转义处理:
( [ { ^ $ | ) ? * + .]}
需要注意的是,正则表达式有2种创建形式:字符串字面量和new RegExp()的方式。由于RegExp的构造函数是字符串,所以某些情况下需要进行双重转义。

__PROTO__
原型继承与访问器属性
__proto__使得继承变得更加容易:
function Super(){};
function Sub(){};
Sub.prototype.__proto__ = Super.prototype;
这是一个非常有用的特性,可以免去如下的工作:
借助中间构造器
无需引入第三方模块来进行基于原型继承的声明。
访问器
可以调用方法来定义属性,如其名有:__defineGetter__、__defineSetter__。例如为Date对象定义一个ago的属性,返回以自然语言描述的日期间隔(例如:某件事发生在3秒之前)。例如:
Date.prototype.__defineGetter__('ago',function(){
var diff = ((Date.now() - this.getTime()) / 1000)
day_diff = Math.floor(diff / 86400)
return day_diff == 0 && (diff < 60 && 'just now' )
|| diff < 120 && '1 minute ago'
|| diff < 3600 && Math.floor(diff / 60) + 'minutes ago'
|| diff < 7200 && '1 hour ago'
|| diff < 86400 && Math.floor(diff / 3600) + 'hours ago'
|| day_diff == 1 && 'Yesterday'
|| diff < 7 && day_diff + ' days ago'
|| Math.ceil(day_diff / 7) + ' weeks ago'
})
var d = new Date('12/12/1990')
console.log(d.ago)
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
