ECMAScript6
常用
let关键字
-
作用:与var类似, 用于声明一个变量
-
特点:
1)在块作用域内有效;
2)不能重复声明;
3)不会预处理, 不存在提升 -
应用:
1)循环遍历加监听
2)使用let取代var是趋势
<script type="text/javascript">
// 不会预处理, 不存在提升
// console.log(username) //error
let username = 'yoliu'
console.log(username) //yoliu
// 在块作用域内有效
let btns = document.getElementsByTagName('button')
for (var i = 0; i < btns.length; i++) {
var btn = btns[i];
btn.onclick = function () {
alert(i) // 此时不管点击哪个按钮都显示3
}
}
for (let i = 0; i < btns.length; i++) {
var btn = btns[i];
btn.onclick = function () {
alert(i) // 此时能够正常显示对应的i
}
}
</script>
const关键字
- 作用:定义一个常量
- 特点:
1)不能修改
2)其它特点同let - 应用:保存不用改变的数据
变量的解构赋值
<script type="text/javascript">
let obj = {
username: 'yoliu',
age: 21
}
// let username = obj.username
// let age = obj.age
let {
username,
age
} = obj
console.log(username, age)
let arr = [1, 3, 5, 'abc', true]
let [, , a, b, c] = arr
console.log(a, b, c)
function foo({
username,
age
}) { //相当于 {username, age} = obj
console.log(username, age)
}
foo(obj)
</script>
模板字符串
- 模板字符串 : 简化字符串的拼接 模板字符串必须用
包含变化的部分使用${xxx}定义
<script type="text/javascript">
let obj = {username:'yoliu',age:21}
let str = '我的名字叫:' + obj.username + ',我今年的年龄是:' + obj.age
console.log(str)
str = `我的名字叫:${obj.username},我今年的年龄是:${obj.age}`
console.log(str)
</script>
- includes(str) : 判断是否包含指定的字符串
- startsWith(str) : 判断是否以指定字符串开头
- endsWith(str) : 判断是否以指定字符串结尾
- repeat(count) : 重复指定次数
简化的对象写法
- 简化的对象写法:
1)省略同名的属性值
2)省略方法的function - 例如:
let x = 1;
let y = 2;
let point = {
x,
y,
setX (x) {this.x = x}
};
<script type="text/javascript">
let username = 'yoliu'
let age = 21
let obj = {
username, //同名的属性可以省略不写
age,
getName(){ // 可以省略函数的function
return this.username
}
}
console.log(obj)
console.log(obj.getName())
</script>
- Object.assign(target, source1, source2…) : 将源对象的属性复制到目标对象上
- Object.is(v1, v2) : 判断2个数据是否完全相等
- __proto__属性 : 隐式原型属性
数组
- Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
- Array.of(v1, v2, v3) : 将一系列值转换成数组
- find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
- findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
箭头函数
作用: 定义匿名函数
-
基本语法:
- 没有参数: () => console.log(‘xxxx’)
- 一个参数: i => i+2
- 大于一个参数: (i,j) => i+j
- 函数体不用大括号: 默认返回结果
- 函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
- 使用场景: 多用来定义回调函数
-
箭头函数的特点:
- 简洁
- 箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this
- 扩展理解: 箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
3点运算符
- 用途
-
rest(可变)参数
-
扩展运算符
<script type="text/javascript">
// rest(可变)参数
// function foo(a, b) {
// console.log(arguments)
// arguments.forEach(function (item, index) {
// console.log(item, index) //因为arguments是伪数组,所以不具备数组的方法,所以会报错
// })
// }
function foo(...value) {
console.log(value)
value.forEach(function (item, index) {
console.log(item, index) //因为arguments是伪数组,所以不具备数组的方法,所以会报错
})
}
foo(2, 65, 33, 44)
// 扩展运算符
let arr = [1, 6]
let arr1 = [2, 3, 4, 5]
arr = [1, ...arr1, 6]
console.log(arr)
console.log(...arr)
</script>
注意:当使用三点运算符收集实参的时候,可变参数只能放在当前的最后即function foo(a,b,c,…value )
形参默认值
当不传入参数的时候默认使用形参里的默认值
<script type="text/javascript">
// 定义一个点的坐标的构造函数
function Point(x = 0, y = 0) {
this.x = x
this.y = y
}
let point = new Point(52,7)
console.log(point)
let point1 = new Point()
console.log(point1)
</script>
promis对象
- 解决
回调地狱
(回调函数的层层嵌套, 编码是不断向右扩展, 阅读性很差) - 能以同步编码的方式实现异步调用
- 在es6之前原生的js中是没这种实现的, 一些第三方框架(jQuery)实现了promise
- 理解:
- Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
- 有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称’回调地狱’)
- ES6的Promise是一个构造函数, 用来生成promise实例*
- 使用promise基本步骤(2步):
-
创建promise对象
-
调用promise的then()
- promise对象的3个状态
- pending: 初始化状态
- fullfilled: 成功状态
- rejected: 失败状态
- 应用:
- 使用promise实现超时处理
- 使用promise封装处理ajax请求
<script type="text/javascript">
/*
// 创建promise对象
let promise = new Promise((resolve, reject) => {
// 初始化promise状态: pending:初始化
console.log(111) // 该函数同步执行,所以可以在222之前打印
// 执行异步操作,通常是发送ajax请求,开启定时器
setTimeout(() => {
console.log(333)
// 根据异步任务的返回结果去修改promise的状态
// 异步任务执行成功
// resolve('哈哈'); // 修改promise的状态为fullfilled:成功的状态
// 异步任务失败
reject('555') //修改promise的状态为rejected:失败的状态
}, 2000)
})
console.log(222)
promise
.then((data) => {
// 成功的回调
console.log(data, '成功了!')
}, (err) => {
// 失败的回调
console.log(err, '失败了!')
})
*/
// 定义获取新闻的功能函数
function getNews(url) {
let promise = new Promise((resolve, reject) => {
// 状态:初始化
// 执行异步任务
// 创建实例对象
let xmlhttp = new XMLHttpRequest();
// open设置请求的方式以及url
xmlhttp.open('get', url)
// 绑定监听 onload
xmlhttp.onload = function () {
// 请求成功
// 修改状态
resolve(xmlhttp.responseText) // 修改promise的状态为成功状态
if (xmlhttp.status != 200) { // 请求失败
reject('暂时没有新闻内容')
}
}
// 发送
xmlhttp.send()
})
return promise
}
getNews('http://localhost:3000/news?id=2')
.then((data) => {
console.log(data)
// 发送请求获取评论内容
let commentsUrl = JSON.parse(data).commentsUrl
let url = 'http://localhost:3000' + commentsUrl
// 发送请求
return getNews(url)
}, (error) => {
console.log(error)
})
.then((data) => {
console.log(data)
}, (error) => {
console.log(error)
})
</script>
Symbol
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
Symbol:
-
概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)*
-
特点:
- Symbol属性值对应的值是唯一的,解决命名冲突问题
- Symbol值不能与其他数据进行计算,包括同字符串拼串
- for in, for of遍历时不会遍历symbol属性。
-
使用:
- 调用Symbol函数得到symbol值
// 创建symbol属性值 let symbol = Symbol() console.log(symbol) let obj = { username: 'yoliu', age: 21 } obj[symbol] = 'hello' console.log(obj)
- 传参标识
let symbol2 = Symbol('one') let symbol3 = Symbol('tow') console.log(symbol2 === symbol3) // false console.log(symbol2) // Symbol('one') console.log(symbol3) // Symbol('two')
-
内置Symbol值
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- Symbol.iterator
对象的Symbol.iterator属性,指向该对象的默认遍历器方法(后边讲)
Iterator遍历器
- 概念: iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制
- 作用:
- 为各种数据结构,提供一个统一的、简便的访问接口;
- 使得数据结构的成员能够按某种次序排列
- ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。
- 工作原理:
- 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
- value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
- 当遍历结束的时候返回的value值是undefined,done值为false
- 原生具备iterator接口的数据(可用for of遍历)
- Array
- arguments
- set容器
- map容器
- String
。。。
<script type="text/javascript">
// 模拟指针对象(遍历器对象)
function myIterator(arr) { // iterator接口
let nextIndex = 0
return { // 遍历器对象
next: function () {
return nextIndex < arr.length ? {
vale: arr[nextIndex++],
done: false
} : {
vale: arr[nextIndex++],
done: true
}
}
}
}
// 准备一个数据
let arr = [1, 4, 6, 'abc']
let iteratorObj = myIterator(arr)
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())
// 将iterator接口部署到指定的数据类型上,可以使用for of去循环遍历
// 数组、字符串、arguments、set容器、map容器
for (let i of arr) {
console.log(i)
}
let str = 'ajdkdff'
for (let i of str) {
console.log(i)
}
function fun() {
for (let i of arguments) {
console.log(i)
}
}
fun(1, 4, 5, 'abc')
let obj = {
username: 'yoliu',
age: 21
}
// for (let i of obj) {
// console.log(i) // error obj is not iterable
// }
// 等同于在指定的数据内结构上部署了iterator接口。。
// 当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历 xxx is not iterable
let targetData = {
[Symbol.iterator]: function () {
let nextIndex = 0
return { // 遍历器对象
next: function () {
return nextIndex < this.length ? {
vale: this[nextIndex++],
done: false
} : {
vale: this[nextIndex++],
done: true
}
}
}
}
}
// 使用三点运算符,结构赋值,默认去调用iterator接口
let arr2 = [1, 6]
let arr3 = [2, 3, 4, 5]
arr2 = [1, ...arr3, 6]
console.log(arr2) //1 2 3 4 5 6
let [a, b] = arr2
console.log(a, b) //1 2
</script>
Generator函数
- 概念:
- ES6提供的解决异步编程的方案之一
- Generator函数是一个状态机,内部封装了不同状态的数据,
- 用来生成遍历器对象
- 可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
- 特点
- function 与函数名之间有一个星号
- 内部用yield表达式来定义不同的状态
- generator函数返回的是指针对象(接11章节里iterator),而不会执行函数内部逻辑
- 调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true}
- 再次调用next方法会从上一次停止时的yield处开始,直到最后
- yield语句返回结果通常为undefined, 当调用next方法时传参内容会作为启动时yield语句的返回值。
async函数
ES2017 (ES8)标准引入了 async 函数,使得异步操作变得更加方便。
-
概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
-
本质: Generator的语法糖
-
语法:
<script type="text/javascript" src="./js/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
// async基本使用
async function foo() {
return new Promise(resolve => {
// setTimeout(function () {
// resolve()
// }, 2000)
setTimeout(resolve, 2000)
})
}
async function test() {
console.log('开始执行', new Date().toTimeString())
await foo()
console.log('执行完毕', new Date().toTimeString())
}
test()
// async里的await返回值
function test2() {
return 'xxx'
}
async function asyncPrint() {
let result = await Promise.resolve('promise')
console.log(result)
result = await Promise.reject('失败了。。。')
console.log(result)
}
asyncPrint()
// 获取新闻内容
async function getNews(url) {
return new Promise((resolve, reject) => {
$.ajax({
method: 'GET',
url, // 同名属性可以不写 等同于:url:url
success: data => resolve(data),
error: error => reject(false)
})
})
}
async function sendXml() {
let result = await getNews('http://localhost:30001/news?id=7')
console.log(result)
if (!result) {
alert('暂时没有评论内容')
return
}
result = await getNews('http://localhost:3000' + result.commentsUrl)
console.log(result)
}
sendXml()
</script>
-
特点:
1、不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
2、返回的总是Promise对象,可以用then方法进行下一步操作
3、async取代Generator函数的星号,await取代Generator的yield
4、语意上更为明确,使用简单,经临床验证,暂时没有任何副作用
Class
- 通过class定义类/实现类的继承
- 在类中通过constructor定义构造方法
- 通过new来创建类的实例
- 通过extends来实现类的继承
- 通过super调用父类的构造方法
- 重写从父类中继承的一般方法
- 基本语法
<script type="text/javascript">
// function Person(name, age) {
// this.name = name
// this.age = age
// }
// let person = new Person('yoliu', 21)
// console.log(person)
// 定义一个人物的类
class Person {
// 类的构造方法
constructor(name, age) {
this.name = name
this.age = age
}
// 类的一般方法
showName() {
console.log(this.name)
}
}
let person = new Person('yoliu', 21)
console.log(person)
person.showName()
// 子类
class StartPerson extends Person {
constructor(name, age, salary) {
super(name, age) // 调用父类的构造方法
this.salary = salary
}
// 父类的方法重写
showName() {
console.log('调用子类的方法')
console.log(this.name, this.age, this.salary)
}
}
let p1 = new StartPerson('yoliu', 21, 88000)
console.log(p1)
p1.showName()
</script>
其他
字符串、数组的扩展
- 字符串扩展
- includes(str) : 判断是否包含指定的字符串
- startsWith(str) : 判断是否以指定字符串开头
- endsWith(str) : 判断是否以指定字符串结尾
- repeat(count) : 重复指定次数
<script type="text/javascript">
let str = 'asjdfkfjfmdls'
console.log(str.includes('as'))
console.log(str.startsWith('a'))
console.log(str.endsWith('s'))
console.log(str.repeat(3))
</script>
- 数值扩展
- 二进制与八进制数值表示法: 二进制用0b, 八进制用0o
- Number.isFinite(i) : 判断是否是有限大的数
- Number.isNaN(i) : 判断是否是NaN
- Number.isInteger(i) : 判断是否是整数
- Number.parseInt(str) : 将字符串转换为对应的数值
- Math.trunc(i) : 直接去除小数部分
<script type="text/javascript">
console.log(0b1010) // 10
console.log(0o56) // 46
console.log(Number.isFinite(Infinity)) // false
console.log(Number.isNaN(NaN))
console.log(Number.isInteger(123.12)) // false
console.log(Number.isInteger(123.0)) // true
console.log(Number.parseInt('123abc123')) // 123
console.log(Number.parseInt('a123abc123')) // NaN
console.log(Math.trunc(123.123)) // 123
</script>
数组扩展
-
Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
-
Array.of(v1, v2, v3) : 将一系列值转换成数组
-
find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
-
findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
<script type="text/javascript">
let btns = document.getElementsByTagName('button')
Array.from(btns).forEach(function (item, index) {
console.log(item)
})
let arr = Array.of(1, 4, 'abc', true)
console.log(arr)
let arr2 = [2, 3, 41, 5, 8, 95]
let result = arr2.find(function (item, index) {
return item > 4
})
console.log(result) // 41
result = arr2.findIndex(function (item, index) {
return item > 4
})
console.log(result) // 2
</script>
对象方法扩展
- Object.is(v1, v2) ,以字符串的形式来判断的
- 判断2个数据是否完全相等
- Object.assign(target, source1, source2…)
- 将源对象的属性复制到目标对象上
- 直接操作 proto 属性
<script type="text/javascript">
console.log(0 == -0) // true
console.log(NaN == NaN) // false NaN与任何数据都不相等
console.log(Object.is(0, -0)) // false
console.log(Object.is(NaN, NaN)) // true 因为字符串的NaN 和 NaN 相等
let obj = {}
let obj1 = {
username: 'yoliu',
age: 21
}
let obj2 = {
sex: '女'
}
Object.assign(obj, obj1, obj2)
console.log(obj)
let obj3 = {}
let obj4 = {
qian: 88888888888
}
obj3.__proto__ = obj4
console.log(obj3)
console.log(obj3.qian)
</script>
拷贝
1、数据类型:
数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
-
基本数据类型:
- 特点: 存储的是该对象的实际数据
-
对象数据类型:
- 特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
2、复制数据
- 基本数据类型存放的就是实际的数据,可直接复制
- 克隆数据:对象/数组
- 区别: 浅拷贝/深度拷贝
- 判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
- 知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
- 常用的拷贝技术
- arr.concat(): 数组浅拷贝
- arr.slice(): 数组浅拷贝
- JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
- 浅拷贝包含函数数据的对象/数组
- 深拷贝包含函数数据的对象/数组
- 浅拷贝(对象/数组)特点:拷贝的引用,修改以后的数据会影响原数据
- 深拷贝(深度克隆)特点:拷贝的时候生成新数据,修改拷贝以后的数据不会影响原数据
关于深浅拷贝的实例:
<script type="text/javascript">
// // 不会影响原数据
// let str1 = 'abcd'
// let str2 = str1
// console.log(str2) // abcd
// str2 = ''
// console.log(str1) // abcd
// let bool1 = true
// let bool2 = bool1
// bool2 = false
// console.log(bool1) //true
// let obj = {
// username: 'yoliu',
// age: 21
// }
// let obj1 = obj
// console.log(obj1)
// obj1.username = 'sss'
// console.log(obj.username)
// // 拷贝数组/对象 没有生成新的数据而是复制了一份引用
// let arr = [1, 4, {
// username: 'yoliu',
// age: 21
// }]
// let arr2 = arr
// arr2[0] = 'abcd'
// console.log(arr, arr2)
/**
* 拷贝数据:
* 基本数据类型:
拷贝后会生成一份新的数据,修改拷贝后的数据不会影像原数据
对象/数组:
拷贝不会生成新数据,而是拷贝的是引用。修改拷贝以后的数据会影响原来的数据
拷贝数据的方法:
1. 直接赋值给一个变量 // 浅拷贝(浅克隆)
2. Object.assign() // 浅拷贝
3. Array.prototype.concat() // 浅拷贝
4. Array.prototype.slice() // 浅拷贝
5. JSON.parse(JSON.stringfy()) // 深拷贝 但不能处理函数数据
*/
let obj = {username:'yoliu', age:21}
let obj2 = Object.assign(obj)
console.log(obj2)
obj.username = 'wade'
console.log(obj)
let arr = [1, 3, {username:'yoliu', age:21}]
let testArr = [2, 4]
let arr2 = arr.concat()
console.log(arr2)
arr2[1] = 'a'
console.log(arr)
arr2[2].username = 'a'
console.log(arr)
let arr3 = arr.slice()
arr3[2].username = 'lll'
console.log(arr)
let arr4 = JSON.parse(JSON.stringify(arr))
console.log(arr4)
arr4[2].username = 'fkgfg'
console.log(arr)
</script>
- 深度克隆
/*
思考:
如何实现深度拷贝(克隆)
拷贝数据里有对象/数组,
拷贝的数据里不能有对象/数组,
即使有对象/数组可以继续遍历对象/数组拿到每一项值,一直到拿到的是基本数据类型,
然后在再去复制,就是深度拷贝
*/
// 知识点储备
/**
* 如何判断数据类型:arr--->Array null ---> Null
* 1. typeof 返回的数据类型:String、Number、Boolean、Undefined、Object、Function(null返回的是Object)
* 2. Object.prototype.toString.call(obj)
*/
let result = 'abcd'
console.log(Object.prototype.toString.call(result))
result = null
console.log(Object.prototype.toString.call(result).slice(8, -1))
result = [1, 3]
console.log(Object.prototype.toString.call(result).slice(8, -1))
// for in 循环 对象(属性名) 数组(下标)
let obj = {
username: 'yoliu',
age: 21
}
for (let i in obj) {
console.log(i)
}
let arr = [1, 3, 'abc']
for (let i in arr) {
console.log(i)
}
// 定义检测数据类型的功能函数
function checkType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
// 实现深度克隆---> 对象/数组
function clone(target) {
// 判断拷贝的数据类型
let result, targetType = checkType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
// 遍历目标数据
for (let i in target) {
// 获取遍历数据结构的每一项值
let value = target[i]
// 判断目标结构里的每一项值是否存在对象/数组
if (checkType(value) === 'Object' || checkType(value) === 'Array') { // 说明对象/数组里又嵌套了对象/数组
// 继续遍历获取到的value值
result[i] = clone(value)
} else { // 获取到的value值时基本数据类型或者是函数
result[i] = value
}
}
return result
}
let arr3 = [1, 2, {
username: 'yoliu',
age: 21
}]
let arr4 = clone(arr3)
console.log(arr4)
arr4[2].username = 'lili'
console.log(arr3, arr4)
let obj3 = {username:'kobe', age: 39}
let obj4 = clone(obj3)
console.log(obj4)
obj4.username = 'wade'
console.log(obj3, obj4)
Set和Map容器
- Set容器 : 无序不可重复的多个value的集合体
- Set()
- Set(array)
- add(value)
- delete(value)
- has(value)
- clear()
- size
- Map容器 : 无序的 key不重复的多个key-value的集合体
- Map()
- Map(array)
- set(key, value)//添加
- get(key)
- delete(key)
- has(key)
- clear()
- size
<script type="text/javascript">
let set = new Set([1, 2, 4, 5, 2, 3, 6])
console.log(set) // 1 2 4 5 3 6
set.add(7)
console.log(set.size, set)
console.log(set.has(7))
console.log(set.has(8))
set.clear()
console.log(set)
let map = new Map([
['key', 'yoliu'],
['age', 21]
])
console.log(map)
map.set(78, 'haha') //添加
console.log(map)
map.delete('age')
console.log(map)
</script>
for of 循环
for(let value of target){}循环遍历
-
遍历数组
-
遍历Set
-
遍历Map
-
遍历字符串
-
遍历伪数组
<script type="text/javascript">
// 遍历数组实现去重
let arr = [1, 2, 4, 5, 5, 6, 6, 2]
let arr1 = arr
arr = []
let set = new Set(arr1)
for (let i of set) {
arr.push(i)
}
console.log(arr)
</script>