JS:深入理解 函数、匿名函数、自执行函数

您所在的位置:网站首页 js匿名函数和闭包的区别 JS:深入理解 函数、匿名函数、自执行函数

JS:深入理解 函数、匿名函数、自执行函数

2024-07-15 19:08| 来源: 网络整理| 查看: 265

转载

原文地址:https://blog.csdn.net/xixiruyiruyi/article/details/54894404

基础概念:定义函数的方式  一般定义函数有两种方式:    1:函数的声明    2:函数表达式  函数的声明      如下代码就是函数声明的代码结构:

function sum(x,y){ alert(x+y); } sum(1,2); //3

      关于函数声明,它最重要的一个特征就是函数声明提升,意思是执行代码之前先读取函数声明。这意味着可以把函数声明放在调用它的语句之后。如下代码可以正确执行:

sum(1,2); //3 function sum(x,y){ alert(x+y); }

  函数表达式     函数表达式中有几种不同的语法。最常见和最具代表性的一种如下代码所示:

var ss = function(x,y){ alert(x+y); }; ss(1,2);

     这种形式看起来好像是常规的变量赋值语句。但是函数表达式和函数声明的区别在于,函数表达式在使用前必须先赋值。所以一下代码执行的时候就会出错:

ss(1,2); //报错,显示undefined is not a function var ss = function(x,y){ alert(x+y); };

     造成这种现象是因为解析器在向执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码前可用;至于函数表达式,则必须等到解析器执行到它的所在的的代码行,才会真正的被解析。     函数表达式中,创建的函数叫做匿名函数,因为function关键字后面没有标识符。

 

匿名函数的调用方式     匿名函数,顾名思义就是没有名字的函数。上面的函数表达式中的创建,即创建一个匿名函数,并将匿名函数赋值给变量ss,用ss来进行函数的调用,调用的方式就是在变量ss后面加上一对括号(),如果有参数传入的话就是ss(1,2),这就是匿名函数的一种调用方式。

还有一种匿名函数的调用方式是:使用()将匿名函数括起来,然后后面再加一对小括号(包含参数列表)。我们再看一下以下一个例子:

alert((function(x,y){return x+y;})(2,3));//5 alert(( new Function("x","y","return x+y;"))(2,3));//5

    在javascript中,是没有块级作用域这种说法的,以上代码的这种方式就是模仿了块级作用域(通常成为私有作用域),语法如下所示:

(function(){ //这里是块级作用域 })();

    以上代码定义并立即调用了一个匿名函数。经函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。    然而要注意一点:

function(){ }();

    上面的代码是错误的,因为Javascript将function关键字当作一个函数声明的开始,而函数声明后面不能加圆括号,如果你不显示告诉编译器,它会默认生成一个缺少名字的function,并且抛出一个语法错误,因为function声明需要一个名字。有趣的是,即便你为上面那个错误的代码加上一个名字,他也会提示语法错误,只不过和上面的原因不一样。在一个表达式后面加上括号(),该表达式会立即执行,但是在一个语句后面加上括号(),是完全不一样的意思,他的只是分组操作符(此处摘自汤姆大叔的博客)。

// 下面这个function在语法上是没问题的,但是依然只是一个语句 // 加上括号()以后依然会报错,因为分组操作符需要包含表达式 function foo(){ /* code */ }(); // SyntaxError: Unexpected token ) // 但是如果你在括弧()里传入一个表达式,将不会有异常抛出 // 但是foo函数依然不会执行 function foo(){ /* code */ }( 1 ); // 因为它完全等价于下面这个代码,一个function声明后面,又声明了一个毫无关系的表达式: function foo(){ /* code */ } ( 1 );

    所以上面代码要是想要实现,就必须要实现赋值,如a = function(){}(),"a="这个告诉了编译器这个是一个函数表达式,而不是函数的声明。因为函数表达式后面可以跟圆括号。所以下面两段代码是等价的。

var aa = function(x){ alert(x); }(5);//5 (function(x){alert(x);})(5);//5

    有上面对于函数和匿名函数的了解,我们引申出来了一个概念,即自执行函数,让我们更加深入的了解为什么。a = 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(){}()来实现自执行,可以用一些操作符在function的前面来消除歧义。

function(x){ alert(x); }(5);//报错,function name expected var aa = function(x){ alert(x); }(1);//1 true && function(x){ alert(x); }(2);//2 0, function(x){ alert(x); }(3);//3 !function(x){ alert(x); }(4);//4 ~function(x){ alert(x); }(5);//5 -function(x){ alert(x); }(6);//6 +function(x){ alert(x); }(7);//7 new function (){ alert(8);//8 } new function (x){ alert(x); }(9);//9

    很多情况下,可以利用自执行函数和闭包来保存某个特殊状态中的值,具体想看下方讲解。闭包    关于闭包,在我的上一篇文章中,做出了基础的了解: 杂七杂八JS : 浅谈闭包一     由于作用域链的配置机制,使得闭包只能取得包含函数中任何变量的最后一个值。即说明了闭包中所保存的是整个变量对象,而不是某一个特殊的变量。我们 用下面这个例子来说明这个问题。

   例子一:

function createFunction(){ var result = new Array(); for( var i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3