ES6简介
ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的当前版本标准。ECMAScript即javascript的正式名称,1996年11月,JavaScript 的创造者网景公司将 JS 提交给国际化标准组织 ECMA,希望这种语言能够成为国际标准,随后 ECMA 发布了规定浏览器脚本语言的标准,即 ECMAScript。这也有利于这门语言的开放和中立。
ECMAScript的历史
-
1997 年 ECMAScript 1.0 诞生。
-
1998 年 6 月 ECMAScript 2.0 诞生,包含一些小的更改,用于同步独立的 ISO 国际标准。
-
1999 年 12 月 ECMAScript 3.0诞生,它是一个巨大的成功,在业界得到了广泛的支持,它奠定了 JS 的基本语法,被其后版本完全继承。直到今天,我们一开始学习 JS ,其实就是在学 3.0 版的语法。
-
2000 年的 ECMAScript 4.0 是当下 ES6 的前身,但由于这个版本太过激烈,对 ES 3 做了彻底升级,所以暂时被"和谐"了。
-
2009 年 12 月,ECMAScript 5.0 版正式发布。ECMA 专家组预计 ECMAScript 的第五个版本会在 2013 年中期到 2018 年作为主流的开发标准。2011年6月,ES 5.1 版发布,并且成为 ISO 国际标准。
-
2013 年,ES6 草案冻结,不再添加新的功能,新的功能将被放到 ES7 中。
-
2015年6月, ES6 正式通过,成为国际标准。
ES6新特性
1、 let&const
- let作用与var相似用于声明变量,常量值可以修改,但let不能重复声明变量var可以重复声明变量,let声明的变量在块级作用域内有效且let不存在变量提升问题。
- const一定要赋初始值,常量值不能修改,存在于块级作用域但对于数组和对象的元素可以修改。
let a = 1
a = 2
console.log(a);//2
const a = 1
a = 2
console.log(a)//报错;
2、箭头函数
箭头函数内的this指向上层对象;始终指向函数声明时所在作用域下的this的值,无法被call改变,普通函数的this指向调用对象。箭头函数不能作为构造函数实例化对象,箭头函数不能使用arguments但可以使用…rest,当形参有且只有一个的时候,可以省略(),当代码体只有一条语句的时候,可以省略{},此时return必须省略,而且语句的执行结果就是函数的返回值。
let n = 1
let a = n => n + 3
console.log(a(n));//4
3、 解构赋值
- ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值。
数组的解构:
const arry = ['num', 'string', 'symbol']
let [a, b, c] = arry
console.log(a)//num
- 对象的解构:和数组解构方法类似将原对象的值赋予新对象然后打印新对象里面的值。
注:对象解构赋值时一定要注意等号两边键名相等。
const {a,b} = {a: 11,b: 22}
console.log(a)//11
4、 模板字符串
模板字面量用倒引号 (``)而不是单引号 (’ ') 或双引号(" ")表示,可以包含用 ${expression} 表示的占位符。
let a = 10
let str = `现在${a}点了`
console.log(str);//现在10点了
5、简化对象的写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法(在属性名和变量名相同的情况下),这样的书写更加简洁。
let name = 'wut'
let age = 10
let a = {
name,
age,
getname() {
return this.name;
}
}
console.log(a.getname());//wut
6、函数参数的默认值设置
ES6允许给函数参数初始默认值,且可以和解构赋值一起使用。
function add(a, b, c = 10) {
return a + b + c
}
console.log(add(1, 2, ));//13
7、rest参数
ES6引入rest参数,用于获取函数的实参,用来代替arguments
function add(...num) {
console.log(num);
}
console.log(add(1, 2, 3)); //[1,2,3]
8、扩展运算符
…能将数组转为逗号分隔的参数序列,虽然形式与rest参数类似,但是rest参数是用在函数定义时的形参位置,扩展运算符是用在函数实际调用时的实参位置。
let a = [1, 2, 3]
function f(x, y, z) {
return x + y + z
}
console.log(f(...a));//6
9、symbol
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。Symbol的值是唯一的,用来解决命名冲突问题。Symbol值不能与其他数据进行运算也不能与自己运算。Symbol定义出来的对象属性不能遍历但可以使用Reflect.ownKeys来获取对象的所有键名。
- Symbol创建方式
1、通过let s2 = Symbol(‘张三’) 的方式创建Symbol,'张三’作为Symbol描述,作用相当于注释,这种方式创建的Symbol,即使传入的描述一致,但实际返回的值是不同的。
let s1 = Symbol('张三')
let s2 = Symbol('张三')
console.log(s1 === s2); //false
2、通过Symbol.for()创建Symbol,这种方式创建Symbol,传入的描述一致,实际返回的值也一致,可以得到唯一的Symbol值。
let s1 = Symbol.for('张三')
let s2 = Symbol.for('张三')
console.log(s1 === s2); //true
10、promise
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
特点:
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。
- Resolve与reject:resolve是对promise成功时候的回调,它把promise的状态修改为fullfiled,reject是失败的时候的回调,他把promise的状态修改为rejected。
Catch的用法:catch方法用来捕获异常,当回调失败后调用catch方法。 - all方法:该方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后并且执行结果都是成功的时候才执行回调。all接收一个数组参数,这组参数为需要执行异步操作的所有方法,里面的值最终都算返回Promise对象。
- Race方法:race方法是谁先执行完成就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的将不会再进入race的任何回调。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello')
reject('error')
}, 1000)
}).then(data => {
console.log(data)//hello
}).catch(error => {
console.log('error')
})
11、迭代器
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
工作原理:创建一个空指针指向当前数据结构的起始位置,第一次调用next方法指针自动指向数据结构的第一个成员,接下来不断调用next方法,指针不断向后移动直到指向最后一个成员。每次调用next方法都会返回一个具有value和done属性的对象,当遍历结束后done属性值为true。
const food = ['火锅', '水果', '蛋糕']
let iterator = food[Symbol.iterator]()
console.log(iterator.next());//{value: '火锅', done: false}
console.log(iterator.next());//{value: '水果', done: false}
console.log(iterator.next());//{value: '蛋糕', done: false}
console.log(iterator.next());//{value: 'undefined', done: true}
12、生成器
生成器就是通过构造函数Generator创造出来的对象,生成器既是一个迭代器,同时也是一个可迭代对象。
执行过程:第一次调用Generator函数开始执行,遇到第一个yield表达式截至,第二次调用Generator函数从上一次yield表达式停止的地方开始执行,知道遇到下一个yield表达式停止,第n-1次调用,Generator函数从上次yield表达式停下的地方,一直执行到return语句(如果没有return语句,就执行到函数结束),第n次调用,Generator函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true,第n次调用,Generator函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。(只有调用next才能执行当前yield代码)
function* fun() {
yield 'hello'
yield 'world'
return 'finish'
}
let g = fun()
console.log(g.next());//{value: 'hello', done: false}
console.log(g.next());//{value: 'world', done: false}
console.log(g.next());//{value: 'finish', done: true}
console.log(g.next());//{value: 'undefined', done: true}
13、Proxy与Reflect(拦截与反射)
Proxy可以对目标对象的读取、函数调用等操作进行拦截,然后对其进行操作处理,即对外界的访问进行过滤和改写。
基本语法:
let proxy=new Proxy(target,handler)
target为目标对象,当目标对象为空时可以用set属性向其中添加属性
handler为自定义操作方法的一个对象,当该对象为空时想当于不设置拦截操作,直接访问目标对象。
proxy是一个被代理后的新对象用于被用户访问。
基本使用:
const person = {
name: 'K',
age: '18',
sex: 'man'
}
let proxy = new Proxy(person, {
get(target, key) {
console.log(`即将获取到${key}的值`); //读取信息之前做的操作
return target[key] //将person上的值赋予到proxy新对象中
},
set(target, key, value) {
console.log(`修改${key}的值为${value}`); //修好age的值为20
target[key] = value
}
})
proxy.age = 20 //给proxy的key重新复制触发set
console.log(proxy.name); //K
常用代理操作:
-
getPrototypeOf(target) 当读取被代理对象target的原型prototype时会触发该操作。
-
setPrototypeOf(target, prototype) 给target设置prototype时触发。
-
isExtensible(target) 判断target是否可扩展时触发。
-
preventExtensions(target) 设置target不可扩展时触发。
-
getOwnPropertyDescriptor(target, prop) 获取target[prop]的属性描述时触发。
-
defineProperty(target, property, descriptor) 定义target的某个属性prop的属性描述descriptor时触发。
-
has(target, prop) 当判断target是否拥有属性prop时,触发。
-
get(target, property, receiver) 读取target的属性property时触发。
-
set(target, property, value, receiver) 设置target的属性property为值value时触发。
-
get中的receiver为Proxy或继承Proxy的对象。
-
set中的receiver是最初被调用的对象(通常是Proxy本身)。
-
deleteProperty(target, property) 删除target的属性property时触发。
-
ownKeys(target) 获取targeet的所有属性key s时触发。
-
apply(target, thisArg, argumentsList) 当目标target为函数,且被调用时触发。
-
construct(target, argumentsList, newTarget) 给target为构造函数的代理对象构造实例时触发。
Reflect是es6新增的一个全局对象,可以通过reflect直接拿到语言内部的方法,所有的方法都可以在object的原型链中找到。
基本使用:
let json = {
a: 1,
b: 2
}
//原来的写法
// delete json.a
// console.log(json); //{b:2}
//用反射的写法
Reflect.deleteProperty(json, 'a')
console.log(json);
常用反射方法:
-
Reflect.getPrototypeOf(target) 获取target的原型
-
Reflect.setPrototypeOf(target, prototype) 设置target的原型
-
Reflect.isExtensible(target) target是否可扩展
-
Reflect.preventExtensions(target) 阻止target的扩展性
-
Reflect.getOwnPropertyDescriptor(target, prop) 获取target的属性prop的描述器
-
Reflect.defineProperty(target, property, descriptor) 修改target的属性property为descriptor值
-
Reflect.has(target, prop) target是否有属性prop
-
Reflect.get(target, property, receiver) 读属性
-
Reflect.set(target, property, value, receiver) 写属性
-
Reflect.deleteProperty(target, property) 删除target的属性property
-
Reflect.ownKeys(target) 返回包含所有自身属性(继承的不算)的数组
-
Reflect.apply(target, thisArg, argumentsList) 对函数target进行调用操作,可传入thisArg可数组作为调用时的参数。
-
Reflect.construct(target, argumentsList, newTarget) 对构造函数进行new操作,即实例化。
14、Set
ES6提供了新的数据结构set(集合),本质上是一个对象。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用「扩展运算符」和for…of进行遍历。
Set的属性和方法:
- size返回set成员总数。
- add(value)增加某个值,返回set结构本身。
- delete(value)删除某个值,返回一个布尔值表示删除是否成功。
- has(value)返回一个布尔值,表示该值是否为set成员。
- clear()清除所有元素,没有返回值。
let s = new Set(['a', 'b', 'c', 'd'])
let size = s.size
let has = s.has('a')
s.add('e')
s.delete('a')
let has2 = s.has('a')
console.log(size, has, has2, s);//4,true,false,['b','c','d','e']
15、Map
ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用「扩展运算符」和for…of进行遍历。Map相比于Set而言多了get(key)方法,增加元素式用set(key,value)格式,其余方法都与set类似参数变为key返回value值。
let m = new Map()
let v = {
key: '键'
}
m.set('key', 'value')
m.set('method', function() {
console.log('我是一个值');
})
m.set(v, ['v1', 'v2', 'v3'])
m.delete('method')
let values = m.get(v)
let size = m.size
console.log(values, size, m);//['v1','v2','v3'],2,{key:value,{key:键}:['v1','v2','v3']}
16,filter
ES6中新增的过滤函数,其参数有三个value,index,arr,过滤函数内容写过滤条件,返回符合条件的新数组。
const nums = [10,40,100,30,200,50]
let newNums = nums.filter(function(n){
return n < 100
})
console.log(newNums);// [10, 40, 30, 50]
17、forEach
用来遍历数组,返回值。
let arr = ['a', 'b', 'c']
arr.forEach((value, index, arry) => {
console.log(value);//a,b,c
console.log(index);//0,1,2
console.log(arry);//['a','b','c']
});
18、some
对数组元素进行指定的逻辑判断,返回布尔值,数组中有一个值满足条件就返回true。
let arr = ['1', '2', '3']
let result = arr.some(item => item > 1)
console.log(result);//true
19、every
对数组元素进行指定的逻辑判断,返回布尔值,数组中所有值都满足条件则返回true。
let arr = ['1', '2', '3']
let result = arr.every(item => item > 1)
console.log(result);//false
20、find
找到一个符合条件的数组成员并立即返回找到的成员不会继续往下寻找。
let arr = ['1', '2', '3']
let result = arr.find(item => item > 1)
console.log(result);//2
21,findIndex
找到一个符合条件的数组成员,立即返回找到成员的位置,不会往下继续执行。
let arr = ['1', '2', '3']
let result = arr.findIndex(item => item > 1)
console.log(result);//1
22、includes
查看某个数组是否包含给定的值,第一个参数为待检查的值,第二个参数为检查开始的位置。返回一个布尔值。
let arr = ['1', '2', '3']
let result = arr.includes('3', 1)
console.log(result);//true
23、from
将类数组对象转化为真的数组,第一个参数为要转化的对象,第二个参数为对转化的数组执行的操作。该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。该类数组的属性名必须为数字或字符串型的数字。
let arr = [1, 2, 3]
let result = Array.from(arr, n => n + 1)
console.log(result);//[2,3,4]
24、of
该方法主要解决数组声明不一致的问题,传进取的参数都为数组的值。
let result = Array.of('abc')
console.log(result);//['abc']
25、reduce
对数组中的每个元素执行一个由我们提供的reducer函数(升序执行),将其结果汇总为单个返回值。reducer函数中有两个参数,第一个为回调函数,第二个为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。返回最终结果。
const nums = [10, 40, 100, 30, 200, 50]
let total = nums.reduce((prevalue, n) => prevalue + n, 0)
console.log(total);//430
26、map
map函数可以将原数组里面的值进行操作,并返回一个新数组。
const nums = [10,40,100,30,200,50]
let newNums = nums.map(function(n){
return n*2
})
console.log(newNums);// [20, 80, 200, 60, 400, 100]
27、freeze
该方法可以冻结一个对象,被冻结的对象不能再添加属性,删除属性,修改属性。
const obj = {
name: 'jack',
age: 18,
};
Object.freeze(obj)
obj.name = 'mack'
console.log(obj.name);//jack
28、is
该方法用来比较两个值是否严格相等,与严格运算符(===) 的行为基本一致。
let a = Object.is('foo', 'foo')
console.log(a);//true
29、assign
该方法用于合并对象,第一个参数为目标对象,第二个参数为原对象,返回合并后的对象。
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
c: 3,
d: 4
}
let newObj = Object.assign(obj1, obj2)
console.log(newObj);//{a:1,b:2,c:3,d:4}
30、setPrototypeOf
该方法作用与proto相同, 用来设置一个对象的prototype对象,返回参数对象本身。
31、getPrototypeOf
该方法用于获取一个对象的原型对象。
32、keys
Object.keys方法,返回一个数组,成员是参数对象自身的(不包含继承的) 所有可遍历的属性键名。
let obj = {
a: 1,
b: 2
}
let arr = Object.keys(obj)
console.log(arr);//['a','b']
33、values
Object.values方法,返回一个数组,成员是参数对象自身的(不包含继承的) 所有可遍历的属性值。
let obj = {
a: 1,
b: 2
}
let arr = Object.values(obj)
console.log(arr);//[1,2]
34、entries
Object.entries方法,返回一个数组,成员是参数对象自身的(不包含继承的) 所有可遍历的键值对。
let obj = {
a: 1,
b: 2
}
let arr = Object.entries(obj)
console.log(arr);//[['a',1],['b',2]]
35、Class
ES6引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基础语法:
- constructor:类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
- 调用方式:类必须使用new调用,否则会报错。这是它跟普通构造函数 ( 普通构造函数完全可以当做普通函数使用 ) 的一个主要区别,后者不用new也可以执行。
- getter和setter:对某个属性进行取值,存值的操作。
- Class的静态属性和方法:类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
- 类的继承:class通过 extends 关键字实现继承。super 关键字既可以当作函数使用,也可以当作对象使用。
- super 作为函数调用时表示父类的构造函数,用来新建父类的this对象。
子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。
如果子类没有定义 constructor 方法,那么这个方法就会被默认添加。
在子类的构造函数中,只有调用 super 方法之后才能够使用 this 关键字,否则会报错。
super 虽然代表了父类的构造函数,但是返回的是子类的实例,即 super 内部的 this 指定的是子类。
super () 只能用在子类的构造函数之中,用在其他地方会报错。 - super 作为对象时在普通方法中指向父类的原型对象;在静态方法中指向父类。
由于 super 指向父类的原型对象,定义在父类实例上的方法或属性是无法通过 super 调用的。如果定义在父类的原型上,super 就可以取到。
ES6规定,通过 super 调用父类的方法时,super 会绑定子类的 this。
如果 super 作为对象用在静态方法之中,这时 super 将指向父类,在普通方法之中指向父类的原型对象。
- Class的私有方法和私有属性:只能在类的内部访问的方法和属性,外部不能访问。属性前加#为私有属性,方法前加_为私有方法。
- 构造函数新属性:ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
class Father {
constructor(x, y) {
this.x = x
this.y = y
}
sum() {
let all = this.x + this.y
console.log(all);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y);
}
}
let son = new Son(1, 2)
son.sum()//3