前端|想到什么写什么
记录当初伤害过我的一些概念😊
一、闭包
var i = 0;
function a() {console.log(i);
}
a();
// 这就是一个简单的闭包,该函数使用了外部的数据
我们先说一下闭包的特点:
(1)通过闭包可以让外部环境访问到函数内部的局部变量。
(2)通过闭包可以让局部变量持续保存下来,不随着它的上下文环境一起销毁。
理解闭包以及它的特点我们需要先了解两个概念:
(1)作用域链:比如你在一个函数中用到了一个变量,但是在当前作用域中没有找到它的值,就会向上级作用域去查,直到查到全局作用域,这个过程就形成了一条作用域链。
(2)垃圾回收:垃圾收集器会周期性地找出那些不再使用的变量,然后释放其内存。如果该变量还在使用,那么就不会被回收。
然后我们来看个栗子:
function a() {var i = 0;
}
a();
console.log(i); // 报错i is not defined
输出会报错,为什么?因为执行完a函数后,i 作为局部变量不再使用会被销毁(垃圾回收),所以在输出就会报错not defined。
function a() {var i = 0;return function b() {console.log(i); // 输出0}
}
var c = a();
c();
显而易见,b函数中用到了a函数中的变量,于是形成了闭包。为什么执行完a函数后i 没被销毁呢?因为执行完a函数后,函数b被赋值给了c,c是全局变量不会被销毁,也就是函数b中的i 还会继续被使用,所以不会被回收。可以看出外部环境也可以访问到函数内部的局部变量。
理解完这个🌰再回看它的概念以及特点就比较好理解了,同时也会发现由于变量不会被销毁,所以过度的使用闭包就可能会产生内存泄漏的问题。
完事儿来做两个题吧!!:
(1)请补全JavaScript代码,要求每次调用函数"closure"时会返回一个新计数器。每当调用某个计数器时会返回一个数字且该数字会累加1。
注意:1. 初次调用返回值为1;2. 每个计数器所统计的数字是独立的。
//来自牛客网上的一道js题
<!DOCTYPE html>
<html><head><meta charset=utf-8></head><body><script type="text/javascript">const closure = () => {// 补全代码}</script></body>
</html>
答案(没有标准答案哦,实现就行):
const closure = () => {var i = 0;return function () {return ++i;}}
let a = closure();
a();
(2)执行以下代码,会输出什么结果?
for (var i = 1; i <= 3; i++) {setTimeout(function () {console.log(i);}, 1000);
}
答案: 4 4 4
解析:在匿名函数中使用了外部变量i ,形成了闭包,匿名函数在1s后执行,因为是闭包所以在循环结束后依然可以访问到i ,此时i 已经变成4(i =4后,不符合条件,才停止循环),所以就会输出三个4。
扩展:如何可以输出1 2 3呢?最简单的办法把var写成let即可。
二、深拷贝、浅拷贝、直接赋值
三、slice、splice、split、filter
四、for in和for of、 map和foreach
五、原型和原型链
六、vuex和pinia
七、跨域
八、await、promise
九、computed和watch
十、原型和原型链
十一、
等我明天补充!