作用域
- 以一座城市作为类比

全局作用域
- 只有一个,作用范围辐射整个程序,在程序运行时一直存在
函数作用域
- 作用范围函数内部及其子函数
- 作用域的查找只能向上查找
- 每次调用都会产生一个新的环境,例如:
function hd() {
let n = 1;
function sum() {
console.log(++n);
};
sum();
}
hd(); // 1
hd(); // 1

- 要保留原有的环境,就要让其中的引用类型还在被使用(基本类型不行)
function hd() {
let n = 1;
return function sum() {
console.log(++n);
};
}
let a = hd();
a(); // 1
a(); // 2
let b = hd();
b(); // 1
b(); // 2

- 在嵌套一层函数
function hd() {
let n = 1;
return function sum() {
let m = 1;
function show() {
console.log(++n);
console.log(++m);
}
show();
};
}
let a = hd();
a(); // n: 2 m:2
a(); // n: 3 m:2
let/const
let/const可以变量声明在作用域块中
{
let a = 10;
}
console.log(a); //报错
for(let i=1; i<3; i++) {
setTimeout(function() {
console.log(i);
},1000);
}
// 1 2
// 每迭代一次,就会产生一个新的块级作用域。而let 具有块级作用域,且还会被定时函数所使用,就会出现上述结果
var只有全局和函数作用域
for(var i=1; i<3; i++) {
setTimeout(function() {
console.log(i);
},1000);
}
// 3 3
// var无块级作用域的概念,直接放在全局作用域。每次迭代造成的改变都会直接影响它的值
- `var模拟块级作用域
for(var i=1; i<3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
},1000);
})(i);
}
// 理念:函数每执行一次会开辟一个新的函数作用域,而因为后面定时函数还会使用该函数中的值,该函数的作用域是不会被回收的
闭包
- 闭包:指有权访问另一个函数作用域中的变量的函数
- 例子:选定某一个价格区间的商品
var goods = [ {name: "ipod",price: 400},
{name: "pen",price: 50},
{name: "orange",price: 1},
{name: "ipad", price: 3000}]
function selectePrice(a,b) {
return function(v) {
return v.price>=a && v.price<=b;
}
}
let a = 10;
let b =300;
console.log(goods.filter(selectePrice(a,b)));
- 动画的抖动
let btns = document.querySelectorAll("button");
btns.forEach(function(item){
item.addEventListener("click",function() {
let left = 1;
setInterval(function() {
item.style.left = left++ + "px";
},100)
})
})
原因是:每次点击产生新的函数作用域,都是left=1,当上一个点击产生的定时器执行到的时候left突然就会便的很大,再次执行到另一个定时器函数又会变小,发生抖动。

let btns = document.querySelectorAll("button");
btns.forEach(function(item){
let left = 1;
item.addEventListener("click",function() {
setInterval(function() {
item.style.left = left++ + "px";
},100)
})
})
不能存在抖动问题了,但是点击次数越多,速度越快,原因是left所有定时器产生的函数都可以修改,点击之后一个定时器修改后,还未到达该定时器下一次执行的时间,但是到达了其他定时器函数执行的时间又会修改

let btns = document.querySelectorAll("button");
btns.forEach(function(item){
let start = false;
item.addEventListener("click",function() {
if(!start) {
let left = 1;
start = setInterval(function() {
item.style.left = left++ + "px";
},100)
}
})
})
- 闭包排序
let lessons = [
{
title: "媒体查询响应式布局",
click: 89,
price: 12
},
{
title: "FLEX 弹性盒模型",
click: 45,
price: 120
},
{
title: "GRID 栅格系统",
click: 19,
price: 67
},
{
title: "盒子模型详解",
click: 29,
price: 300
}
];
function order(file) {
return (a,b)=>(a[file]>b[file]?1:-1);
}
console.table(lessons.sort(order("price")));
闭包问题
- 内存泄漏---闭包特性中上级作用域为函数保存数据,从而造成内存泄漏
<body>
<div desc="houdunren">在线学习</div>
<div desc="hdcms">开源产品</div>
</body>
<script>
let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
item.addEventListener("click", function() {
console.log(item.getAttribute("desc"));
});
});
</script>
清除不需要的数据
let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
let desc = item.getAttribute("desc");
item.addEventListener("click", function() {
console.log(desc);
});
item = null;
});
this指向
let hd = {
user: "后盾人",
get: function() {
return function() {
return this.user;
};
}
};
console.log(hd.get()()); //undefined
箭头函数解决
let hd = {
user: "后盾人",
get: function() {
return () => this.user;
}
};
console.log(hd.get()()); //undefined