资讯专栏INFORMATION COLUMN

函数自执行

_ivan / 707人阅读

摘要:把这两个因素结合起来,就能通过把变量包裹在匿名函数中而对其加以保护。执行完后虽然已经变成数组的长度,但是匿名函数每次立即执行的时候传入的参数是相应的四函数定义内调用本身在中被废弃了。

一 闭包和作用域

闭包是一个受到保护的变量空间,由内嵌函数生成。JavaScript具有函数级的作用域。这意外着定义在函数内部的变量在函数外部不能被访问。JavaScript的作用域又是词法性质的。这意味着函数运行在定义它的作用域中,而不是在调用它的作用域中。把这两个因素结合起来,就能通过把变量包裹在匿名函数中而对其加以保护。(引自《JavaScript设计模式》)

var i = 100;
function makeCounter() {
    var i = 0; // makeCounter的私有变量
    return function() {  console.log(++i);  } //该函数运行的环境是makeCounter的作用域
}
var counter = makeCounter(); // counter即makeCounter的内嵌函数,运行时获取的i来源于makeCounter作用域中的i
counter(); // 输出: 1 而非 101 –>因为makeCounter返回的内嵌函数能获取i,所以也称为makeCounter的特权函数。
counter(); // 输出: 2 
i; // 输出: 100 –>说明makeCounter内的i不能被调用

二 () 调用函数

(1)function foo() {} 和 var foo = function() {},foo都是这里function(){}的引用,调用时只需要直接foo()。但如果直接将()放在function(){}后面则会触发语法错误。

function() {..}() // SyntaxError: Unexpected token(

原因:当解析器遇到function关键字时,默认将其视为一个函数声明(function declaration),而不是一个函数表达式(function expression)。如果不显式告诉解析器将其视为一个函数表达式,则会视其为一个函数声明缺少名字的语法错误。

(2)针对上面语法错误,给函数加个名称并加()执行,会触发另外一个语法错误:

function foo() {….} () ; // SyntaxError: Unexpected token ) 

原因:()放在表达式后面表示这个表达式是个函数并将要被调用,而()放在statement(函数声明也是个statement)后面则是用来与前一个statement分隔,仅仅是一个分组运算符(用在控制运算优先级的,即: 1 + 2 * ( 3 + 4 )这里括号的作用 )
修正:()作为分组运算符时,需要包含一个表达式,所以简单加个表达式 (1)。

function foo() {…}(1) ; //不会报错了,这样的写法其实等同于下面
function foo() {…} // 所以foo在这里并没有被调用,而仅仅是个声明而已。
(1)

(3)上面的修正只是解决了语法错误,但实际上并没有达到我们的期望:让函数立即执行。最常用的方法是将其包在()内。因为在JavaScript中,()只能包含表达式而不能是语句statement。

(function() {..}()) 或者 (function() {..})()

(4)其他方法:原理都是令解析器认识到()前是一个表达式

var x = function() { return 1; }();
true && function() { .. } ();
0, function() {..} ()
! function() {..} ()
~ function() {..} ()
+ function() {..} ()
– function() {..} ()

三 利用闭包保存状态
(1)下面例子给元素添加事件监听,结果每个a点击后输出的都是elmes数组的长度。
原因:for执行后的每个elems的点击事件函数中绑定的是 j ,当点击时输出的 j 确确实实就是 j 在for运行之后的值。

var elems = document.getElementsByTagName(‘a’);
for (var j = 0; j < elems.length; j++) {
    elems[j].addEventListener(‘click’, function(e) {
        e.preventDefault();
        console.log (j);
    }, false);
}

(2)下面例子利用立执行函数,将 j 锁定。
for执行完后 j 虽然已经变成elems数组的长度,但是匿名函数每次立即执行的时候传入的参数是相应的 j

var elems = document.getElementsByTagName(‘a’);
for (var j = 0; j < elems.length; j++) {
    (function( lockedIndex ) {
        elems[j].addEventListener(‘click’, function(e) {
            e.preventDefault();
            console.log(lockedIndex);
        }, false);
    })(j);
}

四 函数定义内调用本身

function foo() { foo(); } 
var foo = function() { arguments.callee(); } // arguments.callee 在ECMAScript5中被废弃了。

五 参考
immediately-invoked-function-expression

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86042.html

相关文章

  • 深入理解JavaScript系列4:立即调用的函数表达式

    摘要:前言大家学的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。其实,前面两个例子里的变量,也可以换成,因为和外面的不在一个作用于,所以不会出现问题,这也是匿名函数闭包的威力。 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。 在详细了解这个之前,我们来谈了解一下自执行这个叫法,本文对这个功能的叫法也不一定完全对...

    roadtogeek 评论0 收藏0
  • 什么是闭包,变量的作用域和执行函数

    摘要:作用域和闭包以及自执行函数作用域作用域分为种全局作用域全局作用域就是在的任何位置都能访问过函数作用域只能在函数里面调用的称之为函数作用域闭包嵌套在函数里面的函数及周边的变量叫闭包闭包存在的问题是周边变量不会被释放,常驻内存中闭包的缺点消耗内 作用域和闭包以及自执行函数 作用域 作用域分为2种 1、全局作用域 全局作用域就是在js的任何位置都能访问过 2、函数作用域 只能在函数里面调用的...

    daydream 评论0 收藏0
  • 调用匿名函数(匿名闭包)解析与调用

    摘要:打开源码,首先你会看到这样的代码结构这是一个自调用匿名函数。模式,是自执行函数的高级模式,可以非常方便的在各个匿名闭包中以全局对象调用闭包函数。 打开jQuery源码,首先你会看到这样的代码结构: (function(window,undefined ){ // })(); 这是一个自调用匿名函数。什么东东呢?在第一个括号内,创建一个匿名函数;第二个括号,立即执行 为什么要创建这样一个...

    Scorpion 评论0 收藏0
  • php底层原理之函数

    摘要:但是到底是如何找到对应的函数的呢今天,我们来一起寻找答案函数分类首先,我们先回顾一下的函数分类,函数包含用户自定义函数内部函数匿名函数等多种类型。用户自定义函数和内部函数编译完成后会将函数名注册到全局函数列表中。 对于PHPer而言,我们通常会把常用的功能封装成一个函数来进行复用,以提升开发效率。但是php到底是如何找到对应的函数的呢?今天,我们来一起寻找答案~ 函数分类 首先,我们先...

    rose 评论0 收藏0
  • 微信小程序(新)必备知识

    摘要:组件化开发小程序在未出现组件之前,要重用的话,只能简单复制粗暴黏贴组件化开发的优势可复用代码分离,可维护更重要定义组件先创建文件夹用于存放组件,然后再创建组件文件夹注意组件的文件名并不是组件名,而页面文件名是页面名,组件名是引用时才确定的引 组件化开发 小程序在未出现组件之前,要重用的话,只能简单(复制)粗暴(黏贴) 组件化开发的优势: 1、可复用(wxml/wxss/js) 2、代...

    mengera88 评论0 收藏0
  • 简单理解Generator执行及async、await语法原理

    摘要:为了更加方便的处理异步操作问题,现在最新的前端框架生态都开始用上了和,有的甚至已经开始使用最新的语法了,这两样都是基于自动执行的原理。这里就简单理解下自执行及语法原理一函数函数指的是能将执行结果传入回调函数,并将该回调函数返回的函数。 为了更加方便的处理异步操作问题,现在最新的前端框架生态都开始用上了Generator和yield,有的甚至已经开始使用最新的async、await语法了...

    stackfing 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<