1. 块级作用域
ES6之前没有块级作用域,ES5的var没有块级作用域的概念,只有function有作用域的概念,ES6的let、const引入了块级作用域。
ES5之前if和for都没有作用域,所以很多时候需要使用function的作用域,比如闭包。
1.1. 什么是变量作用域
变量在什么范围内可用,类似Java的全局变量和局部变量的概念,全局变量,全局都可用,局部变量只在范围内可用。ES5之前的var是没有块级作用域的概念,使用var声明的变量就是全局的。
1 2 3 4 5
| { var name = 'zzz'; console.log(name); } console.log(name);
|
上述代码中{}外的console.log(name)可以获取到name值并打印出来,用var声明赋值的变量是全局变量,没有块级作用域。
1.2. 没有块级作用域造成的问题
if块级
1 2 3 4 5 6 7 8 9 10
| if(true){ var name = 'zzz'; func = function (){ console.log(name); } func(); } name = 'ttt'; func(); console.log(name);
|
代码输出结果为'zzz','ttt','ttt',第一次调用func(),此时name=‘zzz’,在if块外将name置成‘ttt’,此时生效了,if没有块级作用域。
for块级
定义五个按钮,增加事件,点击哪个按钮打印“第哪个按钮被点击了”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>块级作用域</title> </head> <body> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"> </script> <script> var btns = document.getElementsByTagName("button"); for (var i = 0; i < btns.length; i++) { btns[i].addEventListener('click',function (param) { console.log("第"+i+"个按钮被点击了"); }); } </script> </body> </html>
|
for块级中使用var声明变量i时,是全局变量,点击任意按钮结果都是“第五个按钮被点击了”。说明在执行btns[i].addEventListener('click',function())时,for块级循环已经走完,此时i=5,所有添加的事件的i都是5。
改造上述代码,将for循环改造,由于函数有作用域,使用闭包能解决上述问题。
1 2 3 4 5 6 7 8
| for (var i = 0; i < btns.length; i++) { (function (i) { btns[i].addEventListener('click',function (param) { console.log("第"+i+"个按钮被点击了"); }) })(i); }
|
结果如图所示,借用函数的作用域解决块级作用域的问题,因为有块级作用域,每次添加的i都是当前i。

在ES6中使用let/const解决块级作用域问题,let和const有块级作用域,const定义常量,在for块级中使用let解决块级作用域问题。
1 2 3 4 5 6 7
| const btns = document.getElementsByTagName("button"); for (let i = 0; i < btns.length; i++) { btns[i].addEventListener('click',function (param) { console.log("第"+i+"个按钮被点击了"); }) }
|
结果和使用闭包解决一致。
2. const的使用
1.const用来定义常量,赋值之后不能再赋值,再次赋值会报错。
1 2 3 4 5
| <script> const count = 1 </script>
|
2.const不能只声明不赋值,会报错。
3.const常量含义是你不能改变其指向的对象,例如user,都是你可以改变user属性。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> const user = { name:"zzz", age:24, height:175 } console.log(user) user.name = "ttt" user.age = 22 user.height = 188 console.log(user) </script>
|
const内存地址详解

对象count一开始只是0x10的地址,直接将count(给count重新赋值,指向一个新的对象)指向地址改为0x20会报错,const是常量,无法更改对象地址。
对象user一开始指向0x10地址,user有Name、Age、Height三个属性,此时修改属性Name='ttt',user对象的地址未改变,不会报错。
3. ES6的增强写法
3.1. ES6的对象属性增强型写法
ES6以前定义一个对象
1 2 3 4 5 6 7
| const name = "zzz"; const age = 18; const user = { name:name, age:age } console.log(user);
|
ES6写法
1 2 3 4 5 6
| const name = "zzz"; const age = 18; const user = { name,age } console.log(user);
|
3.2 ES6对象的函数增强型写法
ES6之前对象内定义函数
1 2 3 4 5
| const obj = { run:function(){ console.log("奔跑"); } }
|
ES6写法
1 2 3 4 5
| const obj = { run(){ console.log("奔跑"); } }
|
4. 箭头函数
传统定义函数的方式
1 2 3
| const aaa = function (param) { }
|
对象字面量中定义函数
1 2 3
| const obj = { bbb (param) { }, }
|
ES6中的箭头函数
4.1 箭头函数的参数和返回值
4.1.1 参数问题
1.放入两个参数
1 2 3
| const sum = (num1,num2) => { return num1 + num2 }
|
2.放入一个参数,()可以省略
1 2 3
| const power = num => { return num * num }
|
4.1.2 函数内部
1.函数中代码块中有多行代码
1 2 3 4
| const test = () =>{ console.log("hello zzz") console.log("hello vue") }
|
2.函数代码块中只有一行代码,可以省略return
1 2 3 4 5 6 7 8
|
const mul = (num1,num2) => num1* num2
const log = () => console.log("log")
|
4.3 箭头函数的this使用
什么时候使用箭头函数
1 2 3 4 5 6
| setTimeout(function () { console.log(this) } , 1000); setTimeout(() => { console.log(this) }, 1000);
|
结论:箭头函数没有this,这里this引用的是最近作用域(aaa函数里的this)的this。
1 2 3 4 5 6 7 8 9 10 11
| const obj = { aaa(){ setTimeout(function () { console.log(this) }); setTimeout(() => { console.log(this) }); } } obj.aaa()
|
上述中第一个是window对象的this,第二个箭头函数的this是obj的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const obj = { aaa() { setTimeout(function () { setTimeout(function () { console.log(this) }) setTimeout(() => { console.log(this) }) }) setTimeout(() => { setTimeout(function () { console.log(this) }) setTimeout(() => { console.log(this) }) }) } } obj.aaa()
|
5. 高阶函数
5.1 filter过滤函数
1 2 3 4 5 6 7 8 9 10 11
| const nums = [2,3,5,1,77,55,100,200]
let newNums = nums.filter(function (num) { if(num > 50){ return true; } return false; })
|
5.2 map高阶函数
1 2 3 4 5 6 7 8
|
let newNums2 = newNums.map(function (num) { return num * 2 })
console.log(newNums2);
|
5.3 reduce高阶函数
1 2 3 4 5 6 7 8 9 10
|
let newNum = newNums2.reduce(function (preValue,currentValue) { return preValue + currentValue },0)
console.log(newNum);
|
5.4综合使用
1 2 3
| let n = nums.filter(num => num > 50).map(num => num * 2).reduce((preValue,currentValue) => preValue + currentValue) console.log(n);
|