- ECMAScript6.0 (es6/es2015)
介绍
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了
它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言 -
ECMAScript 和 JavaScript 的关系
JavaScript由DOM BOM ECMAScript标准组成
es6+
node.js(node的框架 express koa2) => 运行环境
前端工程化的概念都是建立在node的基础上 => 模块化 => 组件化
高内聚 低耦合 -
let和const
let
作用域只限于当前代码块
- let声明的变量作用域不会被提升
- 暂时性死区只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响
var a = 10;
{
console.log(a)
let a = 20
}
for (let i = 1; i <= 10;i++) {
let i = 10
console.log(i)
}
console.log(i)
块级作用域
function f1() {
let n = 5
if (true) {
let n = 10
}
console.log(n)
}
- 一对大括号的范围为一个块级作用域允许块级作用域的任意嵌套
{{{{
{let insane = ‘Hello World’}
console.log(insane)
}}}}
{{{{
let insane = ‘Hello World’
{let insane = ‘Hello World’}
}}}}
const
- 声明一个只读的常量。一旦声明
对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量
但对于复合类型的数据(主要是对象和数组),变量指向的内存地址
保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址)
至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心
const foo = {}
常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,
但对象本身是可变的,所以依然可以为其添加新属性
变量的解构赋值
- 从数组和对象中提取值,对变量进行赋值,这被称为解构
对象解构
let obj = {name : ‘张三’, age: 18, color : ‘女’}
let {name, age, color:sex} = obj
console.log(name, age, sex)
属性名和值是同样的名字, 可以只写为属性名
let obj = {
p: [
‘Hello’,
{ y: ‘World’ }
]
}
let { p: [x, { y }] } = obj
console.log(x)
console.log(y)
这时p是模式,不是变量,因此不会被赋值
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
}
let { loc, loc: { start }, loc: { start: { line }} } = node
console.log(loc)
console.log(start)
console.log(line)
PS: 冒号后面的才会被赋值
-
默认值
let {x = 3} = {}
console.log(x)let {x, y = 5} = {x: 1}
console.log(x)
console.log(y)let {x: y = 3} = {x: 5}
console.log(y) -
默认值生效的条件是,对象的属性值严格等于undefined
let {x = 3} = {x: undefined}
console.log(x)let {x = 3} = {x: null}
console.log(x)
数组结构
let arr = [1, 2, 3, 4, 5, 6]
let [a,b, …c] = arr
console.log(a,b,c)
let [ , , third] = [‘foo’, ‘bar’, ‘baz’]
console.log(third)
let [x, , y] = [1, 2, 3]
console.log(x)
console.log(y)
let [x, y, …z] = [‘a’]
console.log(x)
console.log(y)
console.log(z)
如果解构不成功,变量的值就等于undefined
不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功
let [x, y] = [1, 2, 3]
console.log(x)
console.log(y)
let [a, [b], d] = [1, [2, 3], 4]
console.log(a)
console.log(b)
console.log(d)
如果等号的右边不是数组 那么将会报错
// 报错
let [foo] = 1
let [foo] = false
let [foo] = NaN
let [foo] = undefined
let [foo] = null
let [foo] = {}
默认值
let [foo = true] = []
console.log(foo)
let [x, y = ‘b’] = [‘a’]
let [x, y = ‘b’] = [‘a’, undefined]
console.log(x)
console.log(y)
PS: ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效
let [x = 1] = [undefined]
console.log(x)
let [x = 1] = [null]
console.log(x)
字符串解构
- 对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let str = ‘abcd’
let [y1,y2,y3,y4] = str
console.log(y1,y2,y3,y4)
let {length : len} = ‘hello’
console.log(len)
变量值交换
let x = 5
let y = 10
[x,y] = [y,x]
console.log(x,y)
从函数返回多个值
function example() {
return [1, 2, 3]
}
let [a, b, c] = example()
function example() {
return {
foo: 1,
bar: 2
}
}
let { foo, bar } = example()
提取json数据
let jsonData = {
id: 42,
status: “OK”,
data: [867, 5309]
}
let { id, status, data: number } = jsonData
console.log(id, status, number)
函数参数的默认值
function (name = ‘jack’, age = 18){}
输入模块的指定方法
let {username} = ctx.request.body
const { SourceMapConsumer, SourceNode } = require(‘source-map’)
字符串扩展
- includes():返回布尔值,表示是否找到了参数字符串。
let s = ‘Hello world!’
s.startsWith(‘Hello’)
s.endsWith(’!’)
s.includes(‘o’)
-
这三个方法都支持第二个参数,表示开始搜索的位置
let s = ‘Hello world!’
s.startsWith(‘world’, 6)
s.endsWith(‘Hello’, 5)
s.includes(‘Hello’, 6) -
repeat: 方法返回一个新字符串,表示将原字符串重复n次
‘x’.repeat(3)
‘hello’.repeat(2)
‘na’.repeat(0)参数如果是小数,会被向下取整, 参数不能负数或者Infinity, 参数是 0 到-1 之间的小数,则等同于 0
-
padStart: 用于头部补全,
-
padEnd: 用于尾部补全
‘x’.padStart(5, ‘ab’)
‘x’.padStart(4, ‘ab’)
‘x’.padEnd(5, ‘ab’)
‘x’.padEnd(4, ‘ab’) -
第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串
-
如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串
‘xxx’.padStart(2, ‘ab’)
‘xxx’.padEnd(2, ‘ab’) -
如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串
‘abc’.padStart(10, ‘0123456789’) -
如果省略第二个参数,默认使用空格补全长度
模板字符串
中间写内容 变量用${变量名}表示
- 内容可以是文字 变量 html代码
函数扩展
函数参数可以设置默认值
function log(x, y = ‘World’) {
console.log(x, y)
}
使用参数默认值时,函数不能有同名参数
rest参数
用于获取函数的多余参数,这样就不需要使用arguments对象了
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中
function add(…values) {
let sum = 0
for (var val of values) {
sum += val
}
return sum
}
add(2, 5, 3)
rest 参数之后不能再有其他参数
function f(a, …b, c) {
// …
}
name属性
函数的name属性,返回该函数的函数名
function foo() {}
console.log(foo.name)
箭头函数
let f = (v) => {
console.log(v)
}
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => {
return 123
}
如果箭头函数只有一个参数,可以省略小括号
let f = v => {
return v
}
如果箭头函数函数体只有一句语句,可以省略{}
let f = v => v
注意点
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
正是因为它没有this,所以也就不能用作构造函数
数组扩展
扩展运算符(…)
将一个数组转为用逗号分隔的参数序列
[…‘hello’]
console.log(…[1, 2, 3])
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
let arr3 = […arr1, …arr2]
Array.from
方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组
Array.from([1, 2, 3], (x) => x * x)
Array.of
方法用于将一组值,转换为数组
Array.of(3, 11, 8)
Array.of(8)
filter
方法用于过滤数组,返回一个新数组,可以传入3个参数,item(数组的每一项) index(数组每一项的下标) arr(原数组本身)
有返回值 返回过滤的条件
let arr = [1, 5, 17, 23, 33, 55].filter((item, index, arr) => {
return item > 20
})
map
方法用于映射数组, 可以传入3个参数,item(数组的每一项) index(数组每一项的下标) arr(原数组本身)
find 和 findIndex
find方法,用于找出第一个符合条件的数组成员。
它的参数是一个回调函数,所有数组成员依次执行该回调函数,
直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
[1, 4, -5, 10].find(n => n < 0
find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组
[1, 5, 10, 15].findIndex((value, index, arr) =>{
return value > 9
})
findIndex方法返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
[1, 5, 10, 15].findIndex((value, index, arr) =>{
return value > 9;
}
fill
方法使用给定值,填充一个数组
[‘a’, ‘b’, ‘c’].fill(7)
new Array(3).fill(7)
fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去
fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
[‘a’, ‘b’, ‘c’].fill(7, 1, 2)
fill方法从 1 号位开始,向原数组填充 7,到 2 号位之前结束
如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象
entries,keys 和 values
可以用for…of循环进行遍历
唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
for (let index of [‘a’, ‘b’].keys()) {
console.log(index)
}
for (let elem of [‘a’, ‘b’].values()) {
console.log(elem)
}
for (let [index, elem] of [‘a’, ‘b’].entries()) {
console.log(index, elem)
}
includes
方法返回一个布尔值,表示某个数组是否包含给定的值
[1, 2, 3].includes(2)
[1, 2, 3].includes(4)
[1, 2, NaN].includes(NaN)
该方法的第二个参数表示搜索的起始位置,默认为0如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始[1, 2, 3].includes(3, 3)[1, 2, 3].includes(3, -1)
flat
用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响
[1, 2, [3, 4]].flat()
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,
可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1
[1, 2, [3, [4, 5]]].flat()
[1, 2, [3, [4, 5]]].flat(2)
如果原数组有空位,flat()方法会跳过空位
[1, 2, , 4, 5].flat()
对象的扩展
属性名为变量名, 属性值为变量的值
方法也可以简写
“
属性名表达式
// 方法一
obj.foo = true
// 方法二
obj[‘a’ + ‘bc’] = 123
可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象
let obj = { foo: 123 }
console.log(Object.getOwnPropertyDescriptor(obj, ‘foo’))
描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性
属性的遍历
for…in
for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名
Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
对象新增方法
Object.assign
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
const target = { a: 1 }
const source1 = { b: 2 }
const source2 = { c: 3 }
Object.assign(target, source1, source2)
console.log(target)
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
const target = { a: 1, b: 1 }
const source1 = { b: 2, c: 2 }
const source2 = { c: 3 }
Object.assign(target, source1, source2)
console.log(target)
如果只有一个参数,Object.assign会直接返回该参数
const obj = {a: 1};
Object.assign(obj) === obj
如果该参数不是对象,则会先转成对象,然后返回
typeof Object.assign(2)
由于undefined和null无法转成对象,所以如果它们作为参数,就会报错
注意点
浅拷贝
Object.assign方法实行的是浅拷贝,而不是深拷贝
也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
const obj1 = {a: {b: 1}}
const obj2 = Object.assign({}, obj1)
obj1.a.b = 2
console.log(obj2.a.b)
同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加
const target = { a: { b: ‘c’, d: ‘e’ } }
const source = { a: { b: ‘hello’ } }
Object.assign(target, source)
Object.keys(),Object.values(),Object.entries()
Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
var obj = { foo: ‘bar’, baz: 42 }
Object.keys(obj)
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值
const obj = { foo: ‘bar’, baz: 42 };
Object.values(obj)
如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组
Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
const obj = { foo: ‘bar’, baz: 42 };
Object.entries(obj)