ES6新特性
字数统计:3.5k字目录
转载:
带你一起敲敲ES6的新特性
ES6 新增的常用新特性
ES6中常用的10个新特性讲解
ES6新特性
1.变量声明
1、常量(const, 不会变量提升,块级作用域,作用域内值不能改,const 对象仍然可以被改变的)
如果const的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址没有变就行:1
2
3
4const student = { name: 'cc' }
student.name = 'yy';// 不报错
student = { name: 'yy' };// 报错
1 | const aa = {a: '12'}; |
2、块级作用域(let,不会变量提升)1
2
3
4
5
6
7
8
9
10for (let i = 0; i<5; i++) {
setTimeout(() => {
console.log(i) //0 1 2 3 4
},30)
}
for (var i = 0; i<5; i++) {
setTimeout(() => {
console.log(i) //5 5 5 5 5
},30)
}
注意:1
2
3
4
5
6
7
8let 关键词声明的变量不具备变量提升(hoisting)特性
let 和 const 声明只在最靠近的一个块中(花括号内)有效
当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
const 在声明时必须被赋值
let const:
块级作用域
不可重复声明
不存在变量提升
特别要说明一点的是对于const和let都有暂存死区
,所谓暂存死区就是:如果作用域内有这样一个变量那么这个作用域内就会绑定这个变量,不会继续向上查找了,以下代码运行会报错
。
1 | const a = 1; |
2.结构赋值
所谓解构赋值就是 声明和赋值都放到了一起一般都是数组 对 数组, 对象 对 对象, 数组能够设置默认值,对象也能够设置默认值,默认值必须采用等号的方式
。1
2
3
4
5let [zhan, si, xl = 5] = [3, 4];
console.log(zhan, si, xl) //3, 4, 5
let {name, age = 23} = {name: 'xl', bigAge: 24}
console.log(name, age) //xl, 23
特别的,可能有时会有关键字的情况可以通过:的形式来更改名字,看下面代码1
2let { name, age: xl, default: d } = { name: 'xlei', age: 9, default: 'xxx' };
console.log(name, xl, d);
来一个默认值的具体应用吧:1
2
3
4
5
6
7
8
9
10
11function ajax({
url = new Error('url without'),
type = 'get',
data = xxx
}){
console.log(data, type) //{a: 5}, get
}
ajax({
url: '/test',
data: {a:5}
})
3.模板字符串
1、模板字符串(拼接方便,可以换行)1
2基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}来界定;
ES6反引号(``)直接搞定;
1 | let exe1 = '张三' |
2、startWith, endWith 返回一个布尔值1
2
3
4
5let str1 = 'www.bsym.online'
let str2 = 'http://www.bsym.online'
console.log(str1.startsWith('http://')) //false
console.log(str2.startsWith('http://')) //true
console.log(str2.endsWith('online')) //true
3、padStart, padEnd补全 – 不会删除原有内容1
2
3
4
5// padStart padEnd 补全(记住只能增加,不能减少)
let str1 = 'nihao'
let newStr = str1.padStart(8,'xl')
let newStr2 = str1.padEnd(8,'xl')
console.log(newStr, newStr2) //xlxnihao, nihaoxlx
3.1字符串新增的一些方法
1 | { |
4.箭头函数(解决this问题,书写起来更简单)
传统函数内的this是定义时所在的环境,而箭头函数内的this是使用时上下文的环境。
ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;
箭头函数最直观的三个特点。
1 | 不需要 function 关键字来创建函数 |
1 | var add = (a, b) => a + b; |
注意:
这里顺带提一下,像上面的自执行匿名函数前后都要加分号
,这样既不会被坑,也不会坑别人。另外不要使用箭头函数的argeuments
细节:
当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{}
和 return
5.函数
在ES6之前,我们往往这样定义参数的默认值:1
2
3
4
5
6
7
8
9
10
11
12
13# ES6之前,当未传入参数时,text = 'default';
function printText(text) {
text = text || 'default';
console.log(text);
}
# ES6;
function printText(text = 'default') {
console.log(text);
}
printText('hello'); // hello
printText();// default
6.Spread / Rest 操作符
Spread / Rest 操作符指的是 ...,具体是 Spread 还是 Rest 需要看上下文语境。
当被用于迭代器中时,它是一个 Spread 操作符:1
2
3
4
5function foo(x,y,z) {
console.log(x,y,z);
}
let arr = [1,2,3];
foo(...arr); // 1 2 3
当被用于函数传参时,是一个 Rest 操作符:当被用于函数传参时,是一个 Rest 操作符:1
2
3
4function foo(...args) {
console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
7.二进制和八进制字面量
ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:1
2
3
4
5let oValue = 0o10;
console.log(oValue); // 8
let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`
console.log(bValue); // 2
8.for…of 和 for…in
for…of 用于遍历一个迭代器,如数组:1
2
3
4
5
6let letter = ['a', 'b', 'c'];
letter.size = 3;
for (let letter of letters) {
console.log(letter);
}
// 结果: a, b, c
for…in 用来遍历对象中的属性:1
2
3
4
5
6let stu = ['Sam', '22', '男'];
stu.size = 3;
for (let stu in stus) {
console.log(stu);
}
// 结果: Sam, 22, 男
9.ES6中的类
ES6 中支持 class 语法,不过,ES6的class不是新的对象继承模型,它只是原型链的语法糖表现形式。
函数中使用 static 关键词定义构造函数的的方法和属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Student {
constructor() {
console.log("I'm a student.");
}
study() {
console.log('study!');
}
static read() {
console.log("Reading Now.");
}
}
console.log(typeof Student); // function
let stu = new Student(); // "I'm a student."
stu.study(); // "study!"
stu.read(); // "Reading Now."
类中的继承和超集:1
2
3
4
5
6
7
8
9
10
11
12
13class Phone {
constructor() {
console.log("I'm a phone.");
}
}
class MI extends Phone {
constructor() {
super();
console.log("I'm a phone designed by xiaomi");
}
}
let mi8 = new MI();
extends
允许一个子类继承父类,需要注意的是,子类的constructor
函数中需要执行 super()
函数。
当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()
。
在 这里 阅读更多关于类的介绍。
有几点值得注意的是:
类的声明不会提升(hoisting
),如果你要使用某个 Class
,那你必须在使用之前定义它,否则会抛出一个 ReferenceError
的错误
在类中定义函数不需要使用 function
关键词
要点
1、数组的扩展运算符:将一个数组转为用逗号分隔的参数序列1
2
3let arr = [...[1, 2, 3], ...[4, 5, 6]]
console.log(arr) // 1, 2, 3, 4, 5, 6
console.log(Math.min(...arr)) // 1
2、对象的解构赋值
对象的 Rest 解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面,注意Rest 解构赋值必须是最后一个参数,否则会报错。Rest解构赋值所在的对象,拷贝了对象obj的属性,Rest解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest解构赋值拷贝的是这个值的引用,而不是这个值的副本,解构赋值不会拷贝继承自原型对象的属性1
2
3
4
5
6
7let obj = {name: 'xl', age: 23, say:'ok', eat: {xl: 'okok'}}
//尚未被读取的属性,分配到指定的对象上面,浅拷贝了对象obj的属性
let {name, age, ...z} = obj
obj.say = 'oo'
obj.eat.xl = 'o?o?'
console.log(name, age, z)
//xl 23 { say: 'ok', eat: { xl: 'o?o?' } }
1 | let z = {a: 3, b: 4, c:{ |
那么要是想实现一个深拷贝,怎么实现呢?其实就是遍历属性如果属性是一个普通值就赋值,不是普通值就递归知道是普通值为止,然后赋值,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 实现深拷贝 保留继承关系 可以实现各种类型的拷贝 实现递归拷贝
function deepClone(obj) {
if (typeof obj !== 'object') return obj;
if (obj == null) return null;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
let o = new obj.constructor(); // 保留类的继承关系
Object.keys(obj).forEach((key, index) => {
if(typeof (obj[key]) == 'object'){
o[key] = deepClone(obj[key])
}else{
// console.log(obj[key])
o[key] = obj[key]
}
})
return o;
}
let o = { a: { a: 1 }, b: function(){
console.log(this.a)
} }
let newObj = deepClone(o);
o.a.a = 2;
console.log( newObj.b());
数组常用方式
1 | // (1)map返回值 返回值是一个新数组 |
数组新增方法
1 | { |
ES6的Class
先复习一下es5中的几个名词:1
2
3
4成员属性(方法)| 实例属性(方法) :在构造函数中通过this.属性声明的
静态属性(方法):通过类来声明的 类.xxx
私有属性(方法):只有在类的内部可以使用,其他任何地方都不可以使用的
公有属性(方法)|原型属性(方法):在原型上声明的属性或者方法 xx.prototype.xxx
1 | function Parent(name) { |
再来说说es6中的class(es6中不考虑私有属性和方法):
ES6 中支持 class 语法,不过,ES6的class不是新的对象继承模型,它只是原型链的语法糖表现形式。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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79class Parent{
constructor(x, y){
this.x = x;
//成员属性|实例属性 可遍历 打印实例可直接打印出来,
// 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),
// 否则都是定义在原型上(即定义在class上)。
this.y = y;
//如果不返回 默认返回实例对象 this
return this.x
}
static b(){ // 属于类上的方法 也称静态方法
return 2;
}
eat(){
//原型上的方法 | 公有方法 并且都是不可枚举的
// 打印实例不能显示的打印出来
console.log(this.x);
return this.x
}
}
class Child extends Parent{ //
constructor(x, y, z){
// Parent.call(this);返回的是子类的实例,
super(x, y);
this.age = z; // 成员属性|实例属性
}
static a(){ // 属于类上的方法
return 1;
}
smoking(){ // 原型上的方法
return super.eat() + this.age
//需要说明的是 super不仅可以调用父类的原型方法
// 还可以调用父类的静态方法,方法内部的this指向当前的子类,
// 而不是子类的实例
// console.log(this.age)
}
}
let child = new Child(2, 3, 4);
// console.log(child);
console.log(child.smoking())
class Foo {
constructor() {
//constructor函数默认返回this,
//这里返回一个全新的对象,结果导致实例对象不是Foo类的实例
return Object.create(null);
}
}
new Foo() instanceof Foo
// false
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
console.log(point)
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
迭代器(Iterators)
生成器(Generators)
对象和数组解构
1 | // 对象 |