再次深入理解闭包

    之前写过一篇关于闭包的文字,当时觉得对闭包已经掌握到目无全牛的程度——直到我看到这篇博文:大部分人都会做错的经典JS闭包面试题

    我觉得我应该重新审视闭包这个概念,以及一些之前了解不够细致的JavaScript细节。下面是我抽取出来的一些容易被忽略的概念以及我的思考。


1.JS中有几种函数

     首先,在此之前需要了解的是,在JS中函数可以分为两种,具名函数(命名函数)匿名函数区分这两种函数的方法非常简单,可以通过输出 fn.name 来判断,有name的就是具名函数,没有name的就是匿名函数。
 在IE下不能获取到去获取具名函数的name会返回undefined,所以下面给出兼容处理方式:
/**
    * 获取指定函数的函数名称(用于兼容IE)
    * @param {Function} fun 任意函数
    */
function getFunctionName(fun) {
    if (fun.name !== undefined)
        return fun.name;
    var ret = fun.toString();
    ret = ret.substr('function '.length);
    ret = ret.substr(0, ret.indexOf('('));
    return ret;
}

2.创建函数的几种方式

  1. 匿名函数表达式,形如:var fn = function () {}
  2. 声明函数,形如:function ghostlpx () {}
  3. 具名函数表达式,形如:var fn = function ghostlpx () {}
  4. Function构造函数
  5. 自执行函数
  6. 其它一些不入流的旁门左道,如eval

3.我的思考

  1. 关于函数表达式:具名函数表达式本质上也是函数表达式,只不过在外部调用的时候一定要用它的变量名fn,不能使用它的函数名,函数名只能在函数内部找得到。
  2. 对象内部的函数表达式:形如 var o = { fn : function () {...} } ,这本质上也是利用函数表达式的方式在创建函数。另外值得引起注意的就是,在该函数内部访问不到存放该函数的变量,因为作用域链是向上寻迹的。
  3. 关于“闭包”这个单词的翻译:准确吗?闭包 closure 应该取的是close的意思, close的本意, 除了闭合, 还有一个意思是贴近。而JS中的closure, 是取“贴近”的意思。设计者叫它closure, 是因为内嵌函数的作用域链贴近了父函数的作用域, 形成了作用域链。因为近, 所以可以用。

4.经典的闭包使用场景

    今天刚好又回头看了看 ECMAScript 5 中新增的bind()方法,这个方法主要作用就是将函数绑定到某个对象上。bind()方法在 ECMAScript 3 中的实现恰好利用了闭包,所以拿出来分析一下。
if ( !Function.prototype.bind ) {
	Function.prototype.bind = function ( o ) {
		var boundArgs = arguments,
			self = this;

		//bind()方法的返回值是一个函数
		return function () {
			var args = [], i;

			//将bind中传入的第二个实参以及传入新函数的所有实参都放到args数组中
			for( i=1; i<boundArgs.length; i++ ) { args.push( boundArgs[i] ); }
			for( i=0; i<arguments.length; i++ ) { args.push( arguments[i] ); }

			//将self作为o的方法来调用,传入实参
			return self.apply( o, args );
		}
	}
<span style="font-size:12px;">}</span>
    bind()方法返回的函数是一个闭包,在这个闭包的外部函数中声明了self和boundArgs变量,这两个变量在闭包中用到。尽管定义闭包的内部函数已经从外部函数中返回,在闭包中照样可以正确返回这两个变量。





猜你喜欢

转载自blog.csdn.net/ghostlpx/article/details/52727611