JavaScript作用域

作为前端开发者,作用域一直是一个比较耐人寻味的一个点,当然其他的语言也有,今天就聊聊JavaScript中的作用域。

首先说下这两个:

引擎:从头到尾负责整个JavaScript程序的编译及执行过程。

编译器:负责语法分析以及代码生成的一切。

那么,作用域就是一个执行环境。执行环境中有变量和函数,这样就决定了他们各自有自己的行为,每个执行环境都有一个与之关联的变量对象,执行环境中的所有的变量和函数都保存在这里。对于这个变量对象,我们是访问不到的,但是引擎和编译器在处理数据时会在后台使用。

一个函数决定了其中定义的变量的作用域,反过来想,一段代码,给外面加了一层包装,这里面定义的一切,在外面是访问不到的,只能在里面访问。当然,闭包可以,这里先不说闭包。

function f1(){
	var t= 1;
	console.log(t);  //1
}
console.log(t);   //出错,访问不到

当一段代码在一个环境中执行的时候,会创建一个作用域链。作用域链就是保证对执行环境中的所有变量和函数可以进行有序的访问,不至于乱套。

看段代码:

var a = 1;
function f1(b){
	var t= 1;
	console.log(t); //1
	console.log(b+a);//2
}
f1(1);
对于这段代码,就有一个作用域链,里面有全局环境,f1环境。首先代码执行的时候,会是全局作用域,找到了a,这样将a压入执行栈中,然后继续扫描,到了f1中,压入执行栈,继续,找到了t。接下来,就是输出t=1,将t跳出执行栈,继续扫描,输出b+a,b作为形参,是1,但是a没有找到,就继续跳出执行栈,在全局环境中找,直至找到了a,输出2。

这段代码只是简单的描述了,但是一个作用域链执行过程就是这样子的。


在JavaScript中只有函数作用域和全局作用域,没有块级作用域的。

for(var i=0;i<10;i++){
	....
}
alert(i);  //10
如果有作用域,这里弹出i就是undefined,但是JavaScript中没有块级作用域。这段代码在执行完毕后,i不能被销毁,而是将变量添加到当前执行环境中,这里就是全局执行环境。

那怎样模仿出块级作用域?

1.立即执行函数表达式
由于函数被包含在一对()括号内部,因此成为了一个表达式,通过末尾加上另外一个()可以立即执行这个函数,比如(function f(){.......})(),第一个()将函数变成表达式,第二个()执行了这个函数。当然还有另外一种书写方式(function(){.......}())。
(function f(){
	var a = 1;
	console.log(a);  //1
})();
console.log(a);   //a is undefined
2.with
with通常被当做重复引用同一个对象中的多个属性的跨界方式,可以不需要重复引用对象本身。
平时的写法:
var obj = {
	a:1,
	b:2,
	c:3
}
obj.a = 2;
obj.b = 3;
obj.c = 4;
with(obj){
	a = 3
}
第二段代码就是利用with,给obj添加属性,方便简单,同时也创建了一个块级作用域,这个作用于仅在with声明中而非外部作用域有效。
3.try/catch
try/catch的catch分局会创建一个块作用域,其中生命的变量仅在catch内部有效。
try{
	undefined();
}catch(err){
	console.log(err);
}
console.log(err);  //ReferenceError: err not found
4.let
let关键字可以将变量绑定到所在的任意作用域中(通常是{.....}),let为其生命的变量隐式的劫持了所在的块级作用域。
var a = true;
if(a){
	let b = 2;
	console.log(b);  //2
}
console.log(b); //Uncaught ReferenceError: b is not defined
再看一个例子:
for(let i=0;i<10;i++){
	console.log(i);
}
console.log(i); //ReferenceError
5.const
在es6中,除了引入let,还引入了const,同样可以用来创建块作用域变量,但其值是固定的,之后的任何修该值的操作都会引起错误。
var a = true;
if(true){
	var b = 2;
	const c = 3;//包含在if中的块级作用域

	b = 3; //正常
	c = 4; //错误
}
console.log(b);  //3
console.log(c);   //ReferenceError

到此,最基本的作用域之类的知识就大概做了阐述,当然闭包也在作用域的范畴,这里没有讨论而已! 微笑


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值