一、作用域
全局作用域只有一个,每个函数有都有作用域(环境)。es6中新增了块级作用域。
函数被执行后其环境变量将从内存中删除,函数每次调用都会创建一个新的作用域。
如果子函数被使用时,父级环境将被保留。 ----闭包
使用let/const 可以将变量声明在块级作用域中,(放在新环境中,而不是全局中)
//块级作用域
使用let/const在块级作用域中定义变量,在全局中找不到该变量
{
let a=1;
const b=2;
}
二、闭包
闭包是函数运行的一种机制,函数执行会形成一个私有作用域(上下文),如果私有作用域的某些内容被私有作用域以外的一些事物(如:变量/事件绑定等)所占用,则当前私有作用域不能被出栈释放。
创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。
闭包的优点:
- 保护私有上下文中的“私有变量”和外界互不影响
- 私有上下文中的“私有变量”和“值”都会被保存起来,可以供其下级上下文中使用
闭包的缺点:
- 如果使用闭包,会导致栈内存太大,页面渲染变慢,性能收到影响,所以在项目中“合理使用闭包”。
闭包的使用
1、闭包的基本使用
//如果子函数被调用,则父函数不会被释放
function fn(){
let n=1;
return function(){
console.log(n++);
}
}
let method=fn();
method();
method();
method();
//手动释放
method=null;
2、对数组对象进行排序:保存变量对象的属性名prop
let phone = [
{
title: "手机1",
click: 100,
price: 3200
},
{
title: "手机2",
click: 110,
price: 1200
},
{
title: "手机3",
click: 2100,
price: 2000
}
];
function myOrder(prop, bool) {
if(bool===undefined) bool=true;
if(bool) return (a, b) => a[prop] - b[prop];
else return (a, b) => b[prop] - a[prop];
}
phone.sort(myOrder('price',false));
console.log(phone);
3、对列表元素绑定事件:保存变量li的索引i
for (var i = 0; i < liList.length; i++) {
liList[i].onclick = (function (i) {
return function () {
console.log(`当前点击按钮的索引:${i}`)
}
})(i)
}
4、闭包实现模块化:保护私有变量
jQuery使用的就是闭包实现模块化
function(window){
const jQuery={...};
window.jQuery=window.$=jQuery;
}(window)
cmd和commonjs的实现
const {getPhone,setPhone} = (function () {
var phone = '1232131223'
function getPhone() {
return '我的电话号码:' + phone
}
function setPhone(phoneNum){
phone = phoneNum
}
// 暴露到外部调用的方法
return {
getPhone,
setPhone
}
})()
setPhone('rrofo')
console.log(getPhone())
三、惰性调用
利用闭包保存值的特性只完成一次判断,后续调用封装的函数不用再次判断来提高函数执行效率。
例如:
window.getComputedStyle(元素) 获取当前元素经过浏览器计算的样式,在ie6到8中,不兼容,需要使用 元素.currentStyle 来获取,可以利用闭包保存值的特性完成只要一次判断,后续调用封装的函数不用再次判断来提高函数执行效率。
function getStyle(el, attr) {
// 判断当前属性是不是属于此对象
if ('getComputedStyle' in window) {
getStyle = function (el, attr) {
return window.getComputedStyle(el)[attr]
}
} else {
getStyle = function (el, attr) {
return el.currentStyle[attr]
}
}
return getStyle(el, attr)
}
getStyle (document.getElementById('box'), 'color')
四、函数柯里化
柯里化是一个预处理思想,使用闭包形成一个不被释放的上下文,把一些信息存储起来,以后基于作用域链,访问到事先存储的信息,然后进行先关处理,我们把这种模式称为柯里化函数。
//预处理变量n,子作用域能够访问到该变量
function fn(n=10){
return function(...args){
return args.reduce((value,item) => value+item,n);
}
}
let sum=fn();
console.log(sum(1,2,3));