炫意html5
最早CSS3和HTML5移动技术网站之一

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%左右。所以说嵌套的函数越多,调用的次数越多,则可以优化的地方也越多。

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

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

jeremy和jeffrey共有getFullName

 

    通过测试,我们可以看出来,第二种方法要比第一种方法在效率上面快了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

炫意HTML5 » javascript嵌套函数的效率问题

(adsbygoogle = window.adsbygoogle || []).push({});
分享到:更多 ()

CSS3教程HTML5教程