用一道面试题考察对闭包的理解

关于闭包的用法,几乎是所有前端面试中必点的菜之一,也是考察javascript掌握程度的重要知识之一,下面这题,是某知名IT企业出的题型,我稍加修改,分享如下:

var name = 'global';
var obj = {
	name : 'obj',
	dose : function(){
		this.name = 'dose';
		return function(){
			return this.name;
		}
	}
}

alert(obj.dose().call(this))

请写出执行结果?

关于这样的题型,应当怎样去分析呢?

obj.dose().call(this) 这个表达式有点长,看着有点眼晕,不妨进行一个等价变形。

var xxx = obj.dose();
xxx.call(this);

这样就清晰多了。这样一眼就看出是在考察call的用法和this的指向。稍有点基础的,一眼就可以看出此处的this就是window对象。如果你看不出,就再去看看那本红宝书3

即使知道此处的this是window还没完。还要顺路普及一下call的用途:

// 1. 替换函数运行环境中的this

// 2. 传递参数

// 3. 运行函数

通过前面的分析可以知道xxx是这样一个函数:

function(){
            return this.name;
        }

由于call指定了this是window,所以return this.name 就是 window中的name,即global;

如果是面试呢,这题到此就结束了,不过举一反三才是我的目的。因此,下面我稍改一下题目:

var name = 'global';
var obj = {
	name : 'obj',
	dose : function(){
		this.name = 'dose';
		return function(){
			return this.name;
		}.bind(this)
	}
}
alert(obj.dose().call(this))

由于return的function中用了bind,所以相当于固定了this,外边再call什么进来,也只是碍眼法而已。由于函数内部邦定了this,所以此处的情况要另外分析了

首先,obj对象定义了name属性为'obj';接着在dose 方法内,又改写了name属性为'dose'; 根据作用域链的就近原则,alert访问的肯定就是'dose'这个值了。

然而ie派认为在return中用bind不常见,兼容性也不高。那不妨再变一下:

var name = 'global';
var obj = {
	name : 'obj',
	dose : function(){
		var that = this;
		this.name = 'dose';
		return function(){
			return that.name;
		} 
	}
}
alert(obj.dose().call(this))

这种写法,自然大家都比较认同了。考察还是相同的内容,只不过是邦定this的手法不一样而已。与其说是考察闭包,不如说是考察对基础知识的理解,因为bind,call,apply之类的方法都是平时使用频率很高的,对它们多花点时间琢磨一下,必然是有好处的。

最后呢再分享一个面试的趣事。面试官问我,用闭包有什么好处?我balabla说了个一二三四。他接着又问我,那用闭包又有什么坏处?我又是balabala说了一二三四,他就笑了。说你这一边是矛,一边是盾,到底是矛好呢还是盾好呢? 当时也没想这么多,反射性的回答说,看情况选用咯。他说这样是不行的。

原来挖了个坑在这里等着我呢,真是太不厚道了。凡事都有两面性嘛,只要撑握的好,自然是可以避害用利。我们都知道电是很危险,也很有用,只要掌握了它的特性,就能很好的利用,而不是受其害,所以并不是矛盾的就不可取。

总结一点:学东西不可浅尝则止,一定要深入原理,举一反三。

 http://www.cnblogs.com/afrog/p/4276709.html 原文地址

原文地址:https://www.cnblogs.com/shitoupi/p/6618430.html