深入理解JavaScript:Function模式(下)——初始化与性能优化
本文深入解析JavaScript中的Function模式,重点介绍初始化与性能优化两大场景。涵盖立即执行函数(IIFE)的多种写法、对象初始化模式,以及通过分支初始化解决浏览器兼容性问题。此外,详细阐述了利用函数属性实现内存优化的缓存策略,包括处理原型链冲突和使用arguments.callee的技巧。
引言
介绍
本篇我们将探讨几种被称为初始化模式和性能模式的JavaScript技巧,主要应用于对象初始化和提升运行性能。部分模式在前文已有所提及,此处旨在进行系统性总结。
立即执行的函数
立即执行的函数
在系列第4篇《立即调用的函数表达式》中,我们已对类似概念做过详尽阐述。此处仅通过两个简洁示例进行回顾与总结。
代码如下:
// 声明完函数以后,立即执行该函数
(function () {
console.log('watch out!');
} ());
//这种方式声明的函数,也可以立即执行
!function () {
console.log('watch out!');
} ();
// 如下方式也都可以哦
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();立即执行的对象初始化
该模式的核心在于:在声明一个对象(而非普通函数)时,立即执行其内部某个方法以完成初始化工作。此模式通常适用于只需执行一次的操作场景。
代码如下:
({
// 这里你可以定义常量,设置其它值
maxwidth: 600,
maxheight: 400,
// 当然也可以定义utility方法
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// 初始化
init: function () {
console.log(this.gimmeMax());
// 更多代码...
}
}).init(); // 这样就开始初始化咯
分支初始化
分支初始化
分支初始化是指在初始化阶段,根据特定的条件或场景执行不同的代码逻辑,即通过条件语句进行赋值。在早期的事件处理开发中,我们常使用如下代码结构:
代码如下:
var utils = {
addListener: function (el, type, fn) {
if (typeof window.addEventListener === 'function') {
el.addEventListener(type, fn, false);
} else if (typeof document.attachEvent !== 'undefined') {
el.attachEvent('on' + type, fn);
} else {
el['on' + type] = fn;
}
},
removeListener: function (el, type, fn) {
}
};
我们来改进这一实现。首先定义两个接口:一个用于添加事件句柄,另一个用于移除事件句柄。代码结构如下:
代码如下:
var utils = {
addListener: null,
removeListener: null
};实现代码如下:
代码如下:
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else if (typeof document.attachEvent !== 'undefined') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else { // 其它旧浏览器
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}这种写法不仅使用便捷,代码结构也更为优雅。
自声明函数
自声明函数
该模式通常涉及在函数内部重新定义同名函数,例如:
代码如下:
var scareMe = function () {
alert("Boo!");
scareMe = function () {
alert("Double boo!");
};
};此类代码容易引发混淆,我们先观察示例的执行结果:
代码如下:
// 1. 添加新属性
scareMe.property = "properly";
// 2. scareMe赋与一个新值
var prank = scareMe;
// 3. 作为一个方法调用
var spooky = {
boo: scareMe
};
// 使用新变量名称进行调用
prank(); // "Boo!"
prank(); // "Boo!"
console.log(prank.property); // "properly"
// 使用方法进行调用
spooky.boo(); // "Boo!"
spooky.boo(); // "Boo!"
console.log(spooky.boo.property); // "properly"从执行结果可见,若将函数赋值给新变量或作为对象方法调用,代码并不会执行重载后的scareMe逻辑;而直接调用原函数则相反:
代码如下:
// 使用自声明函数
scareMe(); // Double boo!
scareMe(); // Double boo!
console.log(scareMe.property); // undefined使用此模式时需格外谨慎,因为实际行为可能与预期不符。当然,你也可以利用这一特性实现某些特殊操作。
内存优化
内存优化
该模式主要利用函数的属性特性来避免重复计算。其典型代码形式如下:
代码如下:
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... 复杂操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存储
myFunc.cache = {};然而,上述代码存在一个潜在问题:若传入的参数名为toString或其他Object原型上的公共方法名,将会导致错误。此时需引入hasOwnProperty方法进行判断,代码如下:
代码如下:
var myFunc = function (param) {
if (!myFunc.cache.hasOwnProperty(param)) {
var result = {};
// ... 复杂操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存储
myFunc.cache = {};若传入参数为多个,可通过JSON.stringify方法将参数数组序列化为一个cachekey值进行存储,代码如下:
代码如下:
var myFunc = function () {
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
result;
if (!myFunc.cache[cachekey]) {
result = {};
// ... 复杂操作 ...
myFunc.cache[cachekey] = result;
}
return myFunc.cache[cachekey];
};
// cache 存储
myFunc.cache = {};对于多参数情况,也可利用arguments.callee特性来实现:
代码如下:
var myFunc = function (param) {
var f = arguments.callee,
result;
if (!f.cache[param]) {
result = {};
// ... 复杂操作 ...
f.cache[param] = result;
}
return f.cache[param];
};
// cache 存储
myFunc.cache = {};
总结
总结
无需过多总结,建议读者仔细研读代码细节。
tween.js 内存泄漏预防:怎么正确停止动画与清理对象
2026-11-05 15:52:56
Vue或React项目中为何不建议直接使用JS刷新页面
2026-11-05 13:57:30
哪里可以找到高质量的免费JS脚本资源?
2026-11-05 13:15:03
JS数组对象怎么根据指定ID字段去重
2026-11-04 21:41:10
JS数组去重方法性能对比:Set、Map与Filter谁更快
2026-11-04 16:14:15
