ECMAScript通常被认为是JavaScript的标准化规范,实际JavaScript是ECMScript的扩展语言,ECMAScript只定义提供最基本的语法。
我们通常所说的ES6指的是ES2015、ES2016、ES2017……等,所以ES6泛指所有的新版本。
ES6是在ES5.1的基础上进行的升级:
① 解决了原有语法的上的一些问题或不足
②对原有语法进行了增强
③全新的对象,全新的语法,全新的功能
④全新的数据类型和数据结构
一、作用域——某个成员(变量)能起作用的范围
在ES6中的作用域分为:全局作用域、函数作用域、块级作用域
用 var 定义的变量存在变量提升,属于全局范围。
当用var定义变量是为全局变量,在双层循环中。下面代码返回值为 0 1 2 内层结束 i=3,得到的结果与预期不符
for (var i = 0; i < 3; i++) {
for (var i = 0; i < 3; i++) {
console.log(i)
}
console.log('内层结束 i=' + i)
}
let 只能在所声明的代码块中使用,外部无法访问,只能先声明变量,才能使用。
下面代码中,使用 let 定义变量,只能在所处的代码块中使用,互不影响,得到的结果符合预期,结果如下:
第一次循环:0 1 2 内层结束 i=0,第二次循环0 1 2 内层结束 i=1,第三次循环0 1 2 内层结束 i=2
for (let i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++) {
console.log(i)
}
console.log('内层结束 i=' + i)
}
看下面代码,用let定义变量是处于一个块作用域中的,在每次循环的过程中,let i= i+1 都是处于一个新的块级作用域中的,与之前的 i 互不干扰,所以调用 elements[0].onclick() 会得到预期的值。 若将 let i =0 改为 var i=0,则所有调用结果都为 3。
var elements = [{}, {}, {}]
for (let i = 0; i < elements.length; i++) {
elements[i].onclick = function() {
console.log(i)
}
}
elements[0].onclick() // 0
elements[1].onclick() // 1
elements[2].onclick() // 2
上面代码的不同结果,是因为变量所处的作用域不同,var 属于全局作用域,都可以修改,而 let 处于块级作用域,只能在所处的代码块中进行修改,使用。
二、下面讲一些新特性
1. const 常量 (在 let 的基础上多了个只读的特性)
const 常量在声明的同时必须赋初值,否则会报语法错误:SyntaxError: Missing initializer in const declaration
不允许在声明过后重新指向内存地址(并不是不能去修改常量中的属性成员)
//新定义,再赋值,报错
const aa
aa = 'dd'
//声明后,重新指向新的内存地址,报错
const name = 'ddd'
name = 'ccc'
//声明常量,为常量中的属性成员赋值
const obj = {}
obj.name = 'zzz'
console.log(obj.name)
2. 解构 (数组的解构 和 对象的解构)
(1) 数组的解构
在ES6中, 以 ... 接收当前元素到最后的所有剩余元素。三个点的方式只能用于最后的解构位置。若解构的元素位置大于数组长度,则对应的值为undefined
const arr = [100, 200, 300]
const [foo, bar, dd] = arr
console.log(foo, bar, dd)
const [foo, ...ree] = arr
console.log(ree)
(2) 对象的解构
与数组方式基本一致,根据属性名去提取对应的属性值,当属性名发生冲突时,可以起别名的方式
const obj = {
name: 'zs',
age: 22
}
//根据属性名提取对应的属性值
const { age } = obj
console.log(age)
//当发生冲突时,可以起别名
const name = 'tom'
const { name: Oname } = obj
console.log(Oname)
3. 模板字符串
(1) 字面量
用反引号定义 => ` `,支持转义字符,支持换行,可以使用插值表达式 ${name}
const str = `hello es2015 \`hi\``
const str = `hello es2015,
hi haow ` //支持换行
console.log(str)
const name = 'tom'
const msg = `heym,${name}`
console.log(msg)
(2) 标签函数
在定义模板字符串之前,添加一个标签,这个标签就是一个特殊的函数,添加标签即调用函数。标签函数的作用对模板字符串进行加工。 如下面代码 gender 的加工
下面代码中,strings接收的是模板字符串的字符,以数组的形式, name和gender接收的是模板字符串的插值表达式
const name = 'tom'
const gender = true
function MyTgeFun(strings, name, gender) {
// console.log(strings, name, gender) // 打印结果[ 'hey,', ' is a ', '.' ] tom true
const sex = gender ? 'man' : 'woman'
return strings[0] + name + strings[1] + sex + strings[2]
}
const result = MyTgeFun `hey,${name} is a ${gender}.`
console.log(result) // hey,tom is a man.
4. 字符串的扩展方法
字符串的查找方法
- includes('string') 判断字符串中是否存在string
- startsWith('string') 判断字符串是否以string开头
- endsWith('string') 判断字符串是否以string结尾
// 字符串的扩展方法
const message = 'Error: foo is not defined'
// 字符串是否已Error开头。用startsWith
console.log(message.startsWith('Error')) //开头 true
console.log(message.endsWith('d')) //结尾 true
console.log(message.includes('fodo')) //中间 fasle
5. 默认值
在定义函数时,可以给形参赋值,若调用时,接收的参数少于形参,则形参就采用默认值
function foo(bar, enable = true) {
console.log('foo invoked - enable: ')
console.log(enable)
}
foo('fs') // foo invoked - enable: true
foo('fs','defult') // foo invoked - enable: defult
6.剩余参数
我们知道,可以使用arguments伪数组的形式接收,而es6中出现了 ... 操作符
// 剩余参数
foo(1, 2, 3, 4)
//arguments
function foo() {
console.log(arguments) // [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4 }
}
// ...
function foo(...args) {
console.log(args) // [ 1, 2, 3, 4 ]
}
7.展开数组
apply(this,arry),第一个参数为this指向,第二个为数组。也可以使用 ... 操作符
// 展开设置参数
const arr = ['fpp', 'ff', 'sdd']
// 一个一个传,当参数不确定时,无法进行
// console.log(
// arr[0],
// arr[1],
// arr[2]
// )
// apply() 第一个参数this的指向,第二个数组
console.log.apply(console, arr)
console.log(...arr)
8.箭头函数
(1)箭头函数简单使用
代码简单易读,下面代码为 filter方法普通函数与箭头函数的对比。
const arr = [1, 2, 3, 4, 5, 6, 7]
arr.filter(function(item) {
return item % 2
})
const aa = arr.filter(i => i % 2)
console.log(aa)
console.log(11)
(2) 箭头函数与this
箭头函数不会改变this的指向,因为箭头函数中无this机制,所以箭头函数内的this指向与箭头函数外相同。即箭头函数指向当前作用域的this
// 箭头函数与this
const person = {
name: 'tom',
sayhi: function() {
console.log(`hi, my namae is ${this.name}`)
// this指向person对象
console.log(this)
},
}
person.sayhi()
//输出为
hi, my namae is tom
{ name: 'tom', sayhi: [Function: sayhi] }
9.对象字面量增强
计算属性名: [Mth.random]: 属性值; 方法不加function: methods () { }
// 对象字面量
// 可以使用表达式的返回值作为对象属性名
const bar = 'e45';
const obj = {
foo: 123,
// bar:bar
bar,
methods1: function() {
console.log('methods1')
},
methods2() {
console.log('methods2')
},
// Math.random():123
[Math.random()]: 222 //计算属性名
}
// obj[Math.random()] = 123
console.log(obj)
obj.methods1()
obj.methods2()
10.对象扩展方法
(1) assign:将多个源对象中的属性复制到一个目标中,若属性值相同,则覆盖,若无此属性值,则添加。复制对象到全新的对象中去,修改不会影响外部数据。可以用于对obj对象参数设置默认值。
function func(obj) {
// obj.name = 'func obj'
// console.log(obj)
const funcObj = Object.assign({}, obj) //复制obj对象到一个空对象
funcObj.name = 'funcObjk' //修改新对象的name属性
console.log(funcObj)
}
const obj = { name: 'global obj' }
func(obj) //打印 funcObj 对象
console.log(obj) //打印obj对象
/*--------打印结果-------------*/
{ name: 'funcObjk' }
{ name: 'global obj' }
(2) Object.is 用于判断两个值是否相等
//Object.is 与 === 对比
console.log(NaN === NaN) //false
console.log(Object.is(NaN, NaN)) //true
console.log(+0 === -0) //true
console.log(Object.is(+0, -0)) //false