JS预解析笔记
要明白JS预解析的运作方式,可以简单理解成两点:将声明语句提前执行,包括变量声明、函数声明、函数参数。其中函...
要明白JS预解析的运作方式,可以简单理解成两点:
- 将声明语句提前执行,包括变量声明、函数声明、函数参数。其中函数参数就相当于函数内局部变量声明。
- 重新回到开始逐行解读代码,顺序是:从左到右、从上到下。
alert(a);
alert(fn);
var a = 1;
function fn(){
return false;
}
/*
预解析过程:
1. 变量与函数提至作用域前面,变量赋值”未命名“,函数依旧是其完整函数块
2. 逐行解读代码,读到alert(a);时,返回检查此前提前的”var a “的值,验证为undefined,则alert(a)弹出undefined。alert(fn)同理。
var a = undefined;
function fn(){
return false;
}
alert(a); //undefined
alert(fn); //fn函数整个代码块
*/
//示例 1 解释
var a; // a 变量 提前到整个作用域的前面 当前值 为 undefind。
function fn(){
return false;
}; // fn 函数 提前整个作用域的前面 当前值 就是整个函数块。
alert(a); // undefind。
alert(fn); // function 整个函数块。
a=1; // a 赋值 1 现在 a 变量才拥有 值:1
function fn(){
return false;
}; // 函数一直没变,只不过被提前到作用域的前面去了。
// 需要注意的是函数在那定义不重要,重要的是在那调用。
// (因为定义完以后它都会被提前到当前作用域的前面,所以函数在哪调用就在哪个作用域生效)
var a; // a 变量 提前到整个作用域的前面 当前值 为 undefind。
function fn(){
return false;
}; // fn 函数 提前整个作用域的前面 当前值 就是整个函数块。
alert(a); // undefind。
alert(fn); // function 整个函数块。
a=1; // a 赋值 1 现在 a 变量才拥有 值:1
function fn(){
return false;
}; // 函数一直没变,只不过被提前到作用域的前面去了。
// 需要注意的是函数在那定义不重要,重要的是在那调用。
// (因为定义完以后它都会被提前到当前作用域的前面,所以函数在哪调用就在哪个作用域生效)
再来个例子2:
alert(a);
var a = 1;
alert(a);
function a(){
return false;
}
/*
首先还是两步走,变量与函数提前,
var a = undefined;
function a(){
return false;
}
这里就要注意,是不是发现函数名和之前的变量名重名了?这咋办?
根据JS解析器的规矩,后出来的同名函数会覆盖先出来的同名变量,
所以此时提到作用域(全局变量)前面的,只有函数名为a的函数块。
接下来就是逐行解读代码了,先是第7行alert(a)了,结果就弹出个a函数块来。
下面又要注意了,此时代码解析到第8行var a=1; 这明显又要走一波预解析提前的套路啊,此时a被赋值1。果然是三十年河东三十年河西,这下轮到a=1来覆盖原先的a函数块了。
所以第9行的alert(a)就弹出值 1。
下面第10行的函数块由于没有执行口子,所以代码执行就到此为止了。
*/
示例2:解释
var a; // 首先提前 变量 当前值 为:undefind。
function a(){
return false;
}; // 遇到函数 提前函数 注意:当前函数命 和 上面的变量名 一样 竟然一样怎么办呢?
// 不要急 js解析器已经做了处理 同名的函数会替换掉 同名的 变量 现在就只剩下 a 函数块 自己了。
alert(a); // 因为 上面 只剩下 a 函数了 所以现在就弹出 a函数的整个函数块。
a = 1; // a = 1 表达式赋值 所以就又把 a 函数给替换成了 变量 值为:1。
alert(a); // 现在 弹出 的值就是被改变过的 a 值为 1;
function a(){ // 这个函数现在就没用了。
return false;
};
var a; // 首先提前 变量 当前值 为:undefind。
function a(){
return false;
}; // 遇到函数 提前函数 注意:当前函数命 和 上面的变量名 一样 竟然一样怎么办呢?
// 不要急 js解析器已经做了处理 同名的函数会替换掉 同名的 变量 现在就只剩下 a 函数块 自己了。
alert(a); // 因为 上面 只剩下 a 函数了 所以现在就弹出 a函数的整个函数块。
a = 1; // a = 1 表达式赋值 所以就又把 a 函数给替换成了 变量 值为:1。
alert(a); // 现在 弹出 的值就是被改变过的 a 值为 1;
function a(){ // 这个函数现在就没用了。
return false;
};
例子3,是讲函数参数的,前面说过可以把函数参数理解成函数内的局部变量,这样便于理解。
var a = 1;
function fn1(a){
alert(a);
a=2;
}
fn1();
alert(a);
/*
老规矩,先预解析参数、函数和变量提前,
var a=undefined; //变量赋值undefined
function fn1(a){ //原装函数块奉上
alert(a);
a=2;
}
再来个逐行解读代码:
var a = 1;
读到fn1函数块,发现里面有参数,好!再来一遍预解析:
a = undefined;
接下来到12行了,fn1()执行的就是函数内最终返回值,此时函数局部作用域内从上到下开始执行代码,先是第9行alert(a), 返回值为undefined,再下面a=2就没有用,不去管它,所以fn1()函数的执行结果是弹出undefined。
最后读到alert(a);由于此时全局作用域中变量a已经被赋值1,所以最终弹出值1
*/
function fn1(a){
alert(a);
a=2;
}
fn1();
alert(a);
/*
老规矩,先预解析参数、函数和变量提前,
var a=undefined; //变量赋值undefined
function fn1(a){ //原装函数块奉上
alert(a);
a=2;
}
再来个逐行解读代码:
var a = 1;
读到fn1函数块,发现里面有参数,好!再来一遍预解析:
a = undefined;
接下来到12行了,fn1()执行的就是函数内最终返回值,此时函数局部作用域内从上到下开始执行代码,先是第9行alert(a), 返回值为undefined,再下面a=2就没有用,不去管它,所以fn1()函数的执行结果是弹出undefined。
最后读到alert(a);由于此时全局作用域中变量a已经被赋值1,所以最终弹出值1
*/
示例3:解释
var a; // a 变量 提前 当前值:undefind。(全局变量)function fn1(a){
alert(a);
a = 2;
}; // fn1 函数块提前 值为: 整个函数
// 该提前的都提前的现在开始 逐行 解读代码,
// 等等 有人会说那 参数 呢? 哈哈哈 不要着急还没到它呢。
var a = 1; // a = 1 赋值表达式 改变 变量 a 值为:1。function fn1(a){
var a; //参数被当成变量 解析到当前函数 顶部。
alert(a); // a 当前函数内 a 值为:undefined.
a = 2; // a = 2 复制表达式 无用
}; // 函数块 没有遇到调用 无用。
fn1(); // 现在遇到函数fn1 的调用了 咱们就去它里面看看 。
// 调用成功后 弹 undefind。
alert(a); // 这个 还是调用 全局的变量 a 值 为 1。
var a; // a 变量 提前 当前值:undefind。(全局变量)function fn1(a){
alert(a);
a = 2;
}; // fn1 函数块提前 值为: 整个函数
// 该提前的都提前的现在开始 逐行 解读代码,
// 等等 有人会说那 参数 呢? 哈哈哈 不要着急还没到它呢。
var a = 1; // a = 1 赋值表达式 改变 变量 a 值为:1。function fn1(a){
var a; //参数被当成变量 解析到当前函数 顶部。
alert(a); // a 当前函数内 a 值为:undefined.
a = 2; // a = 2 复制表达式 无用
}; // 函数块 没有遇到调用 无用。
fn1(); // 现在遇到函数fn1 的调用了 咱们就去它里面看看 。
// 调用成功后 弹 undefind。
alert(a); // 这个 还是调用 全局的变量 a 值 为 1。
关注 捡贝壳
微信扫一扫关注公众号