1.闭包
1.1 变量作用域
- 函数内部可以使用全局变量。
- 函数外部不可以使用局部变量。
- 当函数执行完毕,本作用域内的局部变量会销毁
1.2 什么是闭包
闭包指有权访问另一个函数作用域中变量的函数。-----红宝书
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。 闭包就是一个典型的闭包函数。
<script> function fn() { var num = 10; function fun() { console.log(num); } fun(); } fn(); </script> 复制代码
这就是一个闭包,我们可以利用Chorme调试工具来查看是否产生闭包。
看,出现了closure,由此可见fn()就是一个闭包
1.3 闭包的主要作用
延伸了变量的作用范围
1.4 闭包的案例
循环注册点击事件
用立即执行函数解决,立即执行函数也称为小闭包
<body> <ul> <li>苹果</li> <li>梨子</li> <li>草莓</li> <li>西瓜</li> <li>樱桃</li> </ul> <script> var lis = document.querySelectorAll("li") for (var i = 0; i < lis.length; i++) { (function (i) { lis[i].onclick = function () { console.log(i); } })(i) } </script> </body> 复制代码
循环中的setTimeout()
<body> <ul> <li>苹果</li> <li>梨子</li> <li>草莓</li> <li>西瓜</li> <li>樱桃</li> </ul> <script> // 闭包应用——3秒钟之后,打印所有li元素的内容 var lis = document.querySelectorAll("li") for (var i = 0; i < lis.length; i++) { (function (i) { setTimeout(() => { console.log(lis[i].innerHTML); }, 3000); })(i) } </script> </body> 复制代码
计算打车价格
要求:
- 起步价13(3公里内),之后每多一公里增加5块钱,用户输入公里就可以计算打车价格
- 如果有拥堵情况,总价格多收取10块钱拥堵费
<script> var car = (function () { var start = 13; var total = 0; return { price: function (n) { if (n <= 3) { total = start; } else { total = (n - 3) * 5 + start; } return total; }, yongdu: function (flag) { return flag ? total + 10 : total; } } })(); console.log(car.price(5)); console.log(car.yongdu(true)); </script> 复制代码
我们发现上面三个案例中都使用了闭包
2.递归
2.1 什么是递归?
如果一个函数在内部调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己,这个函数就是递归函数。
递归函数的作用和循环作用效果一样
由于递归很容易发生栈溢出错误,所以必须加退出条件return
<script> var num = 1; function fn() { console.log('我要打印6句话'); if (num == 6) { return; } num++; fn(); } fn(); </script> 复制代码
2.2 用递归求数学题
1.求5的阶乘
<script> function fn(n) { if (n == 1) { return 1 } return n * fn(n - 1) }; console.log(fn(5)); </script> 复制代码
2.求斐波那契数列1、1、2、3、5、8、13、21
用户输入一个数字n就可以求出 这个数字对应的兔子序列值
<script> function fib(n) { if (n == 1 || n == 2) { return 1; } return fib(n - 1) + fib(n - 2) }; console.log(fib(4)); </script> 复制代码
2.3 浅拷贝与深拷贝
- 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
- 深拷贝拷贝多层,每一级别的数据都会拷贝。浅拷贝:
// 浅拷贝的第一种写法 <script> var obj = { id: 1, name: 'andy' }; var o = {}; for (var k in obj) { // k是属性名 obj[k]是属性值 o[k] = obj[k] } console.log(o); </script> // 浅拷贝的第二种写法 <script> var obj = { id: 1, name: 'andy' }; var o = {}; Object.assign(o,obj); console.log(o); </script> 复制代码
深拷贝:
手写深拷贝函数
<script> var obj = { id: 1, name: 'andy', msg: { age: 18 }, color: ['pink', 'red'] }; var o = {}; // 封装函数 function deepCopy(newobj, oldobj) { for (var k in oldobj) { // 判断我们的属性值属于哪种数据类型 // 1.获取属性值 oldobj[k] var item = oldobj[k]; // 2.判断这个值是否是数组 if (item instanceof Array) { newobj[k] = []; deepCopy(newobj[k], item) } else if (item instanceof Object) { // 3.判断这个值是否是对象 newobj[k] = {}; deepCopy(newobj[k], item) } else { // 4.属于简单数据类型 newobj[k] = oldobj[k]; } } } deepCopy(o, obj) </script> // 数组放在第一位的原因是数组也属于对象。