let,const
函数内部的块级作用域,不允许重复声明,不存在变量提升,声明在全局也不具有全局属性(不可用window.访问)
const只读常量,一旦声明无法改变(只能保证引用类型地址不变,不能保证地址数据不变,使用Object.freeze({...})返回冻结对象)
var a = [];
for(let i = 0; i<10; i++){
a[i] = function(){console.log(i)};
}
a[1](); //1 此方法可以取代闭包的存值方案
解构赋值
按照一定模式,从数组和对象中提取值,对变量进行赋值
数组解构:
let [a,b,c] = [1,2,3];
//默认值在等号右边相应数据===undefined生效
let [foo = 6] = [];
对象解构:
let {foo,baz} = {foo:"a", baz:"b"};
let {msg = 6} = {}; //指定默认值
字符串解构:
let [a,b] = 'hello';
数值,布尔值解构(匹配等号右边对象.toString方法):
let {toString:str} = true;
alert(str === Boolean.prototype.toString); //true
函数参数解构赋值:
function fun({x=0,y=0}){alert(x)};
fun({x:1,y:2}); //1
函数参数
function fun(height = 0){}
参数解构赋值+默认参数,设置默认参数后arguments.length=参数总数-默认参数数
function fun({x, y=0}, z=0){console.log(x,y,z)};
fun({x:0, y:1}, 2); //0 1 2
fun({x:0}); //0 0 0
REST参数(是Array实例)
将逗号分隔的参数序列转换为数组参数
function fun(...params){
console.log(params);
};
fun(1,2,3); //[1,2,3]
扩展运算符
REST参数逆运算,数组转为逗号分隔的参数序列
let a1 = [1];
let a2 = [2, 3];
let a3 = [...a1, ...a2]; // [1, 2, 3]
fun(...a3); // fun(1, 2, 3)
模板字符串
let n = 6;
let name = \`hello ${n}\`;
//${fun()}内可以调方法返回值
多行字符串(避免+拼接)
let r = \`hello
world\`;
标签模板,跟函数名后,字符有变量,被处理成多个参数
可用于过滤参数值,实现安全Html
let a = 1;
let b = 2;
function tag(...values){};
tag\`hello ${a} world ${b}\`; //tag(['hello', 'world', ''], 1, 2);
Symbol
新增数据类型,表示独一无二的值
//参数只是表示对当前Symbol值的描述,Symbol返回的值各不相同
let s1 = Symbol('sss');
意义:对象属性名都是字符串,一种机制保障每个属性名独一无二,防止属性名冲突,可结合Class实现私有方法
箭头函数
//只有单条语句可以省略retun xxx;
let f = () => 6;
f(); //6
同普通函数区别
1.this指向固定化,因为箭头函数没有自己的this, 内部this指向定义时的外围作用域
2.不能用作构造函数(不可new)没有construct, prototype
3.函数内部不可使用arguments(可REST参数替代),super, new.target
4.不可以使用yield,不能作为Generator函数
5.无法使用call(), apply(), bind()改变this指向
var obj = {
say:function(){
setTimeout(() => {
console.log(this); //obj
});
setTimeout(function(){
console.log(this); //window
})
},
f:()=>{
console.log(this); //window
}
}
obj.say();
尾调用
某函数最后一步调用另一个函数并返回该函数
function A(x){
return B(x);
}
尾调用优化
尾调用是函数最后一步,不需要保留外层函数调用帧,只保留内层函数调用帧,节约内存,ES6尾调用优化只在严格模式下开启(禁用arguments, caller,因为尾调用优化会改写调用栈,导致以上变量失真)
function f(){
let m = 1;
let n = 2;
return g(m+n);
};
f();
//以上等同,删除f(外层函数调用帧),只保留g(内层函数调用帧)
g(3);
Generator函数
ES6提供的异步编程解决方案,最大特点可以交出函数执行权
整个Generator函数是一个异步任务的容器,异步操作需要暂停的地方用yield语句注明
let readFileAsync = function (name) {
return new Promise(function (resolve, reject) {
setTimeout(()=> {
resolve({name});
}, 1000);
});
};
function* gen() {
console.log('-------------gen start-------------');
yield readFileAsync('66');
yield readFileAsync('77');
console.log('-------------gen end-------------');
};
let g = gen();
console.log('-------------out-------------');
let f1 = g.next();//{done:false, value:Promise}
f1.value.then(function (data) {
console.log(data);
return g.next().value;//{done:false, value:Promise}
}).then(function (data) {
console.log(data);
//{done:true, value:null},如注销这一步end不会输出,说明函数停在yield上未往下执行
g.next();
});
// out -> gen start -> 66 -> 77 -> gen end
Async
Generator函数语法糖
async function gen() {
console.log('-------------gen start-------------');
//await暂停直到promise返回,才开始执行下一个
await readFileAsync('66').then((data)=> {
console.log(data);
});
await readFileAsync('77').then((data)=> {
console.log(data);
});
console.log('-------------gen end-------------');
}
//async语法无需调用next()
gen();
console.log('-------------out-------------');
//gen start -> out -> 66 -> 77 -> gen end
Set和WeakSet
Set新数据结构,类似数组,成员值唯一,可用于数组去重复
const s = new Set([1, 1, 2]);
//add, delete, has, clear, size
s.add("2");
//keys(), values(), entries(), forEach()
//因为Set结构没有key值只有value所以keys,values方法行为一致
for (let item of s.keys()) {
console.log("set:" + item);//输出:1,2,"2"
}
for (let item of s.values()) {
console.log("set:" + item);//输出值:1,2,"2"
}
for (let item of s.entries()) {
console.log(item);//输出:[1, 1],[2, 2],["2", "2"]
}
for (let item of s) {
console.log(item);//输出:1,2,"2"
}
//输出:1:1,2:2,"2":"2"
s.forEach((value, key)=>console.log(key + ":" + value));
WeakSet同Set,但每个成员都必须是对象,无size属性不能遍历,无clear,成员弱引用,随时可能消失
let a = [[1], [2]];
const ws = new WeakSet(a);
//add, delete, has
ws.add({});
//let b = [1,2];
//Error,因为WeakSet要求b中每个成员是对象1,2是值
//const ws = new WeakSet(b);
Map和WeakMap
Map类似键值对集合(Hash),键的范围不限制于字符串,各类型值都可当键
Object结构提供了“字符串-值”,Map结构提供“值-值”
const m = new Map();
const k = {key: 66};
//set, get, delete, has, clear, size
m.set(k, 'content');
const m2 = new Map([['key1', 'value1'], ['key2', 'value2']]);
//keys(), values(), entries(), forEach()
for(let key of m2.keys()){
console.log(key);//输出:key1, key2
}
for(let value of m2.values()){
console.log(value);//输出:value1, value2
}
for(let [key, value] of m2.entries()){
console.log(key, value);//输出:key1, value1, key2, value2
}
//同上
for(let [key, value] of m2){
}
const reporter = {
report: function(){
return "66 say:";
}
}
//支持forEach,添加第二个参数,用来绑定this
m2.forEach(function(value, key, map){
console.log(this.report(), key, value);
}, reporter);
WeakMap同Map,但只接受对象作键名(null除外),无size属性不能遍历,无clear,成员弱引用,随时可能消失
WeakSet, WeakMap用途主要是实例弱引用,删除实例,它们自己也随之消失,不会造成内存泄漏
Iterator(本质指针)
便利器,一种接口,为不同数据结构提供统一访问机制,任何数据结构只要部署Iterator接口,就可遍历,Iterator主要供for...of消费
遍历过程:
1.建立一个指针,指向数据结构起始位
2.第一次调用next(),指针指向数据结构第一个成员(包含value,done属性的对象)
3.第二次调用next(),指针指向数据结构第二个成员
...
具备Iterator接口的数据结构:Array, Map, Set, String,Arguments等
for ... of 循环
Proxy
在目标对象之前假设一层拦截,元编程,对编程语言的编程
//对一空对象假设拦截,重定义属性get行为
var obj = new Proxy({}, {
get:function(target, property){
return 66;
}
});
obj.time //66
WeakSet类似Set, 不重复值集合,但成员只能是对象,不能遍历,因为成员都是弱引用
Reflect
let obj = {foo:1};
//1查找并返回目标对象obj的foo属性值
Reflect.get(obj, 'foo');
类
本质上是ES5语法糖,prototype属性依然存在, 类的所有方法都定义在prototype上,必须调用new创建实例,内部不存在变量提升
类方法内部如果含有this,默认指向类实例
class Point {
_x; //私有属性
//new命令生成对象实例自动调用该方法
//不显示定义,默认加个空constructor方法
//默认返回this实例对象
constructor(x = 0){
//实例属性除非显示定义在其本身(this)上
//否则都是定义在原型上
this.x = x;
this._x = x;
_x = x;
//构造函数不是通过new命令掉,可以用来确定构造函数如何调用
if(new.target !== undefined){
}
}
//方法不用加function关键字修饰
toString(){
return this.x;
}
//静态方法,不被实例继承,只有类调用Point.hello()
//如果静态方法包含this,这个this指类(Point)而非实例对象
static hello(){}
get x(){
return _x;
}
set x(v){
_x = v;
}
}
等同
Point.prototype = {constructor(){}, toString(){}}
类实现私有方法(ES6不支持):
1.命名加_
2.将私有方法移到类定义外
3.利用Symbol值唯一,将私有方法命名为一个Symbol让外界取不到
类继承 extends
class ColorPoint extends Point{
constructor(x, color){
//子类必须调用super后才能调用this,先创造父类实例对象
super(x);
this.color = color;
}
toString(){
return this.color + ' ' + super.toString();
}
}
Module
ES6模块通过export显示指定输出代码,通过import命令输入
export {m, moon as n}
let m = 1;
let moon = 2;
//不使用export default,用户要知道所加载的变量名,函数名
import {m, n} from 'fs';
//使用export default到处模块,import可以取任意名字
export default function(){};
import lulu from 'fs';
模块整体加载
export function a(){}
export function b(){}
import {a,b} from 'xxx';
import * as all from 'xxx';
export和import复合写法
export {a, b} form 'xxx';
export * from 'xxx';
export {default} from 'xxx';
ES6模块与CommonJS模块
1.CommonJS模块输出值拷贝,ES6模块输出值引用
2.CommonJS模块运行时加载,ES6模块编译时输出接口
ES6输入的模块变量,只是一个“符号链接”,只读,不能重新赋值
export let obj = {};
import {obj} from 'xxx';
obj.prop = 66; //ok
obj = {}; // error
Promise
代表一个异步操作,有3种状态:pending,fulfilled,rejected
Promise构造函数是同步执行,then里的回调函数是异步
Promise状态只能从pending->fulfilled或pending->rejected,且状态只能变更1次,不能再变更
Promise的then,catch方法会返回一个新Promise实例
Promise的then,catch抛出错误被后续捕获,请
return Promise.reject(new Error('error'));
throw new Error('error');
缺点:
1.一旦创建,无法取消,
2.不设置回调,内部抛出错误,不会反应到外部
3.处于pending状态,无法得知目前进展
let p = new Promise(function(resolve, reject){
//...Promise
if( /*异步操作成功*/){
resolve(value);
}
else{
reject(error);
}
});
//then方法接受2个回调
p.then(function(value){}, function(error){})
.catch(function(error){});
//等全部状态改变
let ps = Promise.all([p1, p2]);
//一个状态改变
let ps = Promise.race([p1, p2]);
//将现有对象转化为promise,并设为resolve
let p = Promise.resolve($.ajax('/dddd.json'));
//将现有对象转化为promise,并设为reject
let p = Promise.reject('error');
done():Promise对象回调链,无论then,catch结尾,最后一个方法抛出错误,都无法捕捉,提供一个done方法处于回调链尾,保证任何可能出的错误
finally():不论Promise对象最后状态成功失败都执行的操作
*** done和finally并为包含在ES6的Promise中
try():不区分执行函数是同步或异步,统一用Promise包装处理,用then指定下一步流程,用catch方法处理抛出错误
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => {
throw reason
})
);
};
Promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected)
.catch(function (reason) {
// 抛出一个全局错误
setTimeout(() => {
throw reason
}, 0);
});
};
function runAsync1() {
let p = new Promise(function (resolve, reject) {
console.log('begin 1');
setTimeout(()=> {
resolve('data 1');
});
});
return p;
};
function runAsync2() {
let p = new Promise(function (resolve, reject) {
console.log('begin 2');
setTimeout(()=> {
resolve('data 2');
});
});
return p;
};
function runAsync3() {
let p = new Promise(function (resolve, reject) {
console.log('begin 3');
setTimeout(()=> {
resolve('data 3');
});
});
return p;
};
runAsync1()
.then((data)=> {
console.log(data);
return runAsync2();
})
.then((data)=> {
console.log(data);
return runAsync3();
})
.finally(()=> {
console.log("finish");
})
.done(()=> {
console.log("all success");
});
简单手写Promise原理
function Defer(executor) {
var self = this;
self.status = 'pending';
self.data = undefined;
self.onResolvedCallback = [];
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved';
self.data = value;
for (let i of self.onResolvedCallback) {
self.onResolvedCallback[i](value);
}
}
}
try {
//执行异步方法
executor(resolve);
}
catch (e) {
}
};
Defer.prototype = {
constructor: Defer,
//then返回Defer对象
then: function (onResolved) {
var self = this;
var promise2;
if (self.status === 'resolved') {
return promise2 = new Defer(function (resolve) {
try {
var x = onResolved(self.data);
if (x instanceof Defer) {
x.then(resolve);
}
resolve(x);
}
});
}
if (self.status === 'pending') {
return promise2 = new Promise(function (resolve) {
self.onResolvedCallback.push(function (value) {
try {
var x = onResolved(self.data);
//返回值为Promise
if (x instanceof Defer) {
x.then(resolve);
}
}
});
});
}
}
};
var d = new Defer(function (resolve) {
setTimeout(function () {
resolve({a: 0});
}, 1000);
});
d.then(function (data) {
alert(data);
});
ES6严格模式:
1.变量必须声明后使用
2.函数参数不能同名属性
3.不能用with
4.禁止this指向全局
5.不能使用arguments.callee,arguments.caller
6.增加protected, static, interface关键字