Javascript 自动执行函数(当即调用函数)

开头:各类缘由总结一下javascript中的自动执行函数(当即调用函数)的一些方法,正文以下javascript

    在Javascript中,任何function在执行的时候都会建立一个执行上下文,由于function声明变量和function有可能只在该function内部,这个上下文,在调用function的时候,提供一些简单的方式来建立自由变量或私有子function。html

eg:java

// 因为该function里返回了另一个function,其中这个function能够访问自由变量i
// 全部说,这个内部的function其实是有权限能够调用内部的对象。
function makeCounter() {
// 只能在makeCounter内部访问i
 var i = 0;
return function () {
console.log(++i);
};
}
// 注意,counter和counter2是不一样的实例,分别有本身范围内的i。
var counter = makeCounter();
counter(); // logs: 1
counter(); // logs: 2
var counter2 = makeCounter();
counter2(); // logs: 1
counter2(); // logs: 2
alert(i); // 引用错误:i没有defind(由于i是存在于makeCounter内部)。

正文核心
一、Javascript方法: 
       在声明相似function foo(){}或var foo = function(){}函数的时候,经过在后面加个括弧就能够实现自执行,例如foo(),看代码: 
// 由于想下面第一个声明的function能够在后面加一个括弧()就能够本身执行了,好比foo(),
// 由于foo仅仅是function() { /* code */ }这个表达式的一个引用
var foo = function(){ /* code */ }
// ...是否是意味着后面加个括弧均可以自动执行?
function(){ /* code */ }(); // SyntaxError: Unexpected token (
        上述代码,若是甚至运行,第2个代码会出错,由于在解析器解析全局的function或者function内部function关键字的时候,默认是认为function声明,而不是function表达式,若是你不显示告诉编译器,它默认会声明成一个缺乏名字的function,而且抛出一个语法错误信息,由于function声明须要一个名字。        有趣的是,即使你为上面那个错误的代码加上一个名字,他也会提示语法错误,只不过和上面的缘由不同。在一个表达式后面加上括号(),该表达式会当即执行,可是在一个语句后面加上括号(),是彻底不同的意思,他的只是分组操做符。
// 下面这个function在语法上是没问题的,可是依然只是一个语句
// 加上括号()之后依然会报错,由于分组操做符须要包含表达式  
 function foo(){ /* code */ }(); // SyntaxError: Unexpected token )  
// 可是若是你在括弧()里传入一个表达式,将不会有异常抛出
// 可是foo函数依然不会执行 
function foo(){ /* code */ }( 1 );  
// 由于它彻底等价于下面这个代码,一个function声明后面,又声明了一个毫无关系的表达式:  
function foo(){ /* code */ } 
( 1 );
你能够访问ECMA-262-3 in detail. Chapter 5. Functions 获取进一步的信息。
          要解决上述问题,很是简单,咱们只须要用大括弧将代码的代码所有括住就好了,由于JavaScript里括弧()里面不能包含语句,因此在这一点上,解析器在解析function关键字的时候,会将相应的代码解析成function表达式,而不是function声明。
// 下面2个括弧()都会当即执行  
(function () { /* code */ } ()); // 推荐使用这个 
(function () { /* code */ })(); // 可是这个也是能够用的  
// 因为括弧()和JS的&&,异或,逗号等操做符是在函数表达式和函数声明上消除歧义的 
// 因此一旦解析器知道其中一个已是表达式了,其它的也都默认为表达式了 
// 不过,请注意下一章节的内容解释  
var i = function () { return 10; } (); 
true && function () { /* code */ } ();
0, function () { /* code */ } ();

// 若是你不在乎返回值,或者不怕难以阅读 
// 你甚至能够在function前面加一元操做符号  
!function () { /* code */ } (); 
~function () { /* code */ } (); 
-function () { /* code */ } (); 
+function () { /* code */ } ();
// 还有一个状况,使用new关键字,也能够用,但我不肯定它的效率 
// http://twitter.com/kuvos/status/18209252090847232  
new function () { /* code */
new function () { /* code */ } () // 若是须要传递参数,只须要加上括弧()
        上面所说的括弧是消除歧义的,其实压根就不必,由于括弧原本内部原本指望的就是函数表达式,可是咱们依然用它,主要是为了方便开发人员阅读,当你让这些已经自动执行的表达式赋值给一个变量的时候,咱们看到开头有括弧(,很快就能明白,而不须要将代码拉到最后看看到底有没有加括弧。

用闭包保存状态

        和普通function执行的时候传参数同样,自执行的函数表达式也能够这么传参,由于闭包直接能够引用传入的这些参数,利用这些被lock住的传入参数,自执行函数表达式能够有效地保存状态。

// 这个代码是错误的,由于变量i历来就没背locked住 
// 相反,当循环执行之后,咱们在点击的时候i才得到数值 
// 由于这个时候i操真正得到值 
// 因此说不管点击那个链接,最终显示的都是I am link #10(若是有10个a元素的话)  var elems = document.getElementsByTagName('a');  
for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', function (e) { e.preventDefault();  
alert('I am link #' + i); }, 'false'); 
}
// 这个是能够用的,由于他在自执行函数表达式闭包内部 
// i的值做为locked的索引存在,在循环执行结束之后,尽管最后i的值变成了a元素总数
// 但闭包内部的lockedInIndex值是没有改变,由于他已经执行完毕了 
// 因此当点击链接的时候,结果是正确的  
var elems = document.getElementsByTagName('a'); 
for (var i = 0; i < elems.length; i++) {  
(function (lockedInIndex) { elems[i].addEventListener('click', function (e) { e.preventDefault();  
alert('I am link #' + lockedInIndex); }, 'false'); 
})(i); }  
// 你也能够像下面这样应用,在处理函数那里使用自执行函数表达式 
// 而不是在addEventListener外部 
// 可是相对来讲,上面的代码更具可读性  
var elems = document.getElementsByTagName('a');  
for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', (function (lockedInIndex) { return function (e) {  
 e.preventDefault();  
 alert('I am link #' + lockedInIndex);  
 };  
})(i), 'false');  
}
其实,上面2个例子里的lockedInIndex变量,也能够换成i,由于和外面的i不在一个做用于,因此不会出现问题,这也是匿名函数+闭包的威力。 自执行匿名函数和当即执行的函数表达式区别           在这篇帖子里,咱们一直叫自执行函数,确切的说是自执行匿名函数(Self-executing anonymous function),但英文原文做者一直倡议使用当即调用的函数表达式(Immediately-Invoked Function Expression)这一名称,做者又举了一堆例子来解释,好吧,咱们来看看:
// 这是一个自执行的函数,函数内部执行自身,递归 
function foo() { foo(); } 
// 这是一个自执行的匿名函数,由于没有标示名称 
// 必须使用arguments.callee属性来执行本身 
var foo = function () { arguments.callee(); };  
// 这可能也是一个自执行的匿名函数,仅仅是foo标示名称引用它自身 
// 若是你将foo改变成其它的,你将获得一个used-to-self-execute匿名函数 
var foo = function () { foo(); };  
// 有些人叫这个是自执行的匿名函数(即使它不是),由于它没有调用自身,它只是当即执行而已。 (function () { /* code */ } ());  
// 为函数表达式添加一个标示名称,能够方便Debug 
// 但必定命名了,这个函数就再也不是匿名的了 
(function foo() { /* code */ } ());  
// 当即调用的函数表达式(IIFE)也能够自执行,不过可能不经常使用罢了 
(function () { arguments.callee(); } ()); (function foo() { foo(); } ());  
// 另外,下面的代码在黑莓5里执行会出错,由于在一个命名的函数表达式里,他的名称是undefined 
(function foo() { foo(); } ());

但愿这里的一些例子,可让你们明白,什么叫自执行,什么叫当即调用。jquery

注意:arguments.callee在ECMAScript 5 strict mode里被废弃了,因此在这个模式下,实际上是不能用的。浏览器

在JS中最简单的调用方式,直接写到html的body标签里面:
 
 
 
 
 
 
 
在JS中调用方式: 
 

闭包

 

二、JQ方法  ecmascript

1)整个页面的document所有加载完成之后执行。不幸的这种方式不只要求页面的DOM tree所有加载完成,并且要求全部的外部图片和资源所有加载完成。更不幸的是,若是外部资源,例如图片须要很长时间来加载,那么这个js方法执行感受就比较慢了。也就是说这是一种最严谨的页面加载完再执行方法的方法。 window.onload =function() { $("table tr:nth-child(even)").addClass("even"); //这个是jquery代码 };函数

2)仅只须要加载全部的DOM结构,在浏览器把全部的HTML放入DOM tree以前就执行方法。包括在加载外部图片和资源以前。 $(document).ready(function() { $("table tr:nth-child(even)").addClass("even"); //任何须要执行的js特效 });this

3)还有一种简写方式 $(function() { $("table tr:nth-child(even)").addClass("even"); //任何须要执行的js特效 });
spa

参考: http://www.jb51.net/article/81724.htm
http://blog.csdn.net/limlimlim/article/details/9198111

http://www.cnblogs.com/ayning/p/4113314.html

<bodyonload="myfunction()"><html> <bodyonload="func1();func2();func3();"> </body> </html>  <script type="text/javascript">   functionmyfun() {    alert("this window.onload");   }   /*用window.onload调用myfun()*/    window.onload = myfun;//不要括号 </script> <script type="text/javascript">    window.onload=function(){      func1();      func2();     func3(); } </script>
相关文章
相关标签/搜索