文体两开花 ,说道闭包就必须要说下作用域;说道作用域我就想到了作用域链,说道作用域链,我就想到了执行期上下文,说道执行期上下文,我就想到了预编译。所以为了说下闭包,就得从预编译说起。(第二次写文章,文笔不怎么好,加上内容本身难度挺大,请多多包涵,仔细阅读,看懂每一个字,理解图片中的每一个字)
一:预编译
众所周知js两大特点 1.单线程;2.解释执行(解释一行,执行一行)。那么问题来了 如下代码的输入结果是什么?
console.log(a,b)
function a(){}
var b = 0;复制代码
解释一行执行一行, 第一句直接console.log(a,b), 还没有执行到他们的 声明语句,那结果会不会是 xxx is not defient 。 明显不是,稍微有点基础的人都知道 var 和 函数声明会有提升。 这个提升为 函数声明整体提升 , 变量 声明提升。这个提升的过程就是发生在预编译。但是预编译不止这些。
先介绍一波知识点:
js运行三部曲:- 语法分析
- 预编译
- 解释执行
对函数:预编译发生在函数执行前一刻;
对整js :预编译发生在全局执行的前一刻;
那么问题来了:函数声明和变量声明都提升谁的优先级高呢?
看码:
function fn(a) {
console.log(a)
console.log(b)
var a = 123;
console.log(a)
function a(){}
var b = function(){}
console.log(b)
function d (){}
}
fn(1)复制代码
上面的代码分别输出什么,可以自己先看看有了答案,再往下看。
在回答上面的问题前先列出 函数预编译4步曲:
- 创建AO对象
- 找到形参和变量声明,将变量和形参作为AO属性名,属性值为undefined
- 找到实参的值,赋值给形参
- 函数体里面找到函数声明, 值为函数体
全局的预编译,省略 2.的找形参和 3步的实参和形参统一;
现在来回答上面的问题:
下面给出2个题,然后结束预编译。(大家可以先自己坐下,再去自己打下代码,如果跟自己的答案个控制台输出有出入,就看再看看4部曲再做做。熟悉了再往下看哟)
console.log(test);
function test(test) {
console.log(test)
var test = 234;
console.log(test)
function test(){}
}
test(1)
var test = 123;复制代码
function test (a,b){
console.log(a);
c = 0;
a = 3;
b = 2;
console.log(b);
function b(){}
function d(){}
console.log(b)
}
test(1);复制代码
二:作用域,作用域链
来看码:
function a() {
function b(){
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();复制代码
第二步:a执行,生成了自己的AO,插入到了[[scopes]] 0 位GO 往后延
第三步:a执行引起的b的定义,这个时候b继承了a的劳动成果,直接把a的生成的作用域链的引用拿来挂到自己的身上。这个时候 b.scope[0] 指向的AO和 a.scope[0] 指向的AO是同一个。(结合一下自己写代码就能知道,在子函数里面改变了外部函数的值,外部函数的值也改变了)
第四步:b函数执行,生成了自己的AO,把自己的AO插入到刚刚获取的作用域链
function a (){
function b(){
function c(){
}
c();
}
b();
}
a();复制代码
看了这个例子,大家应该能明白点了,(如何还没明白,怪我,第二次写文章,表达不好) 上面所有的AO和BO 都是一个AO和BO,他们拿到地址指向后就可以直接用,一个修改全部都被修改。
三: 文体两开花 ,终于到了 闭包
讨论之前,先说一句话,一句开始我加粗了的话 :当函数执行完毕,执行上下文被销毁
function a () {
function b() {
var bbb = 234;
console.log(aaa)
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();复制代码
到这里文体两开花学闭包就结束了。至于闭包的用处和规避措施。大家就可以网上搜索了,很多。(如何没有看懂,是我的问题,文笔太差, 大家多多包涵,有问题欢迎评论区 指出,我看到就会马上回复,谁叫我没工作呢)。
最后祝各位前端攻城师们都能对js了如指掌,虽然很多js的一些特性(或者说缺陷)确实恶心,但是说不定哪一天就被触发了,如果对这些不了解,那bug是真的找不到了。
ps:最后的最后打个广告,本人普通二本软件工程大四学生,js基础还行,了解一点node,其他的前段技术也多多少少了解点。正在找一份前端开发的工作,坐标成都。希望有找人的大佬,给点内推,面试机会。谢谢大佬们。