深入理解JavaScript:Function模式(下)——初始化与性能优化

作者:霁月

时间:2026-10-29

浏览:660

本文深入解析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 = {};

总结

总结

无需过多总结,建议读者仔细研读代码细节。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章