先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
每次执行A函数时,都会生成一个A的活动变量和执行环境,执行完毕以后,A的执行环境销毁,但是活动对象由于被闭包函数引用,所以仍然保留,所以,最终剩下两个A的变量对象,因此m1和m2在操作x时,指向的是不同的数据,
现在来回答三个问题:
1.(为什么连续执行m1的时候,x的值在递增?)
answer:因为m1在引用的活动对象A一直没有释放(想释放的话可以让m1=null),所以x的值一直递增。
2.定义函数m2的时候,为什么x的值重新从1开始了?
answer:因为又一次运行了A函数,生成一个新的A的活动对象,所以m2的作用域链引用的是一个新的x值。
3.m1和m2里面的x为什么是相互独立,各自维持的?
answer:因为在定义m1和m2的时候,分别运行了A函数,生成了两个活动对象,所以,m1和m2的作用域链是指向不同的A的活动对象的。
好的,到这里先回顾一下前面说到的知识点:
执行环境和变量对象在运行函数时生成
执行环境中的所有代码执行完以后,执行环境被销毁,保存在其中的变量和函数也随之销毁;(全局执行环境到应用退出时销毁)
感觉理解了吗?接下来,再看看另一个很类似的例子:
这个例子和刚刚十分类似,不同的是,在A内部就先定义了两个函数,可以看出 ,最后的结果与上面的例子有些不同:
变量x仍然能保持递增,但是m[0]和m[1]定义的函数,对于x的改变不再是相互独立的,其实大家估计猜到了,这里的m[0]和m[1]的作用域指向的A的变量对象,其实是同一个,为什么呢?很简单,看看刚刚这段代码,其实是只调用了一次A函数,再看上文那句话:
执行环境和变量对象在运行函数时生成
既然A只执行一次,那么A的活动变量当然也就生成了一个,所以这里m[0]和m[1]的作用域指向同一个A的变量对象
这个例子其实算是一个经典案例,在很多地方都有提到,执行完毕后 funs数组中,funs[0]-funs[9]存的其实都是一样的,都是一个返回i值的函数,这个例子容易错误的地方其实在于,弄错了产生执行环境的时机,还是看这句话:
执行环境和变量对象在运行函数时生成
所以,当执行 var funs = A();时,只是定义函数,而没有执行,真正产生环境变量的时间是在console.log(funs0);这三句的时候,此时A的变量对象中i值是什么呢?很简单,看它return的时候,i的值,显然,i的值是10,所以,最后三句输出的都是10
==========================================================================
1.模仿块级作用域
首先简单举个例子来,解释一下什么是块级作用域:
function A(num) {
for (var i = 0; i < num; i++) {
num++;
}
console.log(i)
}
在这个简单的函数中,变量i是在for循环中定义的,如果是在C++或者Java中,这样定义的变量,一旦循环结束,变量也就随之销毁,i的作用范围只在循环这个小块,就称为块级作用域。在javascript中,没有这样的块级作用域,前面一篇文章已经提到,变量是定义在函数的活动对象中的,因此,从定义i开始,在函数内部可以随时访问它。
这样的坏处显而易见:由于javascript不会告诉你变量是否已经被声明,容易造成命名冲突,如果是在全局环境定义的变量,就会污染全局环境,因此可以利用闭包特性来模拟块级作用域。不过在此之前要先介绍另一个知识点:匿名立即执行函数。如果已经比较熟悉的同学可以直接跳过这一块:
匿名立即执行函数
首先举个例子(我比较喜欢举例,感觉看例子比较更容易理解):
var helloWorld = function(){
alert(‘Hello world’)
}
helloWorld();//执行函数
上面的简短代码一共就做两件事:1.定义了一个匿名函数并赋值给helloWorld;2.在helloWorld后面加括号表示调用函数,所以 匿名函数如果直接执行,是不是应该这样写:
function(){
alert(‘Hello world’)
}()
这样的写法会报错,因为在javascript中,function是函数声明的标志,不允许在后面直接加括号,而应该写成这样:
(function(){
//函数体
alert(‘Hello world’)
})()
也就是把声明部分加括号即可,加了括号以后,这一段代码就相当于执行了里面的函数体部分,但是此时内部的变量已经不能被外部访问
具体实现
现在我们讲模拟块级作用域的具体步骤,假设还是针对前面的A函数,如果我们想让i变量只有块级作用域,可以这样写:
function A(num) {
//核心代码
(funnction(){
for(var i = 0; i<num; i++) {
num++;
}
})()
//核心代码结束
console.log(i)//underfined
}
注意看核心代码部分,我们用刚刚讲到的匿名自执行函数在内部形成了一个闭包,这个闭包在哪呢?一直强调,闭包的本质是函数,其实在这里闭包就是那个匿名函数,这个闭包可以到函数A内部的活动变量,又能保证自己内部的变量在自执行后直接销毁,这个应该不难理解了
2.存储变量
我们知道闭包的另一个特点是可以保存外部函数的变量,原理是基于javascript中函数作用域链的特点,内部函数保留了对外部函数的活动变量的引用,所以变量不会被释放(这一块没有理解清楚的请看前一篇文章,里面讲的比较详细),然后我们再来愉快地举例子:
function B(){
var x = 100;
return {
function(){
return x
}
}
}
var m = B()//运行B函数,生成活动变量 x被m引用
总结
阿里十分注重你对源码的理解,对你所学,所用东西的理解,对项目的理解。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
8e3063bbc4ddc4fe929112c8.png)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-3r8CIQQD-1713321056740)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!