javascript之闭包

一.变量声明提前和函数声明提前

1.从代码开始
console.log(wyc);	//function wyc(){
					//	console.log("hello,wyc");
					//}
wyc();				//hello,wyc
function wyc (){
  console.log("hello,wyc");
}
console.log(wp);	//undefined
wp();				//Uncaught TypeError: wp is not a function
var wp = function () {
  console.log("hello,wp");
}

1.wyc是函数声明,会把整体都提前

1.wp是变量声明,只把声明提前,赋值在执行的时候进行

 2.小坑踩一踩

代码的目的是:为true时,只声明wyc函数,不声明wp

来个错误的示范:

if(true){
	function wyc(){
		console.log("i am wyc");
	}
}else{
	function wp(){
		console.log("i am wp");
	}
}
wyc();
wp();

这在ECMAScript中是无效语法,但是有的浏览器的javascript引擎会去修复这个问题,造成浏览器表现不一致。

规范的写法——用函数表达式

var wyc,wp;
if(true){
	wyc = function(){
		console.log("i am wyc");
	}
}else{
	wp = function(){
		console.log("i am wp");
	}
}

二.作用域

msdn原文:

JavaScript has two scopes: global and local.  A variable that is declared outside a function definition is a global variable, and its value is accessible and modifiable throughout your program.  A variable that is declared inside a function definition is local.  It is created and destroyed every time the function is executed, and it cannot be accessed by any code outside the function.  JavaScript does not support block scope (in which a set of braces {. . .} defines a new scope), except in the special case of block-scoped variables.

翻译:

js有两个作用域,全局和局部。在函数外声明的变量是全局变量,他的值可在整个程序中访问和修改。在函数定义内声明的变量是局部变量。  每当执行函数时,都会创建和销毁该变量,且无法通过函数之外的任何代码访问该变量。js不支持块级作用域,但块作用变量的特殊情况除外(指es6新特性let)。 

 简单来说:作用域就是函数内的变量,函数各玩各的,互不影响……

变量互不影响

function outer(){
	var wp = "局部变量1";
	console.log(wp);
}
function outer2(){
	var wp = "局部变量2";
	console.log(wp);
}
console.log(wp);	//全局变量
outer();			//局部变量1
outer2();			//局部变量2

函数互不影响

unction wyc(){
	console.log("全局函数");
}
function outer(){
	return function wyc(){
		console.log("局部函数2");
	}
}
function outer2(){
	return function wyc(){
		console.log("局部函数2");
	}
}
wyc();					//全局函数
var result1 = outer();
result1();				//局部函数1
var result2 = outer2();
result2();				//局部函数2

网上很多人说什么作用域是函数里面能访问外面,外面的不能访问里面什么的,巴拉巴拉一大堆,个人感觉不对,我认为那个是靠作用域链来实现的

 三.执行环境EC

1.先了解概念

(1)执行环境ec——就是函数执行时创建的环境(函数每执行一次就创建一个,for循环会创建多个)

(2)执行环境栈ecStack——函数每次执行,当前执行环境就会入栈,执行结束出栈。

2.执行环境有三部分组成:变量对象vo,作用域链scopeChain,this

(1)变量对象:每个执行环境都会有变量对象,当执行环境处于栈顶时又叫活动对象(由当前作用域的arguments参数,变量,函数组成)

(2)作用域链:由执行环境栈的变量对象组成,从栈顶到栈底

(3)this:函数执行的时候确定指向(全局指向window,其他情况有点复杂,不展开)

3.执行环境分为三种情况:

(1)全局执行环境:在栈底,所以它一直存在,直到关闭浏览器才消失

(2)函数执行环境:函数执行时,它的执行环境入栈,进行相关操作(查询标识符等)

(3)eval:我不咋用,没研究

拿代码说话!!!

这段代码是我用来研究块级作用域用es6的代码转成的es5代码

//
var foo = [];

var _loop = function _loop(i) {
    foo[i] = function () {
        console.log(i);
    };
};

for (var i = 0; i < 10; i++) {
    _loop(i);
}

foo[1]();

_loop执行环境的作用域链:包含local和gloabl两个变量对象,gloabl中包含arguments参数i和this。

 四.闭包

铺垫了这么久,终于来到闭包啦……

js高级程序设计上这样说:闭包是指有权访问另一个函数作用域中的变量的函数。(不过,按照作用域链,我本来就可以访问到啊……这里是指outer函数已经结束运行,再执行inner函数,还会记得其变量)

1.正常来讲,函数执行完毕完毕之后,局部活动对象就会销毁

2.但是函数套函数情况不同

function wyc(){
	var a = 1;
	var b = 2;
	function wp(){
		console.log(b);
	}
	return wp;
}
var result = wyc();
result();

函数执行到result()时,也就wp函数执行的时候,他的执行环境的作用域链包含了一个叫closure的变量对象,其中有b变量(没有a变量)——可以把console.log(b);写成console.log("xxx");观察有没有闭包,答案是没有的。上面就是闭包……即有权访问另一个函数作用域中的变量的函数,也就是说wp是一个闭包。

五.闭包带来的影响及办法

function wyc(){
	var wp = [];
	for(var i = 0;i < 10;i++){
		wp[i] = function(){
			return i
		}
	}
	return wp;
}
var wp = wyc();
console.log(wp[2]());	//10

你可能想wp[2]返回的是2,但是返回的是10.

js高级程序设计中这样说:闭包只能取得包含函数中任何变量的最后一个值。wp[0]-wp[9](不同闭包)的包含函数都是同一个,所以每个函数的作用域链中都保存着是同一个wyc()函数的变量对象。这也是因为没有块级作用域的原因(for{}不是块级作用域,即像函数一样的局部作用域)。

解决办法一:立即执行

function wyc(){
	var wp = [];
	for(var i = 0;i < 10;i++){
		wp[i] = (function(x){
			return x;
		}(i));
	}
	return wp;
}
var wp = wyc();
console.log(wp[2]);	//2

但是wp[2]不是一个函数了,再看另一种办法(多个闭包并且是多个包含函数)

var wp = [];
var wyc = function(i){
	wp[i] = function(){
		return(i)
	}
} 

for(var i = 0;i < 10;i++){
	wyc(i);
}
console.log(wp[1]());	//1
console.log(wp[2]());	//2

1.wyc执行了10次,每次对应一个wp[]闭包。

2.也就是说每个闭包都记住了包含他的函数的变量i,而变量i在10次wyc执行中是不同的

3.es6块级作用域代码转成es5的实现就是这个原理。

转载于:https://my.oschina.net/wyc1219/blog/869594

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值