1. let
1. let只在当前代码块内有效。
for(let i=0;i<arr.length;i++){
.....
}
console.log(i) // i is not defined
2. let不存在变量提升
3. 暂时性死区
var temp=123;
if(true){
let temp=4556;
//内部temp相当于一个局部变量,在声明之前,该变量不可使用。在语法上称为“暂时性死区”
}
console.log(temp) // 1234. 不允许重复声明
let 不允许在相同作用域({})内重复声明一个变量。
ES6允许块级作用域任意嵌套,且外层作用域无法读取内层作用域的变量。
5. ES6规定,块级作用域中,函数声明语句类似let,块级作用域外不可引用
2. const
const声明是一个只读的常量,不能改变
只在声明所在的块级作用域内有效
notice:
var 命令和function命令声明的全局变量依旧是全局对象的属性,let,const命令声明的全局变量不再属于全局对象的属性。
3. 变量解构赋值
- 数组解构赋值: var [a,b,c]=[1,2,3]
- 对象解构赋值:
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"- 字符串解构赋值
- 函数参数解构赋值
用途
- 交换变量值 eg.[x,y]=[y,x]
- 从函数返回多个值。
-function example(){
return [1,2,3];
}
var [a,b,c]=example();
- 函数参数的定义
-// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
- 提取JSON数据
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
- 函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};遍历Map结构
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world输入模块的指定方法:
const { SourceMapConsumer, SourceNode } = require("source-map");
4. 字符串的扩展
- codePointAt([index]):返回对应位置字符的码点
- String.fromCodePoint([unicode]):用于从码点返回对应字符。
- at():返回字符串给定位置的字符。
- for….of: 新增字符串遍历接口
- includes(), startsWith(),endsWith(): 返回布尔值。
- repeat(n): 返回重复n次的字符串
padStart(), padEnd(): ES7推出,头部、尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'模板字符串:(“),模板字符串中嵌入变量,需要将变量名写在${}之中。
- String.raw()
5. 正则的扩展
6. 数值的扩展
- Number.isFinite(), Number.isNaN(): 只对数值数值有效,否则一律返回false
- Number.parseInt(), Number.parseFloat();
- Number.isInteger(): 3和3.0为同一个值。
- Number.EPSILON,新增一个极小常量。
- Math对象的扩展
- Math.trunc(): 去除一个数的小数部分,返回整数部分。
- Math.sign(): 用来判断一个数是正数,负数,零。
参数为正数,返回+1;
参数为负数,返回-1;
参数为0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
7. 数组的扩展
1 . Array.from(arrlike,[func],[context]): 将类数组和可遍历的对象转换为数组。功能类似于ES5:[].slice.call(arraylike)。第二个参数,类似于map方法,将处理后的值放入返回的数组。第三个参数,传入this的环境。
2 . 扩展运算符:(…)也可以将某些数据转换为数组。eg. function foo() {
var args = [...arguments];
}
3 . Array.of(): 将一组值转换为数组。Array.of(3, 11, 8) // [3,11,8]
4 . copyWithin(target, start = 0, end = this.length):
target(必需):从该位置开始替换数据。
start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
5 . find(): 用于找到第一个符合条件的数组成员。
6 . findIndex(): 返回第一个符合条件的数组成员的位置
7 . fill(): 使用给定值,填充一个数组。
8 . 数组实例的:entries(),keys(),values()
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
9 . includes(): Array.prototype.includes返回一个布尔值。
8. 函数的扩展
1 . ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。eg. function log(x, y = 'World') {
console.log(x, y);
}
2.(…): 可以将一个数组转为逗号分隔的参数序列。
3 . name属性:返回该函数的函数名。
4 . 箭头函数
如果箭头函数的代码块部分多于一条语句,需要用大括号括起来,并使用return返回。
1. 函数体内的this对象,是定义时所在的对象,不是使用时所在的对象。
2. 不可以当作构造函数,即不能使用new命令,否则报错。
3. 不可以使用arguments对象,该对象在函数体内不存在。
4. 不可以使用yield命令。
5 . 函数绑定
函数绑定运算符:(::),左边是对象,右边为函数,运算符会自动将左边对象作为上下文环境。
6 . 尾调用优化,尾递归
9. 对象的扩展
1 . 属性简洁表示:
- ES6允许在对象中,只写属性名,不写属性值,这时属性值等于属性名所代表的变量。eg.
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}- 方法也可以简写: eg.
var o={method(){return 'hello!'}}
- ES6允许字面量定义对象,使用变量作为属性名。eg:
let obj = {[propKey]: true, ['a' + 'bc']: 123
};- 属性名表达式与简洁表示法不能同时使用。
2 . Object.is(): 比较两个值是否严格相等,基本与“===”相同,但+0不等于-0,二是NaN等于自身。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
3 . Object.assign(): 用于对象的合并,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举属性。
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
notes:
- Object.assign是浅拷贝,即如果源对象某个属性的值是对象,那么目标对象得到的是对这个对象的引用。如果源对象发生变化,目标对象的属性也会改变。
- Object.assign还能用来处理数组,但会把数组视为对象。eg:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
4 . 属性遍历:
- for…in
- Object.keys(obj): 返回自身所有可枚举属性的数组
- Object.getOwnPropertyNames(obj): 返回自身的所有属性的数组。
- Object.getOwnPropertySymbols(obj):返回一个数组,包含自身所有symbol属性。
- Refletc.ownKeys(obj)
- __proto__属性: 读取或设置当前prototype对象。可以用:Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替
- Object.setPrototypeOf():设置对象的prototype对象。
- Object.getPrototypeOf():读取
- Object.values(), Object.entries(),Object.keys
5 . 对象的扩展运算符
- Rest解构赋值(…): 用于从一个对象取值,将所有可遍历但未读取的属性,分配到对象上。
eg:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }- 扩展运算符(…): 用于取出参数对象的所有可遍历属性,拷贝到当前对象中。
10 . Symbol
原始数据类型,表示独一无二的值,保证对象的属性独一无二。
Symbol作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有Symbol属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。
11 . Set和Map数据结构
set
类似于数组,成员值都是唯一的,无重复。
var s=new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
log([...s])// [1, 2, 3]
log(Array.from(s))//[1, 2, 3]
log(s)//Set(3) {1, 2, 3}
1 . set 函数可以接受一个数组或类数组作为对象,转换为set数据。
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
> 向set加入值,不会发生类型转换。5和"5"是不同值,但NaN等于NaN。
2 . set实例属性和方法:
- Set.prototype.constructor:构造函数,默认就是Set函数。
- Set.prototype.size:返回Set实例的成员总数。
- 实例方法:
add(value):添加某个值,返回set结构本身
delete(value):删除某个值,返回布尔值,表示是否删除成功。
has(value): 返回一个布尔值,表示是否为Set成员。
clear():清除所有成员,没有返回值。
3 . 遍历操作:
keys(),values(),entries(),forEach()
由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以key方法和value方法的行为完全一致。
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
Set结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。这意味着,可以省略values方法,直接用for…of循环遍历Set。
let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
// red
// green
// blue
WeakSet
weakSet与Set类似,也是不重复的值的集合,区别:
1. WeakSet成员只能是对象
2. WeakSet对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,如果其他对象不再引用这个对象,那么垃圾回收机制将自动回收该对象所占内存。这意味着无法引用WeakSet的成员,因此WeakSet不可遍历。
var ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
WeakSet可以接受一个数组或类似数组的对象作为参数。该数组的所有成员,都会自动成为WeakSet实例对象的成员。因此:数组的成员只能是对象。
原型方法:
WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中。
Map
Map类似于对象,也是键值对的集合,但是“键”不限于字符串,各种类型的值都可以当键。
1 . 接受对象作为键值
var m=new Map();
var o={p:"hello world"};
m.set(o,"content");
m.get(o);// "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
2 . 接受数组作为参数,数组成员是一个个表示键值对的数组。
var map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
只有对同一个对象的引用,Map结构才将其视为同一个键。
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
实例属性和操作方法:
(1)size属性
(2)set(key, value)
(3)get(key)
(4)has(key)
(5)delete(key)
(6)clear()
遍历方法:
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历Map的所有成员。
12 . Iterator和for…of循环
遍历器(Iterator)是一种接口,为各种不同数据结构提供统一访问机制。任何数据只要部署Iterator接口,就可以完成遍历操作。
作用:
1. 提供统一的访问接口
2. 使数据结构的成员按照某种次序排列
3. 创造了新的遍历命令for…of循环,Iterator接口主要供for…of消费。
13 . Generator函数
function * foo(x, y) { ··· }
Generator函数是一个普通函数,有两个特征:
1. function关键字和函数名之间有一个*号
2. 函数体内部,使用yield语句,定义不同内部状态。如果有多条yield语句,可以遍历然后输出
Generator函数调用同样加圆括号,但是调用后并不执行,必须调用遍历器对象的next方法,才执行,遇到yield语句,暂停,直到遇到下个next方法恢复执行,一直执行到return语句,遍历结束,done属性为true.
1 . yield语句
Generator函数也可以省略yield,即变成一个单纯的暂缓执行函数。
function* f() {
console.log('执行了!')
}
var generator = f();
setTimeout(function () {
generator.next()
}, 2000);
- yield语句不能再普通函数中调用。
- yield语句如果用在一个表达式之中,必须放在圆括号里面。
for…of循环可以自动遍历Generator函数生成的Iterator对象,此时不再需要调用next方法。
14 . Promise
Promise是一个对象,可以获取异步操作的消息。
Promise状态:
pending, resolved, rejected
只有异步操作的结果,可以决定当前是哪种状态,任何其他操作都无法改变这个状态。
基本用法
var promise=new Promise(function(resolve,reject){
//...some code
if(/*异步操作成功*/){
resolve(value)
}else{
reject(error)
}
})
Promise 构造函数接受一个函数作为参数,该函数两个参数分别是resolve
和reject
,是两个函数。由js引擎提供。
resolve
函数作用:将Promise对象的状态从“pending”变“resolved”,在异步操作成功时调用,并将异步操作结果传递出去。
reject
函数作用:将状态由“pending”变“reject”,失败时调用,并将错误作为参数传递出去。
Promise实例生成后,可以用then方法分别制定resolved,reject状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
实例:
var proTimer=function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
if(test>100){
resolve("成功")
}else{
reject("失败")
}
},1200)
})};
//proTimer异步函数执行后,promise状态改变,会立即出发then方法绑定的回调函数。
proTimer().then(function(value){
log(value)
},function(err){
log(err)
});
Promise.prototype.then()
then方法返回的是一个新的promise实例,因此可以采用链式写法,then后面再调用then, 第一个回调函数完成后,会将返回结果作为参数传递给第二个then回调函数。
Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
getJSON("/posts.json").then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。
跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。但chrome浏览器不遵守这条规定,会抛出错误。
promise.all()
用于将多个Promise实例,包装成一个新的promise实例
var p= Promise.all([p1,p2,p3]);
Promise.all方法的参数必须有iterator接口,且返回的每个成员都是promise实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race()
Promise.race
同样将多个promise实例包装成一个新实例。
var p=Promise.race([p1,p2,p3])
不同的是,只要任一个实例率先改变,p的状态就跟着改变。率先改变的promise实例的返回值就传递给p的回调函数。
Promise.resolve()
将现有对象转换为Promise对象。
Promise.resolve("foo")
//等价于
new Promise(resolve=>resolve("foo"))
Promise.resolve方法参数分为四种情况:
1. 参数是一个promise实例:那么不做任何修改,返回这个实例。
2. 参数是一个thenable对象,指具有then方法的对象。
let thenable={
then:function(resolve,reject){...
.)}
Promise.resolve会将这个对象转换为promise对象,然后立即执行thenable对象的then方法。
3. 参数不是具有then方法的对象,或者不是对象。
promise.resolve返回一个新的promise对象,状态为resolved.
var p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
4 . 不带参数:直接返回一个resolved状态的promise对象。立即resolve的promise对象,是在本轮“事件循环”结束时,setTimeout是在下一次事件循环开始时。
Promise.reject()
Promise.reject(reason)也会返回一个promise实例,实例状态为rejected.
部署done(), finally()方法
done()
保证抛出任何可能出现的错误。
Promise.prototype.done=function(onFullfilled,onRejected){
this.then(onFullfilled,onRejected)
.catch(function(reason){
setTimeout(()=>{throw reason},0)
})
}
finally()
finally方法用于指定不管promise对象最后状态如何,都会执行的操作,接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
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})
)
}
15 . 异步操作和Async函数
异步编程的实现:
回调函数:
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
Promise:将回调函数的嵌套修改成链式调用。
Generator函数
协程:多个线程相互协作,完成异步任务
运行流程如下:
第一步,协程A开始执行。
第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
第三步,(一段时间后)协程B交还执行权。
第四步,协程A恢复执行。
协程A就是异步任务,它分两段或多段执行
写法如下:
function * asyncJob(){
//...其他代码
var f=yield readFile(fileA);//执行到此处,执行权转让出去,等到执行权返回后,再从这继续往后执行
//...其他代码
}
Generator函数调用next()方法可以继续执行任务。
Generator函数的数据交换和错误处理:
next():返回的值是Generator函数向外输出的数据,next()还可以接受参数,进而传入到Generator函数,作为上个阶段任务的返回结果。
function* gen(x){
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }
Generator函数内部还可以部署错误处理代码,捕获函数体外抛出的错误:
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出错了');
// 出错了
异步任务的封装:
var fetch=require("node-fetch");
function * gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g=gen();
var result= g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data)
})
Thunk函数的含义
参数求值策略:
1. 传值调用:进入函数体之前,就计算好参数的值
2. 传名调用:进入函数体之后,用到该参数的时候,计算该参数的值。
传名调用的实现,即将参数放到一个临时函数中,再将这个临时函数传入函数体,这个临时函数成为Thunk函数。
function f(m){
return m * 2;
}
f(x + 5);
// 等同于
var thunk = function () {
return x + 5;
};
function f(thunk){
return thunk() * 2;
}
JS中也是传值调用,但是它的thunk函数替换的不是表达式,而是多参数函数,将其替换成单参数版本,且只接受回调函数作为参数。
Async函数
1. async函数返回一个promise对象
async函数内部,return语句返回的值,会成为then方法回调函数的参数。
2. async函数返回Promise对象,必须要等到内部所有await命令的promise对象执行完,才会发生状态改变。
3. 正常情况下,await命令后面是一个promise对象,如果不是,会调用Promise.resolve()转换成promise对象。
await命令后面的Promise对象如果变为reject状态,reject的参数会被catch方法的回调函数接收到。
只要一个await的promise变为reject,那么整个async函数都会中断执行。
eg.
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
为避免这个问题,两种解决方法:
1. 放在try…catch结构里
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// hello world
- await后面promise对象再跟一个catch
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world如果有多个await命令,可以统一放在try…catch结构中
4 . 如果await后面的异步操作出错,那么等同于async函数返回的promise对象被reject.
注意点
- 最好把await命令放在try…catch代码块中
- 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
继发:
let foo = await getFoo();
let bar = await getBar();
同时触发:
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
3 . await只能用在async函数中,用在普通函数中会报错,例如forEach里不能用await.可以使用for循环。
16. Class类
ES6引入class概念,通过class关键字定义类。
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {//定义在prototype原型上的方法
return '(' + this.x + ', ' + this.y + ')';
}
}
定义类的方法的时候,不需要function关键字,直接定义函数就可以,方法之间不需要都好分隔,否则会报错。
使用类,也是用new命令,跟构造函数用法一致。
可以使用Object.assign()一次性向类添加多个原型方法:
class Point{
constructor(){
//...
}
}
Object.assign(Point.prototype,{
toString(){},
toValue(){}
})
类内部定义的所有方法,都是不可枚举的。
- constructor方法:生成实例自动调用该方法,如果没有显示定义,会默认添加一个空的constructor(){}, 默认返回实例对象,也可以改写。
- 不存在变量提升。
- 类也可以用表达式的形式定义。
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
//使用表达式定义了一个类。需要注意的是,这个类的名字是MyClass而不是Me,Me只在Class的内部代码可用,指代当前类。如果内部没有用到Me,可以省略Me,即:
const MyClass=class {//....}
4 . 私有方法:
es6不提供私有方法,可以在模块外定义私有方法,然后模块内部调用bar.call(this,baz),这就使得bar成为当前模块的私有方法。
5 . this指向:默认指向类的实例,