JavaScript的作用域以及预解析

一、我们先来看下ES5的作用域:

1、全局作用域
一个script标签就是一个全局作用域(也是一个宏任务),如果一个页面有多个script标签则会从上到下执行。
2、函数作用域(局部作用域)
一个函数内就是局部作用域。

二、JavaScript的预解析执行每遇到一个作用域就会进行两步骤:
1、(找出一些关键字初始赋值,代码从上到下查找)如:var、函数声明

如果找到的是var的变量,则统一先把他们存为未定义(undefined);
如果找到的是函数声明,则存为不变的整个函数块 (函数参数的话其实也是一个var变量)

  • 如果遇到变量和函数同名,函数声明会被提升至作用于最上面。
// 函数
function a(y){
    console.log(y+2);
}
// 变量
var a ;
console.log(a); // ƒ a(y){ console.log(y+2); }
  • 如果遇到多个同名的函数,那么就会考虑顺序问题,后者覆盖前者。
console.log(a); // ƒ a(y){ console.log(y+3); }
function a(y){
    console.log(y+2);
}
function a(y){
    console.log(y+3);
}
a(1); // 4

预解析第一步:

a = undefined;
	所有使用var声明的变量,在正式运行代码之前都提前赋值为未定义(undefined),变量提升。
function fn1() { alert(2); }
	所有函数声明,在正式运行代码之前都是整个函数块,整体提升。
2、再逐行解读代码运行

1)、如果遇到的是表达式(+、-、*、/、%、++、–)、赋值(=)等这些能够改变变量的值的,就把相应的变量值修改掉。

2)、如果遇到函数的调用,则又要进行预解析的两个步骤!(因为又遇到了函数作用域)
此时的预解析是在对应函数内部进行预解析的。
i 、(找出一些关键字初始赋值,在函数体内从上到下查找)如:函数参数、var、函数声明、
在函数的参数中如果形参没有显式使用var声明参数,那么默认也是使用了var。函数的参数就是本函数内部变量。

ii、再逐行解读运行
(这里和外层的逐行解读代码是一样的。)
如果在函数内部使用了没有使用var声明的变量(当前作用域内没有定义的变量即自由变量),那么内部函数就会往函数外去寻找这个变量(所谓的由内向外查找)。

在逐行解读代码的时候(如果遇到函数的定义(也就是函数声明)就直接忽略了,因为又不是表达式,又不是函数调用的)

三、例子解析

上面就是讲解了JavaScript语言预解析和执行的流程了,那么我们来看些例子来理解实践一下。

例1:(先思考下为什么这样输出,结合上面的解析)

console.log(a); // ƒ a(){ console.log("函数2") }
var a = 1;
console.log(a); // 1
function a(){ console.log("函数1") }
console.log(a); // 1
var a = 2;
console.log(a); // 2
function a(){ console.log("函数2") }
console.log(a); // 2

解析:
1、(找出一些关键字初始赋值,代码从上到下查找)如:var、函数、函数参数

找到第2行的 var a,此时a = undefined;
遇到第4行的函数声明a (pk同名函数胜),此时a = function a(){ console.log(“函数1”) };
遇到第6行的var a (pk同名函数胜),此时a = function a(){ console.log(“函数1”) };
遇到第8行的函数声明a (pk后来者同名函数胜),此时a = function a(){ console.log(“函数2”) };

2、逐行解读代码
(在这步时遇到函数的声明就直接忽略了,因为又不是表达式,又不是函数调用的)

读到第1行console.log(a); ,此时打印出 f a(){ console.log(“函数2”) }; (f代表function)
读到第2行var a = 1; ,把a重新赋值为1;
读到第3行console.log(a); ,此时打印出 1;
读到第4行为函数的声明,直接忽略;
读到第5行console.log(a); ,此时打印出 1;
读到第6行var a = 2; ,把a重新赋值为2;
读到第7行console.log(a); ,此时打印出 2;
读到第8行为函数的声明,直接忽略;
读到第9行console.log(a); ,此时打印出 2;

从上面分两部份分析,就很清晰了。更多复杂的例子,就按照这两大步骤去分析就容易理解了。

例2:自由变量

var a = 100;
function fn(){
	var b = 200;
	// 变量a在当前函数作用域没有定义,即“自由变量”
	console.log(a); // 100
	console.log(b); // 200
}
fn();

自由变量(当前作用域内没有定义的变量即自由变量)在当前作用域内找不到时,就会依次顺着作用域链往父辈作用域找。
函数的父级作用域就看函数是在哪个作用域内定义的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值