ES6(ES2015)
1. 变量 let 和常量 const
-
var 的问题
- 可以重复声明,没有报错和警告
- 无法限制修改
- 没有块级作用域,
{ }
-
let 和 const
- 不能重复声明
- 都是块级作用域,
{ }
块内声明的,块外无效 - let 是变量,可以修改
- const 是常量,不能修改
-
块级作用域举例
- 原来用 var 的方式,结果弹出的都是 3
- 或者将变量 封装到函数里,限制作用域,但比较麻烦
- 用 let 最简单,直接 var 改 let,解决作用域问题
<!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>Document</title> <script> window.onload= function () { /* var aBtn = document.getElementsByTagName('input') for (var i=0; i < aBtn.length; i++) { aBtn[i].onclick = function () { alert(i) } }*/ var aBtn = document.getElementsByTagName('input') for (let i = 0; i < aBtn.length; i++) { aBtn[i].onclick = function () { alert(i) } } /* var aBtn = document.getElementsByTagName('input') for (var i = 0; i < aBtn.length; i++) { // 封装到函数里,限制作用域 (function (i) { aBtn[i].onclick = function () { alert(i) } })(i) }*/ } </script> </head> <body> <input type="button" value="按钮1"> <input type="button" value="按钮2"> <input type="button" value="按钮3"> </body> </html>
2. 箭头函数
引入箭头函数有两个方面的作用:简化函数和不需要绑定 this
。
x => x * x 上面的箭头函数相当于: function (x) { return x * x; }
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }
和return
都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }
和return
:
x => { if (x > 0) { return x * x; } else { return - x * x; } }
如果参数不是一个,就需要用括号()
括起来:
// 两个参数: (x, y) => x * x + y * y // 无参数: () => 3.14 // 可变参数: (x, y, ...rest) => { var i, sum = x + y; for (i=0; i<rest.length; i++) { sum += rest[i]; } return sum; }
如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
// SyntaxError: x => { foo: x } 因为和函数体的{ ... }有语法冲突,所以要改为: // ok: x => ({ foo: x })
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this
是词法作用域,由上下文确定。
回顾前面的例子,由于JavaScript函数对this
绑定的错误处理,下面的例子无法得到预期结果:
var obj = { birth: 1990, getAge: function () { var b = this.birth; // 1990 var fn = function () { return new Date().getFullYear() - this.birth; // this指向window或undefined }; return fn(); } };
现在,箭头函数完全修复了this
的指向,this
总是指向词法作用域,也就是外层调用者obj
:
var obj = { birth: 1990, getAge: function () { var b = this.birth; // 1990 var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象 return fn(); } }; obj.getAge(); // 25
如果使用箭头函数,以前的那种hack写法:
var that = this;
就不再需要了。
由于this
在箭头函数中已经按照词法作用域绑定了,所以,用call()
或者apply()
调用箭头函数时,无法对this
进行绑定,即传入的第一个参数被忽略:
var obj = { birth: 1990, getAge: function (year) { var b = this.birth; // 1990 var fn = (y) => y - this.birth; // this.birth仍是1990 return fn.call({birth:2000}, year); } }; obj.getAge(2015); // 25
3. ...扩展参数符
- 参数扩展/展开
...args
- 收集剩余的参数,必须当到最后一个参数位置
- 展开数组,简写,效果和直接把数组的内容写在这儿一样
- 默认参数
function show(a, b, ...args) { console.log(a) // 1 console.log(b) // 2 console.log(args) // [3,4,5] } show(1, 2, 3, 4, 5) let arr1 = [1, 2, 3] let arr2 = [4, 5, 6] let arr3 = [...arr1, ...arr2] console.log(arr3) // [1,2,3,4,5,6] function show2(a, b=5, c=8) { console.log(a, b, c) // 88 12 8 } show2(88, 12)
4. 解构赋值
解构赋值
- 左右两个边结构必须一样
- 右边必须是个东西
- 声明和赋值赋值不能分开,必须在一句话里
数组:
let [a, b, c] = [1, 2, 3]; //等同于 let a = 1; let b = 2; let c = 3;
对象:
var { StyleSheet, Text, View } = React; 等同于 var StyleSheet = React.StyleSheet; var Text = React.Text; var View = React.Text;
获取对象中的值:
const student = { name: 'bahg', age: 18, sex: 'girl' } const {name, age, sex} = student console.log(name); // bahg console.log(age); // 18 console.log(sex); // girl
5. 新增四个方法 map、reduce、filter、forEach
(1)map映射 (一对一,返回新数组)
let arr = [12, 5, 8] let result1 = arr.map(item=>item*2) // 简写 console.log(result1) // [ 24, 10, 16 ] let score = [18, 86, 88, 24] let result2 = score.map(item => item >= 60 ? '及格' : '不及格') console.log(result2) // [ '不及格', '及格', '及格', '不及格' ] var users = [ {name: "张XX", "email": "[email protected]"}, {name: "江XX", "email": "[email protected]"}, {name: "李XX", "email": "[email protected]"} ]; var emails = users.map(function (user) { return user.email; }); console.log(emails.join(",")); // [email protected], [email protected], [email protected]
(2)reduce 汇总(多变一,返回新数组)
arr.reduce(function(prev,cur,index,arr){
...
}, init);
- prev 表示上一次调用回调时的返回值,或者初始值 init;
- cur 表示当前正在处理的数组元素;
- index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
- arr 表示原数组;
- init 表示初始值
其实必需以及常用的参数只有两个:prev 和 cur。接下来我们跟着实例来看看具体用法吧~
请参考 https://www.cnblogs.com/cckui/p/9267542.html、https://www.cnblogs.com/amujoe/p/11376940.html
(3)filter 过滤器(保留为true的,返回新数组)
var arr = [12, 4, 8, 9] var result = arr.filter(item => (item % 3 === 0) ? true : false) console.log(result) // Array(2) var result = arr.filter(item => item % 3 === 0) console.log(result) // Array(2) var arr = [ { title: '苹果', price: 10 }, { title: '西瓜', price: 20 }, ] var result = arr.filter(json => json.price >= 20) console.log(result) // Array(1)
(4)forEach 循环迭代(用于遍历数组,无返回值)
var arr = [12, 4, 8, 9] var result = arr.forEach(item => console.log(item)) var result = arr.forEach((item, index)=>console.log(item, index))
注意:除了reduce方法之外的其他三个方法,都传入了一个匿名函数作为参数,而该匿名函数实际含有三个参数(我们这里只写了一个)。其依次代表数组遍历时的当前元素item,数组遍历时的当前元素的索引index,以及正在遍历的数组array。有了这三个参数,可以方便我们做很多事情,比如说将每一项数组元素翻倍,这时需要用到第一个参数item。但是,仅仅只是将item乘以2可不行,我们还得将其赋值给原来的数组,这时我们就得用到后面两个参数index和array。根据上述可知,array[index]是全等于item的。
此外,这三个方法除了传递一个匿名函数作为参数之外,还可以传第二个参数,该参数用于指定匿名函数内的this指向,例如:
// 只传一个匿名函数 arr.forEach(function(item,index,array){ console.log(this); // window });
// 传两个参数 arr.forEach(function(item,index,array){ console.log(this); // [1, -2, 3, 4, -5] },arr);
6. 字符串
(1)模板字符串
- 使用反引号,
${变量}
- 可以折行
let a = 12 let str1 = `asdf${a}` console.log(str1) // asdf12 let title = '标题' let content = '内容' let str = `<div> <h1>${title}</h1> <p>${content}</p> </div>` console.log(str)
<div>
<h1>标题</h1>
<p>内容</p>
</div>
(2)两个新方法
startWith endsWith
var url = 'http://qq.com' console.log(url.startsWith('http')) console.log(url.endsWith('com')) // 都是 true
7. 类
- 原来写法
- 类和构造函数一样
- 属性和方法分开写的
// 老版本 function User(name, pass) { this.name = name this.pass = pass } User.prototype.showName = function () { console.log(this.name) } User.prototype.showPass = function () { console.log(this.pass) } var u1 = new User('able', '1233') u1.showName() u1.showPass()
// 老版本继承 function VipUser(name, pass, level) { User.call(this, name, pass) this.level = level } VipUser.prototype = new User() VipUser.prototype.constructor = VipUser VipUser.prototype.showLevel = function () { console.log(this.level) } var v1 = new VipUser('blue', '1234', 3) v1.showName() v1.showLevel()
- 新版面向对象
- 有了 class 关键字、构造器
- class 里面直接加方法
- 继承,super 超类==父类
class User { constructor(name, pass) { this.name = name this.pass = pass } showName() { console.log(this.name) } showPass() { console.log(this.pass) } } var u1 = new User('able2', '111') u1.showName() u1.showPass() // 新版本继承 class VipUser extends User { constructor(name, pass, level) { super(name, pass) this.level = level } showLevel(){ console.log(this.level) } } v1 = new VipUser('blue', '123', 3) v1.showLevel()
8. 模块化
ES5 不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
导出(export)
ES6 允许在一个模块 export 来导出多个变量或函数。