闭包
//闭包:我们fun 这个函数作用域 访问了另外一个函数 fn 里面的局部变量 num
//被访问的局部变量所在的函数,就叫做闭包函数
function fn() {
var num = 10;
function fun() {
console.log(num);
}
fun();
}
fn();
闭包就是高阶函数,返回的是一个函数
function fn() {
var num = 10;
//function fun() {
// console.log(num);
//}
//return fun;
return function() {
console.log(num);
}
}
var f = fn();
// console.log(f);
f();
// 类似于
// var f = function fun() {
// console.log(num);
// }
闭包的主要作用:延伸了变量的作用范围
利用闭包的方式得到li的索引号(重要)
for (var i = 0; i < lis.length; i++) {
//利用for循环创建了4个立即执行函数
(function(i) { //这个里面的i是由下面的i传递进来的
// console.log(i);
lis[i].onclick = function() {
console.log(i);
}
})(i);
下面的代码块无法达到预期效果的原因:因为function是异步任务,而for是同步任务。所以function先不执行,等按下按钮才执行。而for循环之后 i 就变为了 4 所以按哪个按钮都会打印出 4 。
for (var i = 0; i < lis.length; i++) {
//利用动态添加属性的方式 添加一个索引号
// lis[i].index = i;
lis[i].onclick = function() {
// return i;
console.log(i);
// console.log(this.index);
}
}
闭包定时器 3秒后同时打印出来li
var lis = document.querySelector('.nav').querySelectorAll('li');
// for (var i = 0; i < lis.length; i++) {
// setTimeout(function() {
// console.log(lis[i].innerHTML);
// }, 3000)
// } 异步任务, i = 4 ,4的innerHTML不存在,所以报错
for (var i = 0; i < lis.length; i++) {
(function(i) {
setTimeout(function() {
console.log(lis[i].innerHTML);
//逐步打印第i个,
}, 3000)
})(i);
}
闭包应用-计算打车价格
有些函数,想要立即执行,不需要调用函数再执行,使用立即执行函数就可以
//闭包应用-计算打车价格
//打车计步价13(3公里内),之后每多一公里增加5块钱,用户输入公里数就可以计算打车价格
//如果有拥堵情况,总价格多收取10块钱拥堵费
var car = (function() {
var start = 13; //起步价 局部变量
var total = 0; //总价 局部变量
return {
price: function(n) { //使用了start,当函数使用了另一个函数的局部变量就会产生闭包,此时这个匿名函数就是闭包
if (n <= 3) {
total = start;
} else {
total = (n - 3) * 5 + start
}
return total;
}, //正常总价
yd: function(flag) {
return flag ? total + 10 : total;
} //拥堵之后的费用
}
})();
console.log(car.price(5)); //23
console.log(car.yd(true)); //33
console.log(car.price(1)); //13
console.log(car.yd(false)); //13
闭包总结
闭包是一个函数(一个作用域可以访问另外一个函数的局部变量)
闭包的作用:延伸变量的作用范围(因为局部变量用完立即销毁)
递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
简单理解:函数内部自己调用自己这个函数就是递归函数
递归函数的作用和循环效果一样
由于递归很容易发生“栈溢出”错误,所以必须要加退出条件 return
利用递归函数求 1~n 的阶乘 12345*…n
//利用递归函数求 1~n 的阶乘 1*2*3*4*5*..n
function fn(n) {
if (n == 1) {
return 1;
}
return n * fn(n - 1);
}
console.log(fn(3));
利用递归函数求斐波那契数列(兔子序列)1、1、2、3、5、8…
//利用递归函数求斐波那契数列(兔子序列)1、1、2、3、5、8...
//用户输入一个数字 n 就可以求出 这个数字对应的兔子序列值
function fn(n) {
if (n === 1 || n === 2) {
return 1;
}
return fn(n - 1) + fn(n - 2);
}
console.log(fn(6));
利用递归求:根据id返回对应的数据对象
<script>
//利用递归求:根据id返回对应的数据对象,不是直接打印是返回
var data = [{
id: 1,
name: '家电',
goods: [{
id: 11,
gname: '冰箱',
goods: [{
id: 111,
gname: '海尔'
}, {
id: 112,
gname: '海饿'
}
]
}, {
id: 12,
gname: '洗衣机'
}]
}, {
id: 2,
name: '服饰'
}];
//1.利用forEach 去遍历里面的每一个对象
function getID(json, id) {
json.forEach(function(item) {
// console.log(item);
if (item.id == id) {
o = item;
return item;
// console.log(item);
//得到里层的数据 11 12 利用递归函数
//里面应该有goods这个数组并且数组的长度不为0
} else if (item.goods && item.goods.length > 0) {
o = getID(item.goods, id);
}
});
return o;
}
console.log(getID(data, 11));
console.log(getID(data, 1));
console.log(getID(data, 2));
console.log(getID(data, 12));
console.log(getID(data, 111));
</script>
深拷贝与浅拷贝
- 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用(地址)
- 深拷贝拷贝多层,每一级别的数据都会拷贝
- ES6新增方法可以浅拷贝 Object.assign(target,source)
-
- 深拷贝,开辟一个新内存,复制过来
- 深拷贝
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
//判断我们的属性值属于哪种数据类型
//1.获取属性值
var item = oldobj[k];
//判断这个值是否是数组 数组一定要在对象上面 因为万物皆对象 所以数组会被当对象解析
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
//判断是否是对象
} else if (item instanceof Object) {
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
//属于简单数据类型
newobj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);