javascript嵌套函数的效率问题
javascript自诞生以来就是一门受争议的编程语言,很多人也对javascript的语法表示不解,例如javascript嵌套函数。本文来自Nettuts+的一篇教程,详细的介绍了javascript中嵌套函数效率问题,从小处说起,一直说到匿名函数、继承,感觉不错。
嵌套函数效率
很多jser喜欢在javascript代码中使用嵌套函数,例如下面的例子就是一个典型的嵌套函数:
function foo(a, b) {
function bar() {
return a + b;
}
return bar();
}
foo(1, 2);上面的代码中foo()中嵌入了bar(),当foo()运行的时候,就会调用bar()。javascript引擎不会创建bar()函数,直到外部引用了foo(),随着foo()的运行结束,bar()也会销毁。
当多次运行foo的时候,javascript引擎就要在每次的运行foo时创建bar函数,而每次foo结束就要销毁bar函数,这是一个很费劲的工作。
那么为什么我们不把bar函数拿出来,做为一个独立的函数,它在foo外部只被创建一次,而不是多次,这样就大大的提高了代码效率。例如下面的代码:
function foo(a, b) {
return bar(a, b);
}
function bar(a, b) {
return a + b;
}
foo(1, 2);当然这样做可能随着程序的复杂性,可能存在命名冲突的危险,所以jser需要在这方面权衡,或者采用命名空间来解决这个方式。下面是在jsperf中做的关于上面两个函数大量运行的速度测试http://jsperf.com/nested-named-functions。不同的浏览器测试的结果不同,但是总体来看,两个独立的函数要比相互嵌套的javascript函数效率提高10%~90%。
匿名函数
javascript开发中常用到匿名函数,例如事件处理函数、callback函数等,例如下面的事件处理函数:
document.addEventListener("click", function(evt) {
alert("You clicked the page.");
});这里给document创建了一个事件监听,当每次页面点击之后会alert出来一条消息。跟嵌套函数一样,每次点击需要创建一次匿名函数,处理事件完成之后再销毁。
jQuery中的each方法也是一个匿名函数,例如下面的代码,选择出来所有的a元素,并且添加each方法来处理a元素:
$("a").each(function(index) {
this.style.color = "red";
});如果写成jQuery插件,可以下面的代码:
$.fn.myPlugin = function(options) {
return this.each(function() {
var $this = $(this);
function changeColor() {
$this.css({color : options.color});
}
changeColor();
});
};javascript代码定义了一个名字为myPlugin的jQuery插件,插件中有一个嵌套函数changeColor,根据上面说的,上面的代码效率不如独立出来changeColor高,所以我们可以把changeColor拿到外部来,即下面的代码:
function changeColor($obj, color) {
$obj.css({color : color});
}
$.fn.myPlugin = function(options) {
return this.each(function() {
var $this = $(this);
changeColor($this, options.color);
});
};经过修改过的jQuery插件在效率上提高了15%左右,大家可以通过jsperf来测试两个jQuery插件的效率。所以说嵌套的函数越多,调用的次数越多,则可以优化的地方也越多。
javascript嵌套函数和函数构造
我们在javascript类中长写下面的代码:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
};
}
var jeremy = new Person("Jeremy", "McPeak"),
jeffrey = new Person("Jeffrey", "Way");这段代码定义了一个Person的类,其中包括了getFullName的方法,将firstName和lastName返回。getFullName的方法在每次创建不同的Person对象时会不同,所以jeremy.getFullName === jeffrey.getFullName返回的结果是false(http://jsfiddle.net/k9uRN/).
具体分析见下面图,jeremy和jeffrey是不同的两个对象,他们的getFullName也是不同的。

jeremy和jeffrey
使用prototype关键字
在javascript中有prototype这个关键字,prototype的属性是实例化后的对象所共有的属性,所以上面的代码可以通过prototype改写成下面的方式:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
};
var jeremy = new Person("Jeremy", "McPeak"),
jeffrey = new Person("Jeffrey", "Way");这样getFullName的方法是定义在Person.prototype中的,为所有实例化的对象共有方法,所以jeremy和jeffrey的getFullName是相等的(http://jsfiddle.net/Pfkua/)。他们之间的关系可以通过下面的图片来解释:

jeremy和jeffrey共有getFullName
通过jsPerf的测试,我们可以看出来,第二种方法要比第一种方法在效率上面快了18%~96%。
变量的私有化
在函数内部的变量是私有的,外面是不可以访问到函数内部的变量的,但是函数内部可以访问到外部的变量。看下面的代码:
function Foo(paramOne) {
var thisIsPrivate = paramOne;
this.bar = function() {
return thisIsPrivate;
};
}
var foo = new Foo("Hello, Privacy!");
alert(foo.bar()); // alerts "Hello, Privacy!"代码中创建了一个构造函数Foo();,并且私有了一个变量thisIsPrivate,当运行bar()时,私有的thisIsPrivate会被返回。这样thisIsPrivate受到了保护,在Foo()之外是访问不到的.
这种方法也是很多javascript工程师所推荐的写法,但是跟上面的代码一样,每次实例化Foo();之时,会创建一个bar方法,这样看上去又是对资源的浪费,而且会影响效率。所以我们可以通过使用prototype的方法来实现:
function Foo(paramOne) {
this._thisIsPrivate = paramOne;
}
Foo.prototype.bar = function() {
return this._thisIsPrivate;
};
var foo = new Foo("Hello, Convention to Denote Privacy!");
alert(foo.bar()); // alerts "Hello, Convention to Denote Privacy!"这样的代码有不可以保证变量的私有化,只是我们在变量之前添加下划线_(很多公司内部规定,或者已经成为了很多程序员的编程习惯,_开头的变量是私有的),这样每次实例化Foo();会只建立一个通用的bar方法。
总结
本文也不是说不要大家在javascript中写嵌套函数,只是要适当,要注意这个知识点,在频繁调用的函数内部是不推荐写javascript嵌套函数的。开发者写代码给用户用,为的就是高效代码提高用户体验。
英文全文:http://net.tutsplus.com/tutorials/javascript-ajax/stop-nesting-functions-but-not-all-of-them
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:三水清 来源: 三水清
- 标签: 嵌套函数
- 发布时间:2011-11-21 00:07:40
-
[928] WordPress插件开发 -- 在插件使用 -
[134] 解决 nginx 反向代理网页首尾出现神秘字 -
[53] 整理了一份招PHP高级工程师的面试题 -
[52] 如何保证一个程序在单台服务器上只有唯一实例( -
[51] 海量小文件存储 -
[51] 用 Jquery 模拟 select -
[50] 全站换域名时利用nginx和javascri -
[50] Innodb分表太多或者表分区太多,会导致内 -
[49] CloudSMS:免费匿名的云短信 -
[47] jQuery性能优化指南