一、ES6简介
ECMAScript 6.0 (以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现
ES6简介与历史
二、变量声明let、const
2.1、let命令
块级作用域:
ES6 新增了let 命令,用来声明变量。其的用法类似于var ,但是所声明的变量,只在let命令所在的代码块内有效。
if (true) {
var a = 10;
let b = 20;
}
console.log(a);
console.log(b);
分别用let和var声明了两个变量。在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。这表明,let声明的变量只在它所在的代码块有效。
不存在变量提升:
var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined 。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let 命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
console.log(foo);
var foo = 2;
console.log(bar);
let bar = 2;
上面代码中,变量foo 用var 命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined 。 变量bar 用let 命令声明,不会发生变量提升。这表示在声明它之前,变量bar 是不存在的,这时如果用到它,就会抛出一个错误。 因此,使用let声明变量,极大的消除了代码的潜在bug 的隐患。
2.2、const命令
const 声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415926;
PI = 3;
上面代码表明改变常量的值会报错
const foo;
const 的作用域与let 命令相同:只在声明所在的块级作用域内有效。
if (true) {
const MAX = 5;
}
MAX
三、扩展运算符
3.1、指数运算符
新增了一个指数运算符`**
2 ** 2
2 ** 3
运算符的一个特点是右结合。多个指数运算符连用时,是从最右边开始计算的。
2 ** 3 ** 2
指数运算符可以与等号结合,形成一个新的赋值运算符**= 。
let a = 1.5;
a **= 2;
let b = 4;
b **= 3;
3.2、 数组(扩展运算符)
解构赋值: 扩展运算符(spread )就是我们知道的三个点(... ),它就好像rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1,2,3]);
console.log(1,...[2,3,4],5)
console.log([1,...[2,3,4],5])
[...document.querySelectorAll('div')]
复制数组:
let arr = [1, 2],
arr1 = [...arr];
console.log(arr1);
如果数组含有空位复制过来会有如下的结果
let arr2 = [1, , 3],
arr3 = [...arr2];
console.log(arr3); [1, undefined, 3]
合并数组:
console.log([...[1, 2],...[3, 4]]);
3.3、对象
拓展运算符(... )用于取出 参数对象 所有 可遍历属性 然后拷贝到当前对象。
基本用法: 、 可复制其7他对象里面的内容
let person = {name: "Amy", age: 15};
let someone = { ...person };
console.log(someone);
合并对象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person;
注意:自定义的属性在拓展运算符后面,则拓展运算符对象内部同名的属性将**被覆盖掉。**同理,自定义的属性在拓展运算度前面,则变成设置新对象默认属性值。
let person = {name: "Amy", age: 15};
let someone = { ...person, name: "Mike", age: 17};
let someone1 = { name: "Mike", age: 17,...person};
console.log(someone);
console.log(someone1);
拓展运算符后面是空对象、null、undefined,没有任何效果也不会报错。
let a = {...{}, a: 1, b: 2};
console.log(a);
let b = {...null, ...undefined, a: 1, b: 2};
console.log(b);
3.4、函数
... 加上一个具名参数标识符组成用来表示不确定参数个数。具名参数只能放在参数组的最后,并且有且只有一个不定参数
function addNumbers(x,y,z){
return x+y+z;
}
var numbers = [1,2,3,4];
addNumbers(...numbers);
四、箭头函数、解构赋值、数组新特性、字符串新特性、es6模块化、es6面向对象
4.1、箭头函数
ES6 允许使用“箭头”(=> )定义函数
var f = v => v;
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
var sum = function(num1, num2) {
return num1 + num2;
};
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
let getTempItem = id => { id: id, name: "Temp" };
let getTempItem = id => ({ id: id, name: "Temp" });
注意:
对于普通函数来说,内部的this 指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
上面代码中,setTimeout() 的参数是一个箭头函数,这个箭头函数的定义生效是在foo 函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时this应该指向全局对象window ,这时应该输出21。但是,箭头函数导致this 总是指向函数定义生效时所在的对象(本例是{id: 42}),所以打印出来的是42。
例子: 回调函数分别为箭头函数和普通函数,对比它们内部的this指向。
function Timer() {
this.s1 = 0;
this.s2 = 0;
setInterval(() => this.s1++, 1000);
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
上面代码中,Timer 函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新
4.2、解构赋值
解构赋值是对赋值运算符的扩展。是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
- 解构的源:解构赋值表达式的右边部分
- 解构的目标:解构赋值表达式的左边部分。
数组模型的解构(Array):
- 基本:
let [a, b, c] = [1, 2, 3];
- 可嵌套
let [a, [[b], c]] = [1, [[2], 3]];
- 可忽略
let [a, , b] = [1, 2, 3];
- 剩余运算符
let [a, ...b] = [1, 2, 3];
对象模型的解构(Object):
- 基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
let { baz : foo } = { baz : 'ddd' };
- 可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { }] } = obj;
- 剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
模板字符串:
- 用反引号标记字符串(``)(英文字符) 字符串模板
- 反引号里可以写多行文本
- 在字符串模板中可以使用插值
- 插值的形式:
${表达式}
五、class、extends、constructor、super
5.1、class
在ES6中, class (类)作为对象的模板被引入,可以通class 关键字定义类。class 的本质是函数。 它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
类表达式可以为匿名或命名。
let Example = class {
constructor(a) {
this.a = a;
}
}
let Example = class Example {
constructor(a) {
this.a = a;
}
}
5.2、constructor
ES6引入了class类的概念,创建的每一个class类,都会有一个constructor() 方法,该方法是一种用于创建和初始化class创建的对象的特殊方法–构造函数方法。
class Animal {
constructor() {
this.name = "animal";
}
}
let animal = new Animal();
console.log(animal.name);
如果一个类没有指定constructor() 方法,则会添加默认的constructor() 方法;在这里插入代码片
class Animal(){}
等同于
class Animal(){
constructor(){}
}
一个类只允许有一个constructor() 方法,如果出现多个,则会报:Uncaught SyntaxError: A class may only have one constructor
5.3、extends
通过 extends 实现类的继承。
class Child extends Father { ... }
class B{
constructor(name){
this.name = name;
}
};
class A extends B{
constructor(name,age){
super(name)
this.age = age;
}
};
let a = new A('wxp',18);
console.log(a)
5.4、super
ES6重新实现了类的继承,而在继承的过程中,super 关键字实现了至关重要的作用
. super 作为函数时,代表父类的构造函数
class A {}
class B extends A {
constructor() {
super();
}
}
super 作为函数使用时,必须出现在子类的构造函数constructor 中,否则会报错
参考博客:ES6基础入门 参考教程: ES6教程 ES6菜鸟教程
|