高阶-作用域 函数 闭包
# 1.执行环境与作用域
作用域:标识符的作用范围
标识符:变量/函数名/函数形参/对象的属性
- 全局作用域
- 局部作用域
- 块级作用域 ES6 {}
# 1.1 作用域链
作用域链:查找变量及变量的值,就近原则
查找方法:一级一级往上查找,如果没有找到,继续往上一层作用域继续查找,如果全局作用域仍然没有查找到变量,提醒变量未定义。
# 2.函数
# 2.1 ES5函数相关概念
- 函数定义方式(声明式与表达式)
- 函数参数(形参与实参)
- 函数隐藏参数(arguments 伪数组)
- ES6语法中 没有arguments
- return
- 没有return 返回undefined
- 回调函数
- 现在不调,满足特定条件调用
- 返回异步数据
- 形式参数默认值
- ES5 默认参数
# 2.2 ES6函数新特性
- 箭头函数 [简写函数的写法]
- 省略function ,在() 与{}之间 加上 =>
- 如果函数体只有一句代码,省略 {} 和 return
- 如果参数只有一个,省略()
- 如果没有形参,必须写 ()
注意:ES6的箭头函数 没有 arguments 及 this指向
ES6函数隐藏参数 (rest 参数)
- 解决ES6中没有arguments参数的问题
- let sum = (...data)=>{};
- data 是一个数组,是所有参数的集合,所有的数组处理方法都能够使用
- 前面的数据可以 单独用变量接收, rest 参数 获取除了前面已经用变量接收的数据以外的 数据集合
- reset 参数 必须写在 所有形参的最后
// 前面的数据可以 单独用变量接收 // ...data 获取除了前面已经用变量接收的数据以外的 数据集合 let sum = (a,b,...data)=> { console.log(a); //1 console.log(b); //2 console.log(data); // [ 2, 5, 5, 66, 5 ] }; sum(1,2,2,5,5,66,5);
1
2
3
4
5
6
7
8
# 2.3 ES6处理回调的方法
- Promise 处理回调地狱
# 2.4 ES6 函数形参默认值
直接在形参中写默认值 赋值
let sum = (a=0,b=0)=>{ return a+b; }
1
2
3
# 2.5 ES5 IIFE立即执行函数
- 一个js文件只写一个立即执行函数
- 引入js马上执行这个函数中的内容
;(function(){
console.log('aaaa');
})()
;(function(a){
console.log(a);
})(123)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3.闭包
解决问题
- 局部定义的变量如何在全局作用域访问到?
function fn(){ var a = 100; console.log(a); } //输出a console.log(a);
1
2
3
4
5
6
7
8什么是闭包?
- 函数的变量跨作用域访问
闭包的一般写法
外部函数包含内部函数,外部函数返回了内部函数
function fn(){ var num = 100; return function(){ num--; return num; } }
1
2
3
4
5
6
7外部函数包含内部函数,内部函数挂载到window
;(function(){ var num = 100; window.output = function(){ num--; return num; } })()
1
2
3
4
5
6
7
# 3.1 闭包-体验保管压岁钱
//将钱交给妈妈保存
function mom(){
var money = 500;
return function(){
money -=100;
return money
}
}
//小源花钱
var spendMoney = mom();
console.log( spendMoney());
console.log( spendMoney());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.2 闭包实现-取号器
var add = (function(){
var num = 100;
return function(){
return ++num;
}
})();
console.log(add()) // 101
console.log(add()) //102
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 3.3 闭包-解决定时器问题
循环中有定时器,在定时器中输出循环的中间变量
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i); //输出5个5
},1000)
}
1
2
3
4
5
2
3
4
5
for(var i=0;i<5;i++){
;(function(index){
setTimeout(function(){
console.log(index); //输出 0 1 2 3 4
},1000)
})(i)
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 3.4 闭包-事件监听
事件监听多个lis触发 输出 索引值 i ,无论点击哪个都是输出的都是5
var lis = document.querySelectorAll('ul li');
for(var i=0;i<lis.length;i++){
lis[i].addEventListener('click',function(ev){
console.log(i); // 5
})
}
1
2
3
4
5
6
7
2
3
4
5
6
7
var lis = document.querySelectorAll('ul li');
for(var i=0;i<lis.length;i++){
;(function(i){
lis[i].addEventListener('click',function(ev){
console.log(i); // 0 1 2 3 4
})
})(i)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3.5闭包作用
保护内部的标识符,防止外部污染.形成一个简单的模块或块级作用域
# 4.ES6块级作用域实现闭包
- 解决事件监听问题
var lis = document.querySelectorAll('ul li');
for(let i=0;i<lis.length;i++){
lis[i].addEventListener('click',function(ev){
console.log(i); // 0 1 2 3 4
})
}
1
2
3
4
5
6
2
3
4
5
6
解决定时器问题
for(let i=0;i<5;i++){ setTimeout(function(){ console.log(index); //0 1 2 3 4 },1000) }
1
2
3
4
5
编辑 (opens new window)
上次更新: 2022/09/20, 00:36:06