在谈闭包之间,我们先看一下javascript的作用域,我们以函数举例。
对一个函数来说它的作用域分为三种:
函数定义作用域
函数调用作用域、
函数内部作用域
以下是一段代码:
var x="how are you";
var a=0;
function ab(){
console.log('a=',a);
console.log('x=',this.x);
}
function ac(){
var a=100;
var x="I'm fine";
ab();
}
ac();
ab();
以下为输出:
函数ac的输出与函数ab的输出一致,这是不是很奇怪?函数ac中定义了同名变量a=100,x="I'm fine",ac中调用了函数ab,但函数ab的输出并没有受到影响。
我们来看看《javascript权威指南》中对闭包的解释,闭包就是调用一个函数时,如果该函数内函数体有对函数外变量的引用,函数被调用时,就是会将函数以及函数引用的变量包裹起来,这就形成了闭包。
我们再来看上面的例子,这是js闭包的经典示例,我们不难发现,js中对于函数的调用会回溯到函数定义时的作用域,函数的作用域就是函数定义的作用域,它和函数调用的作用域无关。所以无论函数ac内变量怎么变换,都不会影响ac内函数ab的输出。
那么,在函数调用作用域与定义作用域不同的情况下,如果我们想让函数的掉哦用作用域可以影响函数的输出有什么办法吗?
答案时肯定的,方法可以从两个方面入手:
方案一:函数传参
方案二:改变函数执行上下文
我们先来看方案一怎么实现的,以下是示例代码:
var a='how are you';
function ab(a){
console.log('a=',a);
}
function ac(){
var a="I'm fine";
ab(a);
}
ab(a);
ac(a);
输出:
通过输出可以看出函数ab的输出发生了改变,这是因为在函数ac中变量a被当作参数传入了函数ab。再看函数ac的写法是不是很熟悉,这就是常见的回调函数的写法,回调函数在异步javascript应用很多。在函数ac中函数ab的调用,严格意义上算不上闭包,因为ac只调用了ab本身,没有连ab外的变量一起调用。
我们再来看改变函数执行上下文怎么实现:
var x="how are you";
function ab(){
console.log("x=",this.x);
}
var a={
x:"i'm fine"
};
ab();
ab.call(a);
以下是输出结果:
ab的输出更改成功, 在js中使用call,apply以及bind这些方法可以改变函数执行的上下文。
总结,js中的闭包如果想通了其实很简单,就是一个函数如果被调用的话,它不是在调用它的作用域执行的,而是在定义函数的作用域执行的。理论上在不改变函数执行上下文的情况下,只有定义函数的作用域以及函数内部作用域可以影响函数的输出,调用函数的作用域要想影响函数的输出,只有三个方法,第一个调用函数作用域以及定义函数作用域是同一个作用域(这个纯属扯淡,是个人都知道),第二个是调用函数作用域将参数传进函数内部作用域,第三个是通过apply,call以及bind这些方法改变函数执行的上下文。我现在还想到了第四个方法,时间有限,不说了,以后在补充。
第一次写技术文章,难免有很多遗漏的地方,如果这篇文章能有幸给人看到的话,希望您能留下宝贵的意见。
网友评论