js中作用域和预解析问题

## 作用域链

当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会为其创建一个作用域,又称为执行上下文。

在页面加载后,会首先创建一个全局作用域,然后每执行一个函数,会建立一共对应的作用域,从而形成一条作用域链,每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域
作用域链的作用是解析标识符,当创建函数的时候,会将this/ arguments/命名参数和该函数中的所有局部变量添加到当前作用域中,当JavaScript需要查找变量的时候(这个过程称为变量解析),他会首先会从作用域链中的链尾(也就是当前作用域)查找是否有该变量属性.如果没有找到就顺着作用域链(也就是全局作用域链)继续查找,直到查到链头,如果仍然未找到该变量,就认为这段代码的作用域链上不存在该变量,并抛出一共引用错误的异常。
作用域链需要明确:
1.1ES6之前定义变量通过var ES6之后定义变量用let
1.2.ES6之前没有块级作用域,只有全局作用域和局部作用域
ES6新增加了块级作用域 但是通过let定义变量并无差异(都是局部作用域)
1.3.ES6之前函数大括号外都是全局作用域
1.4.ES6之前函数大括号中都是局部作用域
ES6之前作用域
2.1全局作用域我们又称为0级作用域
2.2定义函数开启的作用域就是1/2/3…级作用域
2.3JavaScript会将这些作用域链接在一起形成一个链条,这个链条就是作用域链
0---->1----->2------>3
2.4.除0级作用域外,当前作用域级别等于上级+1
变量在作用域链查找规则

3.1在当前找,找到就使用当前作用域找到的
3.2如果当前作用域没找到,就去上一级作用域找
3.3依次类推到0级为止,如果0级作用域没找到就报错

var在相同作用域下声明变量可以同名,后声明的覆盖先声明的
let不可以在相同作用域下声明同名变量,会报错

预解析规则
1.将变量声明和函数声明提升到当前作用域最前面
2.将剩余代码按照书写顺序依次放到后面
注意点:通过let定义的变量不会被提升(不会被预解析)

ES6之前定义函数的格式

say();
//ES6之前的这种定义函数的格式,是会被预解析的,所以可以提前调用
function say(){
    
    
	console.log("hellow it666")
}
//预解析之后的代码
function say(){
    
    
	console.log("hellow it666")
}
say();:
say();//say is not a function
//如果将函数赋值给一个var定义的变量,那么函数不会被预解析,只有变量会被预解析
var say = function(){
    
    
		console.log("hellow it666")
}
//预解析之后的代码
var say // undefined
say();
say = function(){
    
    
		console.log("hellow it666")
}:
ES6定义函数
	不会被预解析 //say is not defined
let say = () => {
    
    
	console.log("hellow it666")
}

预解析练习
1.
	var num = 123;
	fun();
	function fun(){
    
    
				console.log(num)
				var num = 666
	}
	//预解析后
	var num
	function fun(){
    
    
				var num //undefined
				console.log(num) //undefined
				num = 666
	}
	num = 123;
	fun();
2.
	var a = 666;
	test();
	function test(){
    
    
			var b = 777;
			console.log(a);
			conso.log(b);
			console.log(c);
			var a = 888;
			let c = 999;
		}
//预解析之后
var a;
function test(){
    
    
			var b;
			var a;
			b = 777;
			console.log(a); //undefined
			conso.log(b); //777
			console.log(c); //报错
			 a = 888;
			 let c = 999;
		}
 a = 666;
 test();
 3.
 //在ES6之前没有块级作用域 ,所以没有将这两个函数定义到其他函数中
	 所以这两个是全局作用域
	 //1.在高级浏览器中,不会对{}中定义的函数进行提升
	 //只有在低级浏览器中才会正常解析
	if(true){
    
    
				function demo(){
    
    
							console.log("hellow demo1111")
						}
	}else{
    
    
				function demo() {
    
    
							 console.log("hello demo2222")
						}
	}
4.
//如果变量名称和函数名称同名,那么函数的优先级高于变量
//企业开发中  变量名称和函数名称不能重名
console.log(value);
var value = 123;
function value(){
    
    
			console.log("fn value");
}
console.log(value)
//预解析之后
function value(){
    
    
			console.log("fn value");
}
console.log(value);//函数的定义
var value
value = 123;
console.log(value)//123

猜你喜欢

转载自blog.csdn.net/mhblog/article/details/114367571
今日推荐