ES6 已经是前端人员必备的知识技能,系统化学习ECMAScript是很有必要的。
ECMAScript概述
通常将ECMAScript看作是JavaScript的标准规范,但实际上JavaScript是ECMAScript的扩展语言。ECMAScript只是提供了最基本的语法,JavaScript在语言基础上进行了扩展。 JavaScript语言本身指的就是ECMAScript。
ES2015概述
ES2015开始按照年份开始命名,很多人习惯将ES2015或之后的新版本称之为ES6。实际工作中,注意分辨ES6是特指还是泛指。
ES2015官网
ES2015主要更新:
解决原有语法上的一些问题或者缺陷
对原有语法进行增强
全新的对象、全新的方法、全新的功能
全新的数据类型和数据结构
准备工作
任何一个支持Es2015的环境都可以: node.js或者最新版本的Chrome浏览器或者在VScode软件中使用Chrome调试。使用VScode的话,需要安装以下插件:
- Debugger for Chrome
- Live Server
- Browser Preview
let 和块级作用域
- 全局作用域: ES5及之前
- 函数作用域: ES5及之前
- 块级作用域:ES2015及之后
被{}包围的部分被称之为块级作用域。
// 通过循环批量添加事件
// 通过 let 定义变量,只能在块级内部被调用
var eles = [{}, {}, {}];
for (let i = 0 ; i < eles.length ; i++) {
eles[i].onclick = function () {
console.log(i);
}
}
eles[0].onclick();
// 循环 实际上有两层作用域
for (let i = 0 ; i < 10 ; i++) {
let i = "foo";
console.log(i);
}
let i = 0;
if (i < 10) {
let i = "foo";
console.log(i);
}
i++;
// 和 var 有另外一个区别,let 不会进行变量声明提升
console.log(a);
// var a = 1;
let a = 2;
const
在let的基础上增加了一个【只读】的效果,不允许修改,且有块级作用域
const name = "zs";
name = "ls";// 会报错,不能修改const类型变量的值
// 声明的时候必须同时赋初值
const name ;// 会报错,声明的时候必须同时赋初值
name = "zs";
const obj = {};
obj.name = "zs";// 不会报错,因为没有改变指针,只是给指针指向的地址增加内容
obj = {};// 会报错,不能更改指针
最佳实践:不用var,主用const,配合let
var会有变量声明提升等问题,所以尽量不用。主用const来声明,实在要修改变量值就用let声明。会让代码质量有很大提高。
数组的解构
const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz)// 输出100 200 300
const arr = [100, 200, 300]
const [, , baz] = arr
console.log(baz)// 输出300
const arr = [100, 200, 300]
const [foo, ...rest] = arr
console.log(rest)// ...表示获取foo之后的值[200, 300]赋给rest
const arr = [100, 200, 300]
const [foo] = arr
console.log(foo)// 输出100。只有一个变量就只获取第一个值
const arr = [100, 200, 300]
const [foo, bar, baz = 400, more = 123] = arr
console.log(more)// 输出123。超出数组范围,没能从arr获取值,输出默认值123
console.log(baz)// 输出300。上述算式中,先进行赋值得到默认值400,再进行解构,得到300
const path = "foo/bar/baz"
// const temp = path.split("/")
// const a = temp[1]
const [,,a] = path.split("/")// 数组解构方式赋值
console.log(a)
对象的解构
// 对象解构
const obj = { name: 'zs', age: 18 }
const { name } = obj //从obj对象解构得到同名属性值,赋给变量name
console.log(name)// 输出zs
const name = "tom"
const { name: newName = "jack" } = obj// 从obj对象解构得到同名属性值,赋给变量newname, 假如没获取到,就只有默认值"jack"
console.log(name)// 输出tom
console.log(newName)// 输出jack
const { log } = console// 将console对象的log方法指针解构赋值给log变量,起到简化代码的作用
log("haha")// 输出haha
模板字符串
使用`字符串内容`书写模板字符串
const str = `this
is a \`string`// 模板字符串可以保留中间换行。在输出html字符串时比较方便。
console.log(str)
const name = "tom"
const str = `hey, ${name},${1 + 1},${Math.random()}`
console.log(str)// ${}插值表达式会将内部的值插入到str字符串中
模板字符串标签函数
利用标签函数对模板字符串进行二次加工处理,得到我们想要的效果
// 模板字符串标签函数
const str = console.log`hello JavaScript`//输出数组['hello JavaScript']
const name = "zs"
const gender = true
function myTagFunc(strings, name, gender) {
// console.log(strings,name,gender)
// 处理一下 性别
const sex = gender ? "man" : "woman"
return strings[0] + name + strings[1] + sex + strings[2]
}
const str = myTagFunc`hi, ${name} is a ${gender}`
console.log(str)
字符串扩展方法
- include()是否包含某字符串
- startsWith()是否包含以某字符串为开头
- endsWith()是否包含以某字符串为结尾
参数默认值
// 函数参数的默认值
function foo(bar,enable = true) {// 默认值参数,要放后面
// enable = enable || true
// enable = enable === undefined ? true : enable
console.log('foo invoked enable:')
console.log(enable)
}
foo('bar')
剩余操作符
...表示剩余操作符
// 剩余参数
function fun(n,...args) {
console.log(args)// 获得剩余参数组成的数组
}
fun(1,2,3,4)// 输出[2,3,4]
展开数组
...还可以用来展开数组
// 展开数组操作
const arr = ['foo', 'bar', 'baz']
// console.log(arr[0],arr[1],arr[2])
// console.log.apply(console,arr)
console.log(...arr)
箭头函数
=>可以简化函数的定义过程
// 原始定义
function plus(a) {
return a + 1
}
console.log(plus(10))
// 箭头函数定义
const plus = a => a + 1
// 多参数,多行定义
const plus = (a, b) => {
console.log('plus invoked')
return a + b
}
console.log(plus(1,2))
const arr = [1,2,3,4,5,6,7]
// const arr1 = arr.filter(function (item)
// return item % 2
// })
const arr1 = arr.filter(i => i % 2)
console.log(arr1)// 输出[1,3,5,7]
箭头函数的this
// 箭头函数与 this
const person = {
name: "tom",
// sayHi: function () {// 原始方法
// console.log(`hi,my name is ${this.name}`)// 输出hi,my name is tom
// }
// sayHi: () => {// 箭头函数方法,但是这里的this指的函数外部的this, 是undefined。无法实现我们想要的效果
// console.log(`hi,my name is ${this.name}`)// 输出hi,my name is
// }
sayHi: function () {
// const _this = this;// 当有这种情况时,都可以使用箭头函数来替代
setTimeout(() => {
console.log(`hi,my name is ${this.name}`)// 输出hi,my name is tom
},1000);
}
}
person.sayHi()
对象字面量的增强
// 对象字面量增强
const bar = "bar"
const age = "age"
const obj = {
name: "tom",
bar,// 等价bar: bar,
sayHi () {
console.log('hi')
console.log(this)
},
// 计算属性名
[1+2]: 18,// 表示1+2结果命名的属性3:18
[age]: 18// 表示以age恒量命名的属性age:18
}
// obj[age] = 18
console.log(obj)
// obj.sayHi()
对象扩展方法
Object.assign()
Object.assign(target, sourceObj1, sourceObj2...)将多个源对象中的属性复制到另一个目标对象中。
// 对象扩展方法
// Object.assign 方法
const source1 = {
a: 123,
b: 123
}
const source2 = {
b: 678,
d: 789
}
const target = {
a:456,
c:789
}
const result = Object.assign(target,source1,source2)
console.log(target)
console.log(target === result)
// 复制对象
// function fun(obj) {
// // 希望内部更改时,不要改外部的对象
// const newObj = Object.assign({},obj)
// newObj.name = 'tom'
// console.log(newObj)
// }
// const obj = {
// name: 'jack',
// age: 18
// }
// fun(obj)
// console.log(obj)
// 应用,在 options 对象参数接收时,简化
function Block(options) {
// this.width = options.width;
Object.assign(this,options)
}
const block1 = new Block({width: 100, height: 100, x: 50, y: 50})
console.log(block1)
Object.is()
判断对象值是否相等,一般不使用
// 对象扩展方法
// Object.is 方法
console.log(
// 0 == false // true
// 0 === false // false
// +0 === -0 // true
// NaN === NaN // false
// Object.is(+0,-0)// false
Object.is(NaN,NaN)// true
)
class类
相比构造函数方法创建对象,更好理解,代码更整洁。
// 原始构造函数方法
// function Person(name, age) {
// this.name = name;
// this.age = age;
// }
// Person.prototype.sayHi = function () {
// console.log(`hi,my name is ${this.name}`)
// }
// class 类
class Person {
constructor (name, age) {
this.name = name;
this.age = age;
}
sayHi () {
console.log(`hi,my name is ${this.name}`)
}
}
const p1 = new Person("tom",18)
console.log(p1)
p1.sayHi()
静态方法static
ES2015中新增添加静态方法的关键字 static
// 静态方法
class Person {
constructor (name, age) {
this.name = name;
this.age = age;
}
sayHi () {
console.log(`hi,my name is ${this.name}`)
}
static create (name,age) {// 声明方法是静态方法
console.log(this)// 静态方法中的this指向Person类
return new Person(name,age)
}
}
const p1 = Person.create("zs",19)
console.log(p1)
类的继承extends
// 静态方法
class Person {
constructor (name, age) {
this.name = name;
this.age = age;
}
sayHi () {
console.log(`hi,my name is ${this.name}`)
}
}
class Student extends Person {
constructor (name,age,number) {
super(name,age)// super对象指向父类Person
this.number = number
}
hello () {
super.sayHi()
console.log(`学号是 ${this.number}`)
}
}
const s1 = new Student("tom",18,101)
s1.hello();
Set 数据结构
一种新的数据类型,类似于数据,但是内部数据不允许重复。
// Set 数据结构
const s = new Set()
s.add(1).add(2).add(3).add(4).add(2)
console.log(s)// 输出{1,2,3,4},因为最后添加的2重复了,所以被忽略
// 遍历方法一
s.forEach(i => console.log(i))// 遍历s的值赋值给形参i并执行箭头函数
// 遍历方法二
for (let i of s) {// 效果同s.forEach(i => console.log(i))
console.log(i)
}
// console.log(s.size)// 获取元素的个数
// console.log(s.has(4))// 判断元素是否在s中
// console.log(s.delete(100))// 删除元素
// console.log(s)
// s.clear()// 清除所有元素
// console.log(s)
// 应用:数组去重
const arr = [1.3,4,6,2,4,7,5,8]
// const b = Array.from(new Set(arr))// 数组和Set集合的转换
const b = [...new Set(arr)]// 利用...展开集合,得到数组
console.log(b)
Map数据结构
类似于对象,内部是一一对应的映射关系键值对,但是不受类型限制
// 原始方法,当对象作为键名会出现问题
const obj = {}
obj[true] = "boolean"
obj[123] = "number"
obj[{a: 1}] = "object"
console.log(Object.keys(obj))// 输出['true','123','[object object]'] 所有键名都是字符串类型
console.log(obj[{}])// 输出"object",不是我们想要的一一对应的效果(只有obj[{a: 1}]的值才是"object")
console.log(obj['[object Object]'])// 输出"object",不是我们想要的
// Map 数据结构
const map = new Map()
const a = { a: 1}
map.set(a,100)
console.log(map)
console.log(map.get(a))
// map.has()
// map.delete()
// map.clear()
map.forEach((value,key) => {
console.log(key,value)
})
Symbol 数据类型
Symbol(),作用就是表示一个独一无二的值。 很多时候,我们添加的数据可能跟模块的数据冲突(覆盖源数据),而造成意料之外的后果。我们就需要使用Symbol()来制造独一无二的数据,来解决这种覆盖(数据重复)问题。
// shared.js =============================
const cache = {}
// // a.js ==================================
cache['foo'] = Math.random()
// // b.js ==================================
cache['foo'] = 123// 会覆盖源数据
// Symbol 符号,作用就是表示一个独一无二的值
const s = Symbol()
console.log(s)
console.log(typeof s)
console.log(Symbol() === Symbol())// 输出false
console.log(Symbol('foo'))// 传入参数来标记
console.log(Symbol('bar'))
console.log(Symbol('baz'))
const obj = {
[Symbol()] : 789,// 可以利用Symbol()设置私有属性,使其不被外部访问
name: "zs"
}
obj[Symbol()] = 123// 利用Symbol()添加数据,不会产生覆盖
obj[Symbol()] = 456
console.log(obj[Symbol()])// 输出undefined
console.log(obj.name)
Symbol补充
// Symbol 补充
console.log(Symbol("foo") === Symbol("foo"))// 输出false, 因为唯一性
const a = Symbol.for(true)// 会自动转换成字符串'true'
const b = Symbol.for('true')// 参数相同的for函数标记的Symbol(),表示同一个Symbol()
console.log(a === b)// 输出true
const obj = {
// 一般对象.toString()都是'[object object]',利用Symbol.toStringTag
// 可更改对象的toString()标签
[Symbol.toStringTag]: "XObject"
}
console.log(obj.toString())// 输出'[object XObject]'
const obj = {
[Symbol()]: "Symbol value",
foo: "foo value"
}
for (var k in obj) {
console.log(k)
}// 只输出'foo',而无法得到Symbol()值
console.log(Object.getOwnPropertySymbols(obj))// 输出[Symbol()]
// console.log(Object.keys(obj))// 只输出['foo'],而无法得到Symbol()值
// console.log(JSON.stringify(obj))只输出{"foo": "foo value"},而无法得到Symbol()值
for of 遍历
const arr = [100, 200, 300, 400]
for (const item of arr) {
console.log(item)
}
arr.forEach(item => { //没有办法打断遍历
console.log(item)
})
for (const item of arr) {//没有办法打断遍历
console.log(item)
if (item >= 200) {
break
}
}
const s = new Set(["foo", "bar", "baz"])
for (const item of s) {
console.log(item)
}
const m = new Map()
m.set("foo",1)
m.set("bar",2)
for (const [key,value] of m) {// 使用数组解构m的键值对数组
console.log(key,value)
}
//const obj = {
// name: "zs",
// age: 18
//}
//for (const item of obj) {// for of 这样遍历对象会报错
// console.log(item)
//}
ES2015其他内容
- 可迭代接口
- 迭代器模式
- 生成器
- Proxy代理对象
- Reflect统一的对象操作API
- Promise异步解决方案
- ESModules语言层面的模块化标准
ES2016概述
相对ES2015只是一个小的版本,只增加了少量内容:数组的includes()方法和指数运算符**。
// ES2016 新增内容
const arr = [1,true,NaN,23,'hello']
// console.log(arr.indexOf(true))// 返回下标1
// console.log(arr.indexOf(null))// -1
// console.log(arr.indexOf(NaN))// -1,这不是我们想要的
// includes 包含
// console.log(arr.includes(NaN))// true
// 指数运算符 **
// console.log(Math.pow(2,3))
console.log(2 ** 10)// 相当于console.log(Math.pow(2,10))
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!