一、模板字符串
如:
`Welcome ${uname}`
注意:${}里可以放:变量、算术计算、三目、对象属性、创建对象、调用函数、访问数组元素——有返回值的合法的js表达式。- 不能放没有返回值的js表达式,也不能放分支/判断、循环等程序结构。比如: if else for while...等
二、let和const
let的优点
不会被声明提前,保证程序顺序执行。让程序块,也变成了”块级作用域”。保证块内的变量,不会影响块外的变量。
let的本质
底层会被翻译为匿名函数自调:
(function(){})()
let和const的三个特点:
- 因为不会声明提前,所以不能在声明变量之前,提前使用该变量。
- 在相同作用域内,禁止声明两个同名的变量!
- 因为let底层相当于匿名函数自调,所以,即使在全局创建的let变量,在window中也找不到!
var, let, const区别
| 区别 | var | let | coust |
|---|---|---|---|
| 是否产生”块级作用域” | × | ✔ | ✔ |
| 是否会被声明提前 | ✔ | × | × |
| 是否保存在window中 | ✔ | × | × |
| 相同作用域中能否重复声明变量 | ✔ | × | × |
| 是否能提前使用 | ✔ | × | × |
| 是否必须设置初始值 | × | × | ✔ |
| 能否修改实际保存在变量中的原始类型值或引用类型地址 | ✔ | ✔ | × |
三、箭头函数
优点:简单
缺点:
- 构造函数不能用
- 对象的方法不能用
- 原型对象方法不能用
- DOM中事件处理函数不能用
- 箭头函数无法用call,apply,bind改变this
- 箭头函数不支持arguments
- 箭头函数没有prototype
四、for of
今后只要遍历数字下标的东西,都可用for of代理普通for循环和forEach
普通for循环
- 优点: 既可遍历索引数组,又可以遍历类数组对象(arguments)——只要下标是数字
- 缺点: 没有可简化的空间
forEach
- 优点: 可以配合ES6的箭头函数,很简化
- 缺点: 只能遍历数字下标的索引数组,无法遍历类数组对象
for of的问题
- 无法获得下标位置i,只能获得元素值
- 无法控制遍历的顺序或步调,只能从头到尾,一个挨一个的顺序遍历
- 无法遍历下标名为自定义下标的对象和关联数组
普通for,forEach,for of, for in的区别
| 遍历对象 | 普通for | forEach | for of | for in |
|---|---|---|---|---|
| 索引数组 | √ | √ | √ | × |
| 类数组对象 | √ | × | √ | × |
| 关联数组 | × | × | × | √ |
| 对象 | × | × | × | √ |
总结:下标为数字,首选for of;下标为自定义字符串,首选for in
五、参数增强
1、默认参数值
如:
function order(
yinliao="鸡腿“
){ … }
2、剩余参数(rest)
优点:
- 支持箭头函数
- 生成的数组是纯正的数组类型,所以使用数组家所有函数
- 自定义数组名arr,比arguments简单的多!
3、展开运算符(spread)
如:
// 合并多个数组和元素
var arr1=[1,2,3];
var arr2=[5,6,7];
var arr3=[...arr1,4,...arr2,8];
// 合并多个对象和属性
var obj1={ x:1, y:2 };
var obj2={ i:4, j:5 };
var obj3={...obj1, z:3, ...obj2, k:6};
六、解构(destruct)
旧js中,要想使用对象中的成员,或数组中的元素,都必须带着"对象名."或"数组名[]"前缀。 实际开发中,对象或数组的嵌套结构可能很深。前缀就可能写很长: “对象名.属性名.更子一级属性名....”, • 非常麻烦。 所以,以后遇到一个复杂的对象或数组时,都可以通过解构方式,来减少数组或对象的嵌套结构便于使用
七、Class
旧js中,构造函数和原型对象是分开定义的。不符合"封装"概念。 今后,只要在es6中创建一种新的类型,包含构造函数+原型对象方法,都要用class来创建
八、Promise
实际开发中,经常需要让多个异步任务顺序执行,但异步函数几乎同时执行,各自执行各自的,互不干扰,互相之间也不会等待。 旧js的做法是利用回调函数,但如果要先后执行的任务多了!就会形成很深的嵌套结构 ——回调地狱。极其不优雅,极其不便于维护,所以Promise解决了回调地狱的问题
Promise三大状态:
- pending(挂起)
- fulfilled(成功)
- rejected(出错)
手动实现Promise对象:
var PENDING = 0; //挂起状态
var FULFILLED = 1; //执行成功状态
var REJECTED = 2; //执行失败状态
//定义Promise构造函数,将来用new创建Promise对象
function Promise() {
// state变量存储当前Promise对象的执行状态
var state = PENDING;
// value变量存储执行成功后的返回值,或执行失败后的错误提示信息
var value = null;
// handlers变量是一个数组,存储将来用.then()函数传入的一个或多个后续任务函数。
var handlers = [];
doResolve(fn, resolve, reject);
function fulfill(result) { //执行成功后,把状态改为成功状态,并把执行结果返回值,保存在变量value中
state = FULFILLED;
value = result;
}
function reject(error) { //执行失败后,把状态改为失败状态,并把错误提示信息,保存在变量value中
state = REJECTED;
value = error;
}
function resolve(result) { //如果当前任务成功执行完成,使用者调用了resolve(返回值)
try {
var then = getThen(result); //就要收集当前Promise对象身上后续的.then()函数中传入的内容
if (then) { //如果有.then
//就调用核心doResolve函数,执行.then()中的函数,并传入两个状态切换函数。
doResolve(then.bind(result), resolve, reject) //resolve和doResolve之间的递归用来处理promise的层层嵌套
return
}
//如果没有.then,就直接切换当前Promise对象的状态,并返回执行结果,结束当前Promise对象的执行
fulfill(result);
} catch (e) {
//如果调用过程中出错,就调用reject()函数,将当前Promise状态切换为失败,并返回错误提示信息
reject(e);
}
}
function handle(handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED &&typeof handler.onFulfilled === 'function') {
handler.onFulfilled(value);
}
if (state === REJECTED &&typeof handler.onRejected === 'function') {
handler.onRejected(value);
}
}
}
this.done = function (onFulfilled, onRejected) {
// 使用定时器,确保当前任务一定是异步执行的
setTimeout(function () {
handle({ //传入修改状态的两个回调函数
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
}
this.then = function (onFulfilled, onRejected) {
var self = this; //保存当前Promise对象
return new Promise(function (resolve, reject) { //创建并返回下一个Promise对象
return self.done(
function (result) { //调用当前对象的done()函数
if (typeof onFulfilled === ‘function’) { //如果.then()中传入的是一个函数
try {
return resolve(onFulfilled(result)); //就调用resolve,传入下一项任务的函数,执行。
} catch (ex) { return reject(ex);}
} else {
return resolve(result); //否则就传入下一个Promise对象,继续等待。
}
},
function (error) {
if (typeof onRejected === 'function') {
try {
return resolve(onRejected(error));
} catch (ex) {return reject(ex);}
} else {
return reject(error);
}
}
}
/**
* .then()函数中传入的内容有两种情况: 可能传入的是下一个Promise对象,也可能直接传入匿名函数
* 如果调用resolve时传入的是下一个Promise对象,
* 就返回这个Promise对象的.then()函数.
* 如果调用resolve时传入的是下一个函数
* 就直接返回这个函数即可
* 如果调用resolve时什么都没传,就返回null
*/
function getThen(value) {
var t = typeof value;
if (value && (t === 'object' || t === 'function')) {
var then = value.then;
if (typeof then === 'function') {
return then;
}
}
return null;
}
/**
* 调用传入的.then()函数,并传入执行成功和执行失败两个修改状态的回调函数*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false; //默认暂时未执行成功
try {
fn( //调用当前任务函数
function (value) { //传入执行成功后,请使用者主动调用的res函数
if (done) return //如果done被标记为true,说明当前异步任务执行完
done = true //否则如果done暂时未被标记为true, 就标记为true,让当前异步任务状态变为完成状态
onFulfilled(value) //调用传入的第一步定义的改变当前Promise状态的函数,把当前Promise对象标记为执行成功,并保存返回值
//这里调用了resolve函数。
},
function (reason) {//传入执行失败后,请使用者主动调用的resolve函数
if (done) return //如果done被标记为true,说明当前异步任务执行完
done = true //否则如果done暂时未被标记为true,就标记为true,让当前异步任务状态变为完成状态
onRejected(reason) //调用传入的第一步定义的改变当前Promise状态的函数,把当前Promise对象标记为执行失败,并保存错误提示
})
} catch (ex) { //如果出现异常
if (done) return //如果done被标记为true,说明当前异步任务执行完,就退出当前任务的执行
done = true //否则如果done暂时未被标记为true,就标记为true。
onRejected(ex) //调用传入的改变状态函数,把当前Promise对象标记为执行失败
}
}