【javaScript基础】马上调用函数表达式

在javaScript中,每一个函数被调用时,都会创建一个新的运行上下文。由于在一个函数里面定义的变量和函数仅仅能在里面訪问。在外面是不行的。上下文提供了一种非常easy的方法来创建私有性。

//makeCounter函数返回另外一个匿名函数,这个匿名函数可以訪问到“私有”变量i, 好像有一点“特权”性。
function makeCounter() {
    // i仅仅能在makeCounter的里面被訪问到
    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
i; // ReferenceError: i没有被定义(它仅仅存在于makeCounter的内部)

在非常多情况下,你不须要函数返回多个“实例”。你只须要一个单例。又或者在其它情况下,你可能连一个返回值都不须要。

问题的关键

如今你定义了像function foo(){}或var foo = function(){}这种函数,这样你得到了一个函数的标识符。你能够通过()来调用它。如foo()。

//像这样定义的函数能够通过后面的()来调用,如foo(),由于foo不过一个
//函数表达式‘function(){/*...*/}‘的引用
var foo = function(){ /* ... */ }
//只能过后面的() ,函数表达式就能被运行,这是不合常理的。
function(){ /* ... */ }(); // SyntaxError: Unexpected token (

正如你以上所看见的,出现了异常。

当JS解释器在全局作用域或函数的里面遇到functionkeyword时,会默觉得是一个函数声明,而不是一个函数表达式。假设你不确切地告诉解释器是一个表达式,它会觉得是一个没有名字的函数声明,所以导致语法错误异常,由于函数声明是须要名字的。

顺便说一下:函数、括号、语法错误
有趣的是,假设你为函数指定了一个名字,而且把括号放在它后面,出于不同的原因。解析器也会抛出一个语法错误。当括号放在表达式的的后面意味着表达式是一个将被调用的函数,括号放在声明的后面,会与前面的声明全然分开。只代表一个分组操作符(作为一种控制优先级的一种控制方式)。

<span style="font-weight: normal;">//这个函数在语法声明上是有效的。它不过一个声明,紧跟着的括号是无效的,
//由于分组操作符须要包含一个表达式
function foo(){ /* ... */ }(); // SyntaxError: Unexpected token )
//如今假设你在括号里放一个表达式,没有异常抛出
//可是函数仍然没有运行
function foo(){ /* ... */ }( 1 );
//事实上上面的相当于下面两个:一个是函数声明,一个是不相关的表达式
function foo(){ /* ... */ }

( 1 )</span>

想要了解很多其它。请訪问, ECMA-262-3
in detail. Chapter 5. Functions

马上调用表函数达式(IIFE)

幸运的是以上语法错误能够简单地被修复。最广泛的做法是告诉解析器函数表达式不过用括号括起来的,由于在javaScript中,括号不能包含声明。依据这一点,当解析器遇到functionkeyword时,会把它解析成一个表达式而不是函数声明。

//下面两种都能够被用来马上运行一个函数表达式,用函数的运行上下文去创建
//私有性
(function(){ /* ... */ }()); // Crockford推荐使用这个
(function(){ /* ... */ })(); // 可是这一个也工作得非常好

//从括号或强制操作符来看,消除了函数声明和函数表达式的歧义,
//当解析器已经预期是一个表达式时,他们也能够被忽略,请看下面的样例
var i = function(){ return 10; }();
true && function(){ /* ...*/ }();
0, function(){ /* ... */ }();

//假设你不关心函数的返回值或你的代码可读性
//你能够节省一个字节。通过在函数前面加一个一元操作符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

//还有另外的版本号,但我不清楚它的实现性能会如何,用‘new‘keyword实现。
//运行是正常的
new function(){ /* code */ }
new function(){ /* code */ }()
关于括号须要注意的重要点

特别在“消除歧义”的括号(即包着函数表达式的括号),是不须要的(由于解析器已经觉得它是表达式了)。对于用在赋值中还是一个不错的想法。

这种括号非常明显暗示了函数表达式能够马上被调用,而且这个变量将包含函数的返回结果。不是函数本身。这能够免去一些人阅读你代码的麻烦,由于假设你的函数声明非常长时。可能要滚动到以下才知道你这个函数有没有被调用。

一般来说。想写出清晰的代码。从技术上说要阻止解析器抛出语法错误异常,编写清晰的代码也须要阻止其它开发人员把错误异常抛向你。

用闭包来保存状态

通过传递參数来调用马上函数。调用具有名称标识的函数并同一时候向它传递參数,这两者的调用方式是非常像的。

不论什么定义在一个函数里面的函数都能訪问它外面函数的所传递进来的參数以及外层函数的变量(这样的关系被称为闭包),一个马上调用函数表达式能够被用来“锁住”值和保存状态值。

假设你想学习很多其它关于闭包的内容,请阅读Closures explained with JavaScript.

以下例2和例3会依照你期望的运行,马上运行函数表达式有一个非常大的缺点是它是匿名或没有命名的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
	<a href="###">点我</a>
	<a href="###">点我</a>
	<a href="###">点我</a>
	<a href="###">点我</a>
	<a href="###">点我</a>
	<script type="text/javascript">
		var elems = document.getElementsByTagName( ‘a‘ );
		//例1
		for ( var i = 0; i < elems.length; i++ ) {
			console.log(i);
			elems[ i ].addEventListener( ‘click‘, function(e){
				e.preventDefault();
				alert( ‘I am link #‘ + i );
			}, ‘false‘ );
		}
		//运行结果:
		//I am link #5
		//I am link #5
		//I am link #5
		//I am link #5
		//I am link #5

		//例2
		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 );
		}
		//运行结果:
		//I am link #0
		//I am link #1
		//I am link #2
		//I am link #3
		//I am link #4

		//例3
		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‘ );
		}

		//运行结果:
		//I am link #0
		//I am link #1
		//I am link #2
		//I am link #3
		//I am link #4
	</script>
</body>
</html>
时间: 2024-10-11 21:22:59

【javaScript基础】马上调用函数表达式的相关文章

理解JavaScript的立即调用函数表达式(IIFE)

首先这是js的一种函数调用写法,叫立即执行函数表达式(IIFE,即immediately-invoked function expression).顾名思义IIFE可以让你的函数立即得到执行(废话). 一般来说,IIFE有以下几种用途: 1. 创建只使用一次的函数,并立即执行它. 2. 创建闭包,保存状态,隔离作用域. 3. 作为独立模块存在(例子如jQuery),防止命名冲突,命名空间注入(模块解耦). 1. 创建只使用一次的函数,并立即执行它 创建只使用一次的函数比较好理解,在需要调用函数的

【javaScript基础】立即调用函数表达式

在javaScript中,每个函数被调用时,都会创建一个新的执行上下文.因为在一个函数里面定义的变量和函数只能在里面访问,在外面是不行的,上下文提供了一种很容易的方法来创建私有性. //makeCounter函数返回另外一个匿名函数,这个匿名函数能够访问到"私有"变量i, 好像有一点"特权"性. function makeCounter() { // i只能在makeCounter的里面被访问到 var i = 0; return function() { cons

JavaScript 编码规范 之 函数表达式

! function () { var a = function () // 赋值一个函数表达式 { } , b = function () // b c 效果一样 都是返回一个拥有闭包的函数 { var time = +new Date ; return function () { ; console.log( time ) } }() , c = ( function () // 加上圆括号的原因 1 表示是立即执行 2 拥有闭包元素 { var time = +new Date ; ret

函数声明、 函数表达式 与立即调用函数表达式的比较

函数声明 函数声明创建将来代码调用的函数.函数可以在声明之前的位置被调用.代码样例如下: //可以在声明之前的位置被调用 var size=area(3,6); function area(width,height){ return width*height; }; //可以在声明之后的位置被调用 var size2=area(2,4); 函数表达式   将函数放在本该表达式待的位置,这称为函数表达式.在函数表达式中,经常使用匿名函数.代码样例如下 var area=function(width

浅谈javascript立即调用函数表达式

函数声明.函数表达式.匿名函数: 函数声明:function fnName () {-};使用function关键字声明一个函数,再指定一个函数名,叫函数声明. 函数表达式 var fnName = function () {-};使用function关键字声明一个函数,但未给函数命名,最后将匿名函数赋予一个变量,叫函数表达式,这是最常见的函数表达式语法形式. 匿名函数:function () {}; 使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数,匿名函数属于函数表达式

JavaScript基础 超链接调用js函数

镇场诗: 清心感悟智慧语,不着世间名与利.学水处下纳百川,舍尽贡高我慢意. 学有小成返哺根,愿铸一良心博客.诚心于此写经验,愿见文者得启发.------------------------------------------ code: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"

JavaScript 基础(七) 箭头函数 generator Date JSON

ES6 标准新增了一种新的函数: Arrow Function(箭头函数). x => x *x 上面的箭头相当于: function (x){ return x*x; } 箭头函数相当于匿名函数,并且简化了函数定义.一种像上面的,只包含一个表达式, 连{ ... }和return都省略掉了.还有一种可以包含多条语句,这时候就不能省略{ ... }和return: x =>{ if(x > 0){ return x * x; }else{ return -x *x; } } 如果参数不是

JavaScript基础之定义函数

javascript 字符串 字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript并未提供修改已知字符串内容的方法 常见功能: obj.length                           长度   obj.trim()                           移除空白 obj.trimLeft() obj.trimRight) obj.charAt(n)                       

JavaScript笔记五:函数表达式

1.函数表达式 var function = function() { //函数体 }; 2.递归 function factorial(num) { if(num<=1){ return 1;  } else {return num*factorial(num-1);} } arguments.callee是一个指向正在执行函数的指针,因此可以用它实现递归. function factorial(num) { if(num<=1){ return 1;  } else {return num