JavaScript
是解释性语言,也就是说,编译一行,执行一行,但js
并非上来就进入编译环节,它在编译之前存在预编译过程。
js
中预编译一般有两种:全局的预编译和函数的预编译,分别发生在script
内代码执行前和函数的执行前。
首先来看一个例子:
function test(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
var b = function() {}
console.log(b);
function d() {}
}
test(1)
就以上述例子中的a为例,有形参a,变量a,函数a,那test函数执行时,此时的a到底是什么呢?
输出结果:
ƒ a() {}
123
123
ƒ () {}
要想弄明白最终的输出结果,就不得不好好学习一下预编译的详细过程。
在预编译学习中,经常听到一句话:函数声明整体提升,变量声明提升。
这句话可以解决大多数场景下的预编译问题,但光凭这句话无法理解透预编译,接下来我们来一起捋一下函数预编译的大致流程。
函数预编译四部曲
-
预编译开始,会建立
AO(Activation Object)
对象 -
找形参和变量声明,使其作为
AO
的属性名,值赋予undefined
-
实参和形参相统一(将实参值赋值给形参)
-
找函数声明,函数名作为
AO
属性名,值赋予函数体
案例分析
学习了函数的预编译过程,就可以回头细细的品味一下上面的案例:
AO :{
a: undefined,
b: undefined
}
AO :{
a: 1,
b: undefined
}
AO :{
a: function a() {},
b: undefined,
d: function d() {}
}
第一个console.log(a); // 此时AO中a的值为function a() {}
执行赋值操作:
a = 123 // AO中的a值修改为123
第二个console.log(a) // 123
第三个console.log(a) // 123
b = function() {} // AO中的b值修改为function b(){}
console.log(b) // function b(){}
全局中不存在形参和实参,所以只需处理变量声明和函数声明
全局预编译三部曲
-
生成
GO(Global Object)
-
找变量声明,由于全局变量默认挂载在
window
之上,若window
当前已存在当前属性,忽略当前操作,若没有,变量作为属性名,值赋予undefined
。 -
找函数声明,函数类似与变量,先去
window
上查看,不存在,函数作为函数名,值为函数体
案例分析
将函数预编译案例稍微修改,如下:
// test部分的结果与函数部分相同,再次只分析全局部分
console.log(a);
var a = 1;
console.log(a);
function test(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
console.log(b);
var b = function() {}
console.log(b);
}
test(2);
GO/window: {
a: undefined,
test: function() {}
}
- 因此第一个
a
的值为undefined
,随后a
赋值为1
,所以第二个a
的值为1
test中定义了变量a,因此打印的a为自身AO中的值。如果test中没有定义a,就会沿着作用域链,当GO中查找a。
1. 当函数中出现同样名称的函数名和变量名,编译器真的会先做变量提升再去函数提升吗?查看了一些大佬的博客,当出现变量名和函数名相同时,变量提升应该会被忽略掉,不会做重复的无用之功
2. let/const声明的变量应当同样进行了变量提升,只不过它与var声明的变量做了一定的区分
题目一
function test() {
console.log(b);
if (a) {
var b = 100;
}
console.log(b);
c = 234;
console.log©;
}
var a;
test();
a = 10;
console.log©;
GO: {
a: undefined,
test: function test() {},
c: undefined
}
JavaScript中变量如果未经声明就赋值,会默认将变量挂载到window对象上,这也就是所谓的
imply global
。c就是imply global
。
// AO还会存储[[scope]]属性,存储AO的作用域链
AO: {
b: undefined,
[[scope]]: [TestAO, GO]
}
有同学会问,
if(a)
为false,if内部不会执行,那test的AO中为什么还会有b啊?预编译并不是执行,它只不过把变量、函数等进行提升,只有在执行时,才会设计代码逻辑的判断。
console.log(b) // AO中b为undefined
if (a) // AO中无a,沿[[scope]]找到GO中的a,值为undefined
b = 100; // 不执行
console.log(b) // undefined
c = 234; // AO中没有c属性,沿[[scope]]找到GO中的c修改为234
console.log© // 打印的是GO中的c,234
// test执行完毕,AO销毁
a = 10; // GO中的a修改为10
console.log© // GO中c值为234,234
题目二
var foo = 1;
function bar() {
console.log(foo);
if (!foo) {
var foo = 10;
}
console.log(foo);
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-wUWoABBS-1714910768474)]
[外链图片转存中…(img-LHxoFjal-1714910768475)]
[外链图片转存中…(img-bSBL5D89-1714910768475)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!