javascript 作用域和作用域链

首先说一下js的作用域,变量有4种基本方式进入作用域:

      1.语言内置: 所有的作用域里都有this和arguments;(需要注意的是arguments在全局作用域是不可见的)

      2.形式参数: 函数的形式参数会作为函数体作用域的一部分;

      3.函数声明: 像这种形式: functionfn() {};

      4.变量声明: 像这样: var name;

前两种我们这里不做讨论。

什么是作用域?

简单来说就是变量和函数可作用的范围。在ECMAScript6之前js是没有块级作用域的,只有全局作用域跟函数作用域(局部作用域)。

下面的这段代码,可能会经常遇到:

//要获取列表元素的索引
var li=document.querySelectorAll('li');
for(var i=0; i<li.length; i++){	
	li[i].οnclick=function(){
		alert(i);
	}
}

为什么得到始终都是li.length?

其实每个li对象在触发click事件时,for循环已经执行完毕,匿名函数中并没有重新定义变量i,所以此时都指向全局变量i(for循环不存在作用域),所以结果都是li.length。

说到作用域,变量提升就不得不说。上面情况就是存在变量提升导致的。

一、变量提升

看下面这段代码:

function fn(){
	if(!b){			
	var b=10
	}
	console.log(b)   //10
}
fn();
这里可能刚接触js的会感到诧异。if语句根本执行,为什么打印结果是10 。

其实js在执行这段代码的时候回提前声明变量b,但是没有赋值。

上面的代码在执行时,会解析成:

function fn(){
       var b;  // 声明提前
	if(!b){			
		b=10
	}
	console.log(b)  
}
fn();

这里也是js中比较怪的一个现象,在js中,用var关键字声明的变量,在js解析时会提前声明。


二、函数声明提前

在js中不仅变量会声明提前,函数同样也会声明提前

function fn(){
	console.log(test); 	// function test(){}
	console.log(test2)   //undefined 
	return ;
	function test(){}
	var test2=function(){}
}
fn();

这里的test2为什么没有提前。这里还得说一下函数声明的两种方式

1.   函数声明:用function关键字声明函数。

2.   函数表达式:用var定义一个变量指向一个匿名函数(非function关键字声明的函数)。

test2只是声明了一个变量,指向了一个匿名函数。声明提前了,没有给他赋值。

上面的代码在执行时,会解析成:

function fn(){
	function test(){};   //整体提前
	var test2;   //声明提前
	console.log(test); 	
	console.log(test2)  
	return ;
	test2=function(){}   //函数表达式
}
fn();

注:在js中用function关键字声明的函数,在js解析时,会整体提前到该作用域的最前面。

三、作用域链

作用域链想说清楚比较麻烦,这里只是简单的说一下。

有点js基础的应该都知道,所有末定义直接赋值的变量自动声明为拥有全局作用域。这是为什么?

我们先看下面的这段代码:

function fn1(){
	function fn2(){
		function fn3(){
			n=10;
		}
		fn3();		
	}
	fn2();
	console.log(n)  // 10
}
fn1();
console.log(n);   // 10

作用域链:fn3 -> fn2-> fn1-> global;

var n="a";
function fn1(){
	function fn2(){
		var n="b";
		function fn3(){
			console.log(n)   // b
		}
		fn3();
	}
	fn2();
	function test(){
		g=10;
	}
	test();
	console.log(g)  //10
	console.log(n)  //a
}
fn1();
作用域链:fn3 -> fn2-> fn1-> global;

作用域链:test -> fn1-> global;

js中,没有用var关键字声明的变量,在js运行时会向他的上一层作用域去找是否已经声明,直到全局作用域,如果还是没有,就会自动声明一个全局变量。

四、with语句

with 语句用于设置代码在特定对象中的作用域。

var sex="woman";
var age=20;
function fn(){
	var sex='man';
	var name='lisi';
	var json={
		name:'zhangsan'
	}
	with(json){
		console.log(name);   //zhangsan
		console.log(sex);    // man
<span style="white-space:pre">		</span>console.log(age);    //20
	}
<span style="white-space:pre">	</span>console.log(name)            // lisi
}
fn();
当设置的对象中没有想对应用的属性时,会向with设置的特定作用域逐级向上一作用域中找。当with语句执行完毕时,作用域链回复正常。


上面只是自己对作用域的一些浅解,有不当之处还请指正。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值