ES6
全称ECMAScript 6.0
,是JavaScript
的下一个版本标准,2015.06 发版。ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念。es6新特性:Symbol
、class
、数值的扩展
、字符串的扩展
、数组的扩展
、对象的扩展
等
Symbol数据类型
Symbol
表示独一无二的值,它是js中的第七种数据类型.- 基本的数据类型:
null undefined number boolean string symbol bigInt
- 引用数据类型
object
1
2
3
4
5
6
7let s1 = Symbol('tew')
let s2 = Symbol('tew')
console.log(s1) // Symbol(tew)
console.log(s2) // Symbol(tew)
console.log(typeof s1) // symbol
console.log(s1==s2) // false
console.log(s1===s2) // false
- 基本的数据类型:
Symbol使用注意事项
Symbol
函数不能使用new否则会报错, 它是原始数据类型不是对象1
let s3 = new Symbol('tew') // Symbol is not a constructor
Symbol
函数接收一个字符串作为参数,表示对Symbol
的描述和区分,主要是为了在控制台显示,或者转为字符串的时候,比较容易区分. 字符串只是描述,不代表其他.Symbol
不能隐式转换,但可以显示转换为字符串或者布尔值,转换为Number的话会报错。1
2
3
4console.log(String(Symbol('tew'))) // Symbol(tew) string
console.log(Symbol('tew').toString()) // Symbol(tew) string
console.log(!Symbol('tew')) // false
console.log(Number(Symbol('tew'))) // Cannot convert a Symbol value to a numberSymbol
不能与其他值做任何运算,会报错1
console.log(Symbol('tew')+'1') // Cannot convert a Symbol value to a string
Symbol
作为对象的属性名使用时,属性不会出现在for in/of
中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回,不能使用点运算符1
2
3
4
5
6
7
8
9
10
11let yyy = Symbol('ss')
// 不能写成 {yyy: 'hello'} 需要加 []
const obj = {[yyy]: 'hello', a:2}
console.log(obj) // {a: 2, Symbol(ss): "hello"}
console.log(obj[yyy]) // hello
console.log(obj.yyy) // undefined
for (const i in obj) {
console.log(i) // a 未出现 Symbol(ss): "hello"
}
console.log(Object.keys(obj)) // ["a"]
console.log(JSON.stringify(obj)) // {"a":2}在直接使用symbol作为属性名的时候,只能使用通过
obj[Object.getOwnPropertySymbols(obj)[0]]
1
2
3
4
5
6
7
8
9const obj = {
[Symbol()]: 123,
a: 22
}
console.log(obj) // {a: 22, Symbol(): 123}
console.log(obj[Symbol()]) // undefined
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol()]
console.log(Object.getOwnPropertySymbols(obj)[0]) // Symbol()
console.log(obj[Object.getOwnPropertySymbols(obj)[0]]) // 123
Class类
传统方法是通过构造函数,定义并生成新对象,是一种基于原型的面向对象系统Es6中可以使用class声明一个类,之后以这个类来实例化对象
es5
传统方式1
2
3
4
5
6
7
8
9
10
11const Tew = function(a, b) {
this.a = a
this.b = b
}
Tew.prototype = {
constructor: Tew,
print: function(){
console.log(this.a + ' ' + this.b)
}
}
const tew = new Tew('hello', 'world').print() // hello worldes6
方式1
2
3
4
5
6
7
8
9
10class Tew{
constructor(a,b){
this.a = a
this.b = b
}
print(){
console.log(this.a +' ' + this.b)
}
}
new Tew('hello', 'world').print() // hello worldclass
使用注意事项- Tew中的constructor方法是构造函数,this关键字则代表实例对象,也就是说,es5中的构造函数Tew,对应Es6的Tew这个类的构造方法,主要用于初始化对象的属性
- 定义类的方法的时候,前面不需要加上function关键字,方法之间不需要逗号分隔,加了会报错
- 构造函数的prototype属性,在es6的类上继续存在,而且类的所有方法都定义在类的prototype属性上面
- 定义在类中的方法都是不可以被枚举的
- constructor方法是类的默认方法.通过new命令生成对象实例时,自动调用该方法.一个类必须有constructor方法,如没有显示定义,会默认添加一个空的contructor方法
- 用new实例化对象,如忘记使用new,将会报错
es6 class
类的继承1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Humen{
constructor(){
this.eyes = 2
this.hands = 2
}
say(){
console.log('I can say')
}
}
let humen = new Humen()
console.log(humen) // Humen {eyes: 2, hands: 2}
humen.say() // I can say
class Women extends Humen{
say(){
console.log('Women say')
}
}
let women = new Women()
console.log(women) // Women {eyes: 2, hands: 2}
women.say() // Women say- 子类继承父类使用
extends
关键字,为父类指定静态方法,使用static方法名 - 构造函数或方法是在类被实例化以后立刻调用的,可以用来传参
super
在构造函数中可以当一个函数来使用,相当于调用父类的构造函数super.父类方法
调用父类的方法super
在原型方法中,可以当一个对象来使用,相当于父类的原型对象,并且会自动绑定this到子类上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
32class Humen{
constructor(){
this.eyes = 2
this.hands = 2
}
say(){
console.log('I can say')
}
}
class Thief extends Humen{
constructor(){
super() // 子类继承父类必须调用父类的构造函数 必须放在第一句
// 子类可以增加或修改父类的属性
this.hands = 3
this.face = 1
}
// 重写父类的方法
say(){
super.say() // 调用父类的方法
console.log('Thief say')
}
// 子类扩展的方法
run(){
console.log('Thief run')
}
}
let thief = new Thief()
console.log(thief) // Thief {eyes: 2, hands: 3, face: 1}
console.log(thief.hands) // 3
console.log(thief.face) // 1
thief.say() // Thief say
thief.run() // Thief run
- 子类继承父类使用
静态方法 es5中类的方法是静态方法
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// es5 静态方法只能通过 类名.静态方法名() 调用,不能使用对象实例调用
function Animal(type){
this.type = type
this.walk = function(){ console.log('对象实例的方法') }
}
Animal.eat = function() { console.log('定义在类上的静态方法') }
var dog = new Animal('dog')
dog.walk() // 对象实例的方法
Animal.eat() // 定义在类上的静态方法 只能通过类去调用
dog.eat() // dog.eat is not a function
//es6 静态方法只能通过 类名.静态方法名() 调用,不能使用对象实例调用
class People {
constructor(){
this.name = name
}
walk (){
console.log('普通方法')
}
static eat (){
console.log('静态方法')
}
}
let people = new People('tew')
people.walk() // 普通方法
People.eat() // 静态方法
people.eat() // people.eat is not a function
数值的扩展
Math.trunc(num)
干掉小数点,返回整数部分。Math.sign(num)
判断参数是正数,负数,正0还是负0,是正数时返回1 ,是负数时返回-1,0的时候返回0,-0的时候返回-0,NaN,对于非数值,会先将其转换为数值。Math.hypot(3,4)
返回参数的平方和的平方根(勾股定理)Math.cbrt(8)
返回参数的立方根Number.isInteger(num)
判断是否是整数 数值3.0和3.00都会被认为是整数。Number.isNaN(num)
用来检查一个值是否为NaN,只有NaN才返回true,非NaN返回false1
2
3
4
5
6
7
8
9
10
11
12
13
14console.log(Math.trunc(1.634)) // 1
console.log(Math.sign(5)) // 1
console.log(Math.sign(-5)) // -1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-0)) // -0
console.log(Math.sign(NaN)) //NaN
console.log(Math.sign(null)) // 0
console.log(Math.hypot(3,4)) // 5
console.log(Math.cbrt(8)) // 2
console.log(Number.isInteger(3.0)) // true
console.log(Number.isInteger(3.1)) // false
// Number.isNaN() 与 isNaN() 的区别,isNaN先调用Number()转换在判断, Number.isNaN() 只对数值有效
console.log(isNaN('NaN')) // true
console.log(Number.isNaN('NaN')) // false
字符串的扩展
模板字符串 在模板字符串中使用
${'字符串'|'运算符'|变量}
${表达式}
插值1
2
3
4
5
6
7let flag = true, text = '模板字符串'
let html = `
<ul>
<li>${text.slice(0,2)}</li>
<li class="${flag?'show':'hide'}">${text}</li>
</ul>`
console.log(html)//<ul><li>模板</li><li class="show">模板字符串</li></ul>str.repeat(n)
重复n个相同的字符串str.includes('a')
字符串中是否包含某字符str.startsWith('a')
字符串是否以某字符开头str.endsWith('a')
字符串是否以某字符结尾1
2
3
4
5
6
7
8
9let str = 'abca'
console.log(str.repeat(2)) // abcaabca
console.log(str) // abca
console.log(str.includes('a')) // true
console.log(str.includes('d')) // false
console.log(str.startsWith('a')) // true
console.log(str.startsWith('b')) // false
console.log(str.endsWith('a')) // true
console.log(str.endsWith('b')) // falsestr.padStart(2,'0')
向前填充字符str.padEnd(2,'0')
向后填充字符1
2
3
4
5
6
7
8
9
10
11
12
13// 第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串
console.log('1'.padStart(2, '0')) // 01
console.log('01'.padStart(2, '0')) // 01
console.log('1'.padEnd(2, '0')) // 10
console.log('10'.padEnd(2, '0')) // 10
let date = new Date()
console.log(date.getHours().toString().padStart(2, '0') + '时') // 09时
console.log(date.getMinutes().toString().padStart(2, '0') + '分') // 08分
// 如果省略第二个参数 默认使用空格补全长度
console.log('a'.padStart(5)) // ' a'
console.log('a'.padEnd(5)) // 'a '
// 如果补全的字符串和原字符串的长度之和 小于指定的长度 会截去超出位数进行补全
console.log('abc'.padStart(10, '0123456789')) // 0123456abc => 789 被截掉用 abc补全
数组的扩展
Array.from()
将类数组或可遍历的对象转化成真正的数组如NodeList arguments string Set Map
等1
2
3
4
5
6
7
8
9let lis = document.querySelectorAll('li');
console.log(Array.isArray(lis)) // false
let lis2 = Array.from(lis)
console.log(Array.isArray(lis2)) // true
console.log(Array.from('hello')) // ['h', 'e', 'l', 'l', 'o']
console.log(Array.from(new Set(['a', 'b']))) // ['a', 'b']
// Array.from(arg, callback) 可以接收第二个参数,作用类似数组的map方法,对每个元素处理后放回数组中
let items = document.querySelectorAll('.item')
console.log(Array.from(items, s => s.innerText))Array.of(e1,e2,…)
按顺序创建包含每个参数的数组,不考虑参数的数量和数据类型1
2
3
4
5
6
7
8
9// Array.of()和Array()区别在于处理整数参数
// Array(n) n个长度的undefiend数组
// Array.of(n) 一个长度的数组 [n]
console.log(Array.of(1, 'a', {}, [], true)) // [1, "a", {…}, Array(0), true]
console.log(Array(1, 'a', {}, [], true)) // [1, "a", {…}, Array(0), true]
console.log(Array.of(7)) // [7]
console.log(Array(7)) // (7) [,,,,,,]
console.log(Array(7).length) // 7
console.log(Array(7)[1]) // undefinedarr.find()
返回数组中第一个符合条件的数组元素,否则返回undefined
arr.findIndex()
返回数组中第一个符合条件的数组元素的索引,否则返回-1
1
2
3
4
5
6
7
8
9const arr = [1, '2', '3', true]
let resFind = arr.find((item)=>{
return item > 1
})
let resFindIndex = arr.findIndex((item)=>{
return item > 1
})
console.log(resFind) // '2'
console.log(resFindIndex) // 1arr.fill()
用固定值填充数组中从指定起始索引到指定终止索引内的全部元素,不包括终止索引。(会改变原数组
)1
2
3
4const arr = [1, '2', true]
// console.log(arr.fill('a')) // ["a", "a", "a"]
// console.log(arr.fill('a', 1)) // [1, "a", "a"]
console.log(arr.fill('a', 1, 2)) // [1, "a", true]arr.includes()
检测数组是否包含某元素,可判断NaN
1
2
3
4let arr = [1, NaN, 'a']
console.log(arr.includes(1)) // true
console.log(arr.includes(NaN)) // true
console.log(arr.includes('b')) // false扩展运算符(spread)…
将类数组转为用逗号分隔的参数序列,好比rest参数的逆运算1
2
3
4
5
6
7
8
9
10var arr = [1,4,7,3,2,11]
var str = 'tew'
console.log(...arr) // 1 4 7 3 2 11
console.log(...str) // t e w
console.log(Math.max.apply(null,arr)) // 11
console.log(Math.max(...arr)) // 11 => Math.max(1,4,7,3,2,11)
// 扩展运算符与解构赋值结合使用
const [first, ...arr] = [1, 2, 3]
console.log(first) // 1
console.log(arr) // [2, 3]
对象的扩展
使用
扩展运算符(spread)…
取出参数对象的所有可遍历属性,拷贝到当前对象之中(浅拷贝)1
2
3
4
5
6
7
8
9// 展开一个对象
let obj = {a:1, b:2}
let obj1 = {
c:'children',
name:'tew',
...obj
}
console.log({...obj}) // {a: 1, b: 2} 可以浅拷贝对象
console.log(obj1) //{c: "children", name: "tew", a: 1, b: 2}对象属性名和属性值相同时可简写, 属性可以是表达式,对象的方法简写可省略
:function
1
2
3
4
5
6
7
8
9
10
11let a = 1
let b = 'c'
const obj = {
a, // 属性名和值相同时可简写
[b+a]: '3', // 属性可以使表达式
say () { // 对象方法简写
console.log(this.a + '--' + this[b+a])
}
}
console.log(obj) // {a: 1, c1: "3", say: ƒ}
obj.say() // 1--3Object.is(a,a)
比较两个值是否相等 多数情况下Object.is等价于”===”,可以判断NaN,但-0
和0
不相等1
2
3
4
5
6
7console.log(Object.is(1,1)) // true
console.log(Object.is(null,null)) // true
console.log(Object.is(undefined,undefined)) // true
console.log(NaN === NaN) // fasle
console.log(Object.is(NaN,NaN)) // true
console.log(Object.is(0,-0)) // false
console.log(Object.is(+0,-0)) // falseObject.keys()
返回一个数组,数组中每一项是对象中可被遍历的键名Object.values()
返回一个数组,数组中每一项是对象中可被遍历的键值Object.entries()
返回一个数组,数组中每一项是对象中可被遍历的键值对数组Object.getOwnPropertyNames()
返回一个数组,由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成。Object.getOwnPropertyDescriptors(obj)
返回对象所有属性的描述对象Object.getOwnPropertyDescriptor(obj, 'a')
返回指定属性的描述对象Object.getOwnPropertySymbols(obj)
方法返回一个给定对象自身的所有Symbol
属性的数组。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
30let a = 1
let b = 'c'
const obj = {
a, // 属性名和值相同时可简写
[b+a]: '3', // 属性可以使表达式
say () { // 对象方法简写
console.log(this.a + '--' + this[b+a])
},
[Symbol('tew')]:'hello'
}
console.log(obj) // {a: 1, c1: "3", Symbol(tew): "hello", say: ƒ}
console.log(Object.keys(obj)) // ["a", "c", "say"]
Object.defineProperty(obj, 'a', {
enumerable: false //是否可枚举 默认值为true
})
console.log(Object.keys(obj)) // ["c", "say"]
console.log(Object.getOwnPropertyNames(obj)) // ["a", "c", "say"]
console.log(Object.values(obj)) // ["3", ƒ]
console.log(Object.entries(obj)) //[["c", "3"],["say", ƒ]]
console.log(Object.getOwnPropertyDescriptors(obj))
/* {
a: {value: 1, writable: true, enumerable: false, configurable: true}
c1: {value: "3", writable: true, enumerable: true, configurable: true}
say: {writable: true, enumerable: true, configurable: true, value: ƒ}
Symbol(tew): {value: "hello", writable: true, enumerable: true, configurable: true}
} */
console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
//{value: 1, writable: true, enumerable: false, configurable: true}
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(tew)]Object.assign(target,[obj1])
用于对象的合并,将源对象的所有可枚举属性,复制到目标对象target中,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性.String
类型和Symbol
类型的属性都会被拷贝 只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false) 是浅拷贝而不是深拷贝1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16let a = 1
let obj = {
a,
[Symbol('tew')]:'hello',
say () {
console.log(this.a + '--' + this[b])
}
}
console.log(Object.assign({a:3}, obj)) // {a: 1, Symbol(tew): "hello", say: ƒ}
// 如果只有一个参数,会直接返回该参数,不是对象则会先转成对象.
console.log(Object.assign(obj)) // {a: 1, Symbol(tew): "hello", say: ƒ}
console.log(Object.assign(2)) // Number {2}
// 如果一个参数是null或undefiend无法转成对象则会报错
console.log(Object.assign(null)) // Cannot convert undefined or null to object
// console.log(Object.assign(undefined)) //Cannot convert undefined or null to object
// 如果Object.defineProperty()
添加/修改属性 或 自定义Setters
和Getters
(Vue2双向绑定原理就是基于此)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/* 添加/修改属性 */
obj2 = {x: 1}
Object.defineProperty(obj2, 'y', {
//描述或设置了该属性的细节
value: 100, // 设置的值
writable: true, //是否可被改写 默认值为true
enumerable: true, //是否可枚举 默认值为true
configurable: true //是否可被删除 默认值为true
})
console.log(obj2) // {x: 1, y: 100}
obj2.y = 200 // 改写
for (const key in obj2) {
//枚举属性
console.log(key + '--' + obj2[key]) // x--1 y--200
}
delete obj2.y // 可删除
console.log(obj2) // {x: 1}
/* 自定义 Setters 和 Getters 实现简单的双向绑定 */
//<input type="text" id="model"><br/>
//<div id="modelText"></div>
let user = {}
modelText.textContent = model.value = '默认值'
Object.defineProperty(user,"name",{ // 监听name属性改变
get:function(){
return defaultName
},
set:function(newValue){
modelText.textContent = newValue
}
})
model.addEventListener("keyup", function () {
user.name = this.value
}, false)