一 ES6介绍
ES6新特性
- let 和 const 命令
- es6 的模板字符串
- 增强的函数
- 扩展的字符串,对象,数组功能
- 解构赋值
- Symbol
- Map和Set
- 迭代器和生成器
- Promise对象
- Proxy对象
- async的用法
- 类 class
- 模块化实现
浏览器支持:
- 目前90%的浏览器都支持,如果不支持,强大的babel可以将es6转为es5代码.
参考文献
01 let和const
- let/const 声明变量,没有变量提示
- let/const 是一个块级作用域
- 不能重复声明(var 可以重复声明,下面的会覆盖上面的)
- const 特殊,一般用来声明常理,一旦声明,无法修改.
- 不会污染全局变量
-
建议: 在默认情况下,用const,而只有在你知道变量值需要被修改的情况下使用 let
//var 声明变量,有变量提升
//console.log(a); //undefined
//var a = 2;
//1. let 声明变量,没有变量提升
//console.log(b); //报错:Uncaught ReferenceError: b is not defined
//let b = 1;
//2. let是一个块级作用域
// console.log(c); //报错: Uncaught ReferenceError: c is not defined
//if (1 == 1) {
// let c = 10;
//}
//console.log(c); //报错: Uncaught ReferenceError: c is not defined
//3. 不能重复声明(var可以重复声明,下面的会覆盖上面的)
//let d = 1;
//let d = 2; //报错:不能被重复声明 Uncaught SyntaxError: Identifier 'd' has already been declared
// const也有let上面3个特性,而且 const一般用来声明常量,一旦声明,无法修改.
//const max = 30;
//max = 20; //报错:不允许被修改 Uncaught TypeError: Assignment to constant variable.
//讨论: const声明对象,对象是否可以修改呢?
//const person = {
// name: '小马哥'
//};
//person.name = 'alex';
//console.log(person); //修改里面的对象属性是可以的.
//但是如果直接给 person重新赋值,则会报错.
//作用1: 不会影响for循环
//作用2: 不会污染全局变量
let RegExp = 10;
console.log(RegExp);
console.log(window.RegExp);
//建议: 在默认情况下,用const,而只有在你知道变量值需要被修改的情况下使用 let
02 模板字符串
模板字符串:使用 tab键上面的反引号``,插入变量时使用 ${变量名}
//模板字符串:使用 tab键上面的反引号``,插入变量时使用 ${变量名}
const oBox = document.querySelector('#box');
let id=1,name='小马哥';
let htmlStr = `
<ul>
<li>
<p id="${id}">${name}</p>
</li>
</ul>
`;
oBox.innerHTML = htmlStr;
03 函数之扩展运算符和箭头函数
- es6剩余参数: 由三个点 ... 和一个紧跟的具名参数指定 ...keys (keys名字自定义, 主要是解决了 arguments的问题 )
//1.带参数默认值的函数
//es5的写法
function es5add(a, b) {
a = a || 10;
b = b || 20;
return a + b;
}
console.log(es5add());
//es6的写法
function es6add(a = 10, b = 20) {
return a + b;
}
console.log(es6add());
//2. 默认的表达式也可以是一个函数
function newadd(a, b = getVal(5)) {
return a + b;
}
function getVal(val) {
return val + 5;
}
console.log(newadd(10));
//3. es6剩余参数: 由三个点 ... 和一个紧跟的具名参数指定 ...keys
//es5写法
// function pick(obj){
// let result = Object.create(null);
// for(let i=1; i<arguments.length; i++){
// result[arguments[i]] = obj[arguments[i]];
// }
// return result;
// }
// let book={
// title: 'es6的教程',
// author: '小马哥',
// year:2020
// }
// let bookData = pick(book, 'title', 'year');
// console.log(bookData);
//es6 剩余参数 改写上面
function pick(obj, ...keys) {
// ...keys 解决了 arguments 的问题
let result = Object.create(null);
for (let i = 0; i < keys.length; i++) {
result[keys[i]] = obj[keys[i]];
}
return result;
}
let book = {
title: 'es6的教程',
author: '小马哥',
year: 2020
}
let bookData = pick(book, 'title', 'year');
console.log(bookData);
//4. 扩展运算符...
//剩余运算符: 把多个独立的参数合并到一个数组中
//扩展运算符: 将一个数组分隔,并将各个项作为分离的参数传给函数
const maxNum = Math.max(20, 30);
console.log(maxNum);
//处理数组中的最大值 es6
const arr = [10, 20, 30, 40, 50];
console.log(Math.max(...arr));
//5. es6的箭头函数
// 使用 => 来定义 function(){} 等于 ()=>{}
// let nadd = function(aa,bb){
// return aa+bb;
// }
// console.log(nadd(10, 20));
//改写 箭头函数
let wadd = (a, b) => {
return a + b;
}
console.log(wadd(10, 10));
//如果只有一个参数的话,还可以简写
let yadd = a => {
return a + 10;
}
console.log(yadd(10, 20));
//如果返回值也是一个值的话, 还可以简写
let badd = a => (a + 5);
console.log(badd(100));
//闭包
// let fnn = (function(){
// return function(){
// console.log('hello es6');
// }
// })();
let fnn = (() => {
return () => {
console.log('hello es6 2');
}
})();
fnn();
- es6中,箭头函数没有this绑定
- 使用箭头函数的注意事项
- 一旦使用箭头函数,内容中就不存在 arguments
- 箭头函数不能使用 new 关键字来实例化对象
// 6. 没有this绑定
// es5中的this指向: 取决于调用该函数的上下文对象
let PageHandle = {
id: 123,
init: function() {
//箭头函数没有this指向,箭头函数内部this值只能通过查找作用域链来确定
document.addEventListener('click', (event) => {
this.doSomeThings(event.type);
}, false)
},
doSomeThings: function(type) {
console.log(`事件类型:${type}, 当前id:${this.id}`);
}
}
PageHandle.init();
//7. 使用箭头函数的注意事项
// 1. 一旦使用箭头函数,内容就不存在 arguments
// 2. 箭头函数不能使用 new 关键字来实例化对象
let Person = ()=>{};
let p = new Person();
04-解构赋值
解构赋值,是对赋值运算符的一种扩展,
它针对数组和对象来进行操作
//解构赋值 是对赋值运算符的一种扩展
//它针对数组和对象来进行操作
//优点: 代码书写上简洁易读
let node = {
type: 'iden',
name: 'foo'
}
//es5
// let tpye = node.type;
// let name = node.name;
//es6
//完全解构
let {
type,
name
} = node;
console.log(type, name);
//另外一个例子
// let obj = {
// a: {
// name: '张三'
// },
// b: [],
// c: 'hello, world'
// };
//不完全解构,可忽略一些属性
// let {
// a
// } = obj;
// console.log(a);
//可以使用剩余运算符
// let {
// a,
// ...res
// } = obj;
// console.log(res);
//默认值
// let {a,b = 30} = {a:20};
//对数组的解构
let arr = [1,2,3];
let [a,b,c] = arr;
console.log(a,b,c);
//可嵌套
let [aa,[bb],cc] = [1,[2],3];
05-扩展的对象功能
-
1. es6直接写入变量和函数,作为对象的属性和方法
// 1. es6直接写入变量和函数,作为对象的属性和方法
const name = 'xiaoma',
age = 20;
const person = {
name, //等价于 name:name
age,
sayName() {
console.log(this.name);
}
}
person.sayName();
- 2.属性名的表达式
const name = 'a';
const obj = {
isShow: true,
[name + 'bc']: 123,
['f' + name]: function() {
console.log(this);
}
}
console.log(obj);
- 对象的方法
- is() 相当于 === 比较两个值是否严格相等
- assign() 对象的合并
//3. 对象的方法
// is() 相当于 === 比较两个值是否严格相等
console.log(NaN === NaN); //false 不严谨
console.log(Object.is(NaN, NaN)); //true 很严谨
// assign() 浅拷贝
// 对象的合并
// Object.assign(target, obj1, obj2, ...) //把obj1,obj2 等后面的对象都合并到 target中
//返回合并之后的新对象
let newObj = Object.assign({}, {a:1}, {b:2});
console.log(newObj);
06 Symbol
-
原始数据类型 Symbol, 它表示是独一无二的值
//新的数据类型
//原始数据类型 Symbol, 它表示是独一无二的值
const name = Symbol('name');
const name2 = Symbol('name');
console.log(name === name2); //false
//最大的用途: 用来定义对象的私有变量
let s1 = Symbol('s1');
let s2 = Symbol('s2');
let obj = {
[s1]: '小马哥'
};
obj[s2] = '12';
//如果用 symbol 定义的对象中的变量,取值时一定要用 [变量名],不看用 .
console.log(obj[s1]); //小马哥
console.log(obj.s1); //undefined
//注意点: 无法遍历
//获取 Symbol 声明的属性名(作为对象的key)
// let s = Object.getOwnPropertySymbols(obj);
// console.log(s[0]);
let m = Reflect.ownKeys(obj);
console.log(m);
07 Map和Set
-
Set 集合: 表示一个无重复值的有序列表
//Set 集合: 表示一个无重复值的有序列表
let set = new Set();
// console.log(set);
//添加元素
set.add(2);
set.add('4');
set.add('4'); //第二次添加会被忽略
set.add(['hello', 2, 3]);
//删除元素
set.delete('4');
//校验某个值是否在集合中
console.log(set.has(2));
//集合的长度
console.log(set.size);
console.log(set);
//将set转为数组
let set2 = new Set([1,2,3,3,3,4]);
//通过扩展运算符
let arr = [...set2];
console.log(arr);
-
Map 类型是键值对的有序列表,键和值是任意类型
let map = new Map();
//设置值,set方法
map.set('name', '张三');
map.set('age', '20');
//获取值,get方法
console.log(map.get('name'));
//校验
console.log(map.has('name'));
//删除
map.delete('name');
//任意类型
map.set(['a',[1,2,3]], 'hello');
console.log(map);
08 数组的扩展功能
-
entries() keys() values() 返回一个遍历器,可以使用 for...of 循环进行遍历
// entries() keys() values() 返回一个遍历器,可以使用 for...of 循环进行遍历
// keys() 是对键名的遍历
// values() 是对值的遍历
// entries() 是对键值对的遍历
// console.log(['a', 'b'].keys()); //Array Iterator {}
for (let index of ['a', 'b'].keys()) {
console.log(index); // 0 1
}
for (let ele of ['a', 'b'].values()) {
console.log(ele); // a b
}
for (let [index, ele] of ['a', 'b'].entries()) {
console.log(index, ele); // 0 1
}
-
includes() 返回一个布尔值,表示某个数组是否包含给定的值
// includes() 返回一个布尔值,表示某个数组是否包含给定的值
console.log([1,2,3].includes(2)); //true
console.log([1,2,3].includes('2')); //false
09 迭代器
-
迭代器 Iterator 是一种新的遍历机制,俩个核心
-
迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器,通过迭代器的next()方法获取结果
-
迭代器是用于遍历数据结构的指针(数据库的游标)
// Iterator
// 是一种新的遍历机制,俩个核心
// 1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器,通过迭代器的next()方法获取结果
// 2.迭代器是用于遍历数据结构的指针(数据库的游标)
//使用迭代
const items = ['one', 'tow', 'three'];
//1.创建新的迭代器
const ite = items[Symbol.iterator]();
console.log(ite.next()); //{value: "one", done: false} done如果为false表示遍历继续,如果为true,表示遍历完成.
console.log(ite.next());
console.log(ite.next());
console.log(ite.next());
10 生成器
generator 函数,可以用过 yield 关键字,将函数挂起(函数停留在那,不会执行),为了改变执行流提供了可能,同时为了异步变成提供了方案.
它和普通函数的区别
1. function 后面,函数名之前有个 *
2. 只能在函数内部使用 yield表达式,让函数挂起
主要用处: 部署ajax操作,让异步代码同步化.
看下面2个例子
// 加载loading...页面
// 数据加载完成... (异步操作)
// loading 关闭掉
function* load() {
loadUI();
yield showData();
hideUI();
}
let ite = load();
ite.next();
function loadUI() {
console.log('加载loading...页面');
}
function showData() {
//模拟异步操作
setTimeout(() => {
console.log('数据加载完成');
ite.next();
}, 1000);
}
function hideUI() {
console.log('隐藏loading...页面');
}
如上,第一个例子.
第一次 ite.next() 的时候,进入 yield showData() 在这个函数中, ite.next(),则继续往下执行.
输出如下, 将异步改为同步执行.
加载loading...页面
数据加载完成
隐藏loading...页面
第二个例子,是带参数的例子.如下
function* main() {
let res = yield request('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976');
console.log(res);
//执行后面的操作
console.log('数据请求完成,可以继续操作');
}
const ite = main();
ite.next();
function request(url) {
$.ajax({
url,
method: 'get',
success(res) {
ite.next(res);
}
})
}
如上, const ite = main() 此时,代码还未进入 main中, 下面的 ite.next() 此时才会进入 main中, 而且会卡在 第一个yield处. 此时, yeild 后面是 request函数, 会运行这个函数, 而在这个函数中, ite.next(res), 把返回值当成参数返回回去, 此时 main 中的 res 接到到的就是这个值. 然后拿到 res的值,继续往下操作.
注意: main res = yield request('xxx') 这个res的值, 不是后面的 yield request('xxx'),而是 request('xxx') 中, ite.next(res) 中的 res这个返回值.这个要注意!
下面是2个自己写的练习.分别有参数和没有参数的情况.
//1. 显示正在加载, 加载数据,结束之后,关闭加载
function* main() {
showLoading();
yield loadData();
hideLoading();
}
const ite = main();
ite.next(); //此时运行到 yield loadData();
function showLoading() {
console.log('正在加载...');
}
function loadData() {
setTimeout(() => {
console.log('数据加载中...');
ite.next();
}, 1000);
}
function hideLoading() {
console.log('加载完成!');
}
//2. 异步加载1个数据, 然后根据这个数据,再异步请求数据
//生成器的方法
function* main() {
// 这个one是 ajaxOne()返回的数据
let one = yield ajaxOne();
let two = yield ajaxTwo(one);
console.log('最终的结果为:', two);
}
const ite = main();
ite.next(); //这个next会运行到 第一个yield处
function ajaxOne() {
setTimeout(() => {
//获取一个数据 100
ite.next(100); //这个next会执行到第二个yeild处
}, 1000);
}
function ajaxTwo(one) {
setTimeout(() => {
//根据ajaxOne获取到的100,再做一个异步操作
let newdata = one + 300;
ite.next(newdata) //这个next会执行到第三个yeild处,没有的话,会执行到结尾处
}, 1000);
}
11 Promise对象
- promise 英文翻译 承诺
-
相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果
-
各种异步操作都可以用同样的方法进行处理 axios库
特点
-
对象的状态不受外接影响, 处理异步操作的三个状态: Pending(进行中) Resolved(成功) Rejected(失败)
-
一旦状态改变,就不会再变,任何时候都可以得到这个结果.
自己感受: Promise对象,含有1个回调函数,回调函数中,有2个函数, resolved是成功时候返回,rejected是失败时候返回
// new promise对象
let pro = new Promise(function(resolved, rejected) {
//执行异步操作
let res = {
code: 201,
data: {
name: 'xiaomage',
age: 10
},
error: '失败了 '
}
setTimeout(() => {
if (res.code === 200) {
resolved(res.data)
} else {
rejected(res.error);
}
}, 1000);
});
console.log(pro);
pro.then(v => {
console.log(v);
}, e => {
console.log(e);
});
12 async异步操作
- 作用: 使得异步操作更加方便
-
async 返回一个 promise对象 then catch
-
async 是 Generator 的一个语法糖
-
await命令一定要在 async命令中
-
await 后面是一个异步的操作 会等待
async function f() {
// return await 'hello async';
let s = await 'hello world';
let data = await s.split('');
return data;
}
//如果async函数中有多个 await ,那么then函数会等待所有的await指令,运行完的结果才执行
//then 是f() 中所有的异步结束,最后的return的值
f().then(v => {
console.log(v);
}).catch(e => {
console.log(e);
})
//出错的时候
async function f2() {
// throw new Error('出错了');
try {
await Promise.reject('出错了');
} catch (error) {
};
return await Promise.resolve('hello');
}
f2().then(v => {
console.log(v);
}).catch(e => {
console.log(e);
})
16 module模块的使用
es6模块功能主要有两个命令构成: export 和 import
export用于规定模块的对外接口 import用于输入其他模块提供的功能
一个模块就是一个独立的文件