| let块级作用域、 const常量
| 解构赋值
| 箭头函数、default、rest、spread
| 模板字符串
| class: extends、super、constructor、静态属性和方法、实例属性
| Promise、Generator、async/await
| 模块化: import、export、as、*、default export
| 数据结构: Set不重复值的集合、Map
| Proxy 对象的拦截器
| Symbol
| symbol 独一无二的值
| Set、Map数据结构
let和const
一、let 声明变量
let完全可以取代var, 特性: 1、let不允许重复声明 2、没有预解析功能 3、块级作用域
1、预解析功能
console.log(a); // 报错, 如果是原来的var声明这里会是undeined, 所以let没有预解析功能
let a = 20;
2、块级作用域 在{ }中声明的变量只能在括号里使用
var name = 'lulu';
function prsone(){
let name = 'siguang';
}
prsone();
console.log(name); // 'lulu'
// 输出的都是10
for(var i=0; i<10; i++){
setTimeout(function(){
console.log(i); // 使用var声明的i都会打印出9,如果使用let输出的就是0到10
})
}
二、const常量
1、常量只允许赋一次值不能被修改 2、常量声明都为大写 3、与let相当只在块级作用域有效
const NAME = 'siguang'; // 不能变化的值
NAME = 'lulu'; // 报错
if (true) {
const MAX = 5;
}
MAX // 报错,const与let相同都是在块内使用
解构赋值
允许从数组和对象中提取的值,对变量进行赋值,被称为解构赋值
一、数组解构使用[]
let [a, b, c] = [1, 2, 3]; // a=1, b=2, c=3
// 默认值
let [x, y = 'b'] = ['a']; // x='a', y='b'
二、对象解构使用{}
// 对象是按名字来解析赋值
let obj = {
getName: function(){},
foo: 'aaa',
bar: 'bbb'
};
let {foo, bar} = obj // foo='aaa', bar='bbb'
// 对象的解构赋值,先找到同名,在将值赋给对应的变量
let { foo: val, bar } = { foo: "aaa", bar: "bbb" };
console.log(val, bar) // foo='undefined', val='aaa', bar='bbb'
三、字符串的解构赋值
const [a, b, c, d, e] = 'hello'; // a=h, b=e, c=l, d=l, e=o
const [...tail] = 'hello'; // ['h', 'e', 'l', 'l', 'o']
# length属性
let {length: len} = 'hello'; // length = 5
四、默认参数 default
# 参数作为数组
function add([x, y]){
return x * y
}
add([3,2]); // 6
# 参数作为对象,对x、y的默认初始值
function move({x = 0, y = 0}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
五、不定参数 Rest
function f(x, ...y) {
// y是一个数组
return x * y.length;
}
f(3, "hello", true) == 6
六、扩展运算符 Spread
function f(x, y, z) {
return x + y + z;
}
// 将数组中的每个元素展开为函数参数
f(...[1,2,3]) // 6
模板字符串
一、写到`...`之间,值的输出使用 ${...}
二、可以写多行字符串,只写到`...`之间就可以
三、${...}可以解析变量、对象的值、表达式、函数返回
let name = 'siguang';
let obj = {
age: 33
}
console.log(`你的名字是: ${ name } 你的年龄是: ${ obj.age }`)
四、标签模板
let a=10, b=20;
dialog`Hello ${a+b} world ${a*b}`; // 等同于 dialog()
函数扩展
一、箭头函数
1、箭头函数的注意问题:
* 箭头函数里的this不是指向调用者,而指向对象
* 不能当构造函数来用, 不能使用new
* 函数内不存在arguments对象
* 不可以使用yield命令,箭头函数不能用作Generator函数
arr.sort(function(){ ... }) 相当于 arr.sort((a, b) => a-b);
// 箭头函数的this,不是指向调用者
const Template = {
test(){
console.log(this); // this指向Template
document.querySelector("#showThis").onclick = () =>{
/* 如果非箭头函数this应该指向 #showThis */
/* 这里箭头函数不是指向调用者,所以指向了 Template */
console.log(this);
}
}
}
Template.test();
2、var f = function(v){ return v; }
// ES6写法
var f = v => v;
3、var sum = function(num1, num2){
return num1 + num2;
}
// ES6写法
var sum = (num1, num2) => {
return num1 + num2;
}
4、对象中方法的简写
var obj = {
name: 'haha',
getName(){ // 是getName: function(){}的简写
console.log(this.name);
},
setName(name){
this.name = name;
console.log(this.name);
}
}
二、函数参数默认值
function fn(a, b = 2){
// b如果不传相当于2,等同于 var b = arguments.length > 1 && arguments[1] == undefined ? arguments[1] : 2;
return {a, b}
}
console.log(fn(10)); // 返回{a: 10, b: 2}
// 如果没有参数默认值时还需要在函数体内做兼容
function fn(name){
var getName = name || 20;
}
fn();
三、参数的解构赋值
const full = ({ first, last }) => first + ' ' + last;
full({first: 20, last: 30})
// 等同于
// function full(person) {
// return person.first + ' ' + person.last;
// }
四、rest 获取多余参数
以'...变量名' 来获取多余的参数,返回一个数组,这样就不需要arguments对象了
function person(...rest){
console.log(rest); // [1,2,3,4,5]
}
person(1,2,3,4,5);
function person(a, ...rest){
console.log(a); // 1
console.log(rest); // [2,3,4,5]
}
person(1,2,3,4,5);
五、spread 扩展操作符 ... 与rest相反
function add(x, y) {
return x + y; // 4+38
}
var numbers = [4, 38]; // 只能为数组不能为对象
add(...numbers) // 42
# 可以将字符串转成数组
let arr = [...'hello']; // ['h', 'e', 'l', 'l', 'o']
六、name属性
funciton foo(){ ... }
foo.name; // 'foo' 返回函数名
七、::运算符
箭头函数可以绑定this对象,减少显式this对象的写法(call、apply、bind)
ES7提出了函数绑定来取代"call、apply、bind"调用,使用两个"::"
foo::bar; // 等同于 bar.bind(foo);
foo::bar(...arguments); // 等同于 bar.apply(foo, arguments);
类、继承
一、类的一些特性
1、对象方法的简写方法
class Cat{
getName(){ // 老写法 getName: function(){}
...
}
}
2、通过__proto__属性可以直接调用父类
var parent = {
getParentName(){
console.log('parent')
}
}
var childer = {
__proto__: parent, // 通过__proto__指向parent, 就可以直接调用parent类中的方法
getChildeName(){
console.log('childer');
}
}
childer.getChildeName(); // childer
childer.getParentName(); // parent
二、创建类
class Cat {
// ES6中新型构造器, 用来初始化时这里接收参数
constructor(name){
this.name = name;
}
getName(){ // 公有方法
console.log(this.name);
}
static bar(baz){ // 私有方法
debugger;
return this.name = baz;
}
* gen(){
let arg = 10;
yield arg;
}
}
Cat.userName = 'siguang';
var oCat = new Cat('哈哈');
oCat.getName();
oCat.bar('lulu'); // 报错静态方法调用不到,并且不会被继承
oCat.gen().next()
三、继承 extends
// 创建一个类
class Person {
constructor(name){
this.name = name;
}
getName(){
console.log(this.name);
}
}
// 继承这个类
class Children extends Person {
constructor(name, color){
super(name); // super指向继承的构造函数Person的constructor
this.color = color;
}
getColor(){
console.log(this.name, this.color);
}
}
// 实例化
var op = new Person('siguang');
op.getName(); // 'siguang'
var oc = new Children('lulu', 'red');
oc.getColor(); // 'red'
oc.getName(); // 'lulu'
四、static 静态属性和方法
类似构造函数,直接挂载到函数下的叫对象的属性和方法,而写到构造函数内部的叫构造函数的属性和方法
1、静态方法前面需要加上'static'关键字,相当于只是函数下的方法而不是prototype的方法,静态方法可以被子类继承,
class Foo{
static methodName(){
return 'hello'
}
}
Foo.methodName(); // hello
var foo = new Foo();
foo.methodName(); // 报错
2、静态属性
ES6中没有静态属性,只能声明静态方法,ES7中可以直接写到类内在进行转码
class Foo {
constructor(...arg){
this.args = args;
}
outputUserName(){
console.log(this.username); // 这里username未定义,除非在constructor中定义 this.username
}
}
Foo.username = 'siguang'; // 类的静态属性
var foo = new Foo();
console.log(foo.personName); // undefined
foo.outputUserName(); // undefined
五、实例属性
注意: 一定要将实例属性和静态属性区分,实例属性写到constructor中this.username, new后的实例时候可以被实例方法调用,而静态属性只挂到了类下直接通过类来调取,Foo.username
class Foo{
constructor(){
this.username = 'siguang';
}
showName(){
console.log(this.username); // siguang
console.log(Foo.username); // lulu
}
}
Foo.username = 'lulu';
var foo = new Foo();
foo.showName();
****** ES7 中静态属性和实例属性的定义 ******
class MyClass{
usernameA = 'siguang'; // 实例属性
showName(){
console.log(this.usernameA);
}
}
六、super()方法
继承时必须调用一次super方法,否则constructor中的this为undefined,调用父类的构造器进行初始化, 子类调用父类的构造函数
class BaseModel {
constructor(options, data) { // class constructor,node.js 5.6暂时不支持options = {}, data = []这样传参
this.name = 'Base';
this.url = 'http://azat.co/api';
this.data = data;
this.options = options;
}
getName() { // class method
console.log(`Class name: ${this.name}`);
}
}
class AccountModel extends BaseModel {
constructor(options, data) {
super({private: true}, ['3333', '4444']);
this.name = 'Account Model';
this.url +='/accounts/';
}
getAccountsData() {
return this.data;
}
}
let accounts = new AccountModel(5);
accounts.getName(); // Account Model
console.log('Data is %s', accounts.getAccountsData); // {private: true}
let base = new BaseModel({public: true}, ['111', '2222']);
console.log(base.getName()); // Base
七、class中的Generator方法
方法前面加" * " 号表示该方法是Generator函数
class MyClass = {
constructor(){
...
}
* getName(){
...
}
}
Module 模块
一、import: 模块加载
// 取整个对象
import $ from 'jquery';
// 通过解构取对象
import {name1, name2, nam3} from './user.js';
// 通过逗号分两整体和解构分别来取
import React, { Component, PropTypes } from 'react';
// 重命名
import * as React from 'react'; // * 对整体模块加载,并通过as转换一个名
// 按需加载
button.addEventListener('click', event => {
imoprt('dialog.js')
.then(dialog => {
dialog.show();
}).
catch(err =>{
// error
})
}, false)
不同写法
1、普通写法
meat.js
export function beef(){
return '牛肉';
}
export function pork(){
return '猪肉';
}
main.js
import { beef, pork } from 'meat.js';
console.log(beef()); // 牛肉
console.log(pork()); // 猪肉
2、key的简写
var fn1 = function(){
console.log('fn1');
}
var fn2 = function(){
console.log('fn2');
}
export {fn1, fn2} // 对象名与key相同可以写成一个
二、export: 模块输出
1、使用对象简写方式
var name1 = 'aaa';
var name2 = 'bbb';
var name3 = 'ccc';
export {name1, name2, name3}
// 也可以写成
export var name1 = 'aaa';
export var name2 = 'bbb';
export var name3 = 'ccc';
2、可以直接输出变量、函数或类
export function person(){ ... }
// 不能直接输出变量名
var name = 'siguang';
export name; // 报错
写成: export var name = 'siguang';
写成: var name = 'siguang'; export {name};
3、跨模块常量
const常量只能在当前代码下使用,通过export可以进行跨模块常量,多个文件都可以使用
export const name = 'siguang';
export const age = 33;
import * as info from 'userinfo'; // 或 import { name, age } from 'userinfo'
三、as 关键字来修改名字
meat.js
export function beef(){
return '牛肉';
}
export function pork(){
return '猪肉';
}
main.js
// * 代表meat.js下所有的对外接口,转换成meat对象下,这样就可以通过meat来调用meat下的
import * as meat from './meat.js';
console.log(meat.beef()); // 牛肉
console.log(meat.pork()); // 猪肉
四、* 将somModule内的所有导出接口
import * as newSome from './someModule' // 将someModule类的所有接口更改到newSome下
五、export default指定匿名
不使用default在import加载定义名与导出名必须相同,否则无法加载,如果指定默认输出使用export default,在import导入的时候不用在关心命名的问题
1、meat.js
// 倒出匿名函数
export default function() {
console.log('foo');
}
简写
export default(){ // export default {} 写成默认对象
}
main.js
// 导入时可以任意起名
import beef from './meat.js'
2、default与不写default输出的区别
// 使用default来输出,import不需要使用{}
export default function crc32() {
// ...
}
import crc32 from 'crc32';
// 不使用default来输出,import需要使用 {}
export function crc32() { // 输出
// ...
};
import {crc32} from 'crc32'; // 输入
Set、Map数据结构
一、Set(): 类似数组的一种新结构,成员都是唯一的值没有重复值,相当于数组去重
# 数组去重的新方法
let setValue = new Set([1,2,33,1,22,2,2,4,2,1,2])
console.log(setValue, Object.prototype.toString.call(setValue)); // {size: 5, [1, 2, 33, 22, 4]}, '[Object Set]'
let arr = [...setValue]; // [1, 2, 33, 22, 4] 需要进行解构
特性:
1、不允许数组里有重复数据
方法:
1、set.size: 获取数据的长度
2、set.add(value): 添加值
3、set.delete(value): 删除set的实例值
4、set.has(value): 传入的参数是否为set的成员
5、set.clear(): 删除set的所有成员
二、Map(): 将二维数组转成对象
var map = new Map([['username', 'siguang'], ['password', 'ssssss']]);
map.get('username'); // siguang
/* new Map([['usernmae', 'aaa', 'password', 'ssssss'], ['aaaa', 1111]]); 注意一个数组中只有两个下标的值,这里只能get到username, password不会取到 */
特性: 不允许有重复的key值
方法:
1、map.size: 成员总数
2、map.set('key', 'value'): 添加成员
3、map.get(): 获取
4、map.clear(): 清除所有
对象扩展 Object
一、简写
1、对象属性和值相同可以写成一个
var foo = { name: 'siguang'};
var baz = {
foo // foo: foo 相同
};
console.log(baz.foo.name); // siguang
2、对象中函数简写
var o = {
name: 'momo',
getName(){ // 等同于 getName: function(){}
retrun this.name;
}
}
3、参数作为对象返回
function f(x, y) { return {x, y}; }
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
// 2、CommonJS模块输出变量
const getItem = function(){ ... }
const setItem = function(){ ... }
const clear = function(){ ... }
module.exports = { getItem, setItem, clear };
// 等同于
// module.exports = {
// getItem: getItem,
// setItem: setItem,
// clear: clear
// };
二、[] 属性名表达式
// 对象的属性名可以用'[]'字符串拼接
var sex = '男';
var obj = {
name: 'momo',
[sex]: false,
['get'+'Name'](){
console.log(this.name, this['男']); // 返回 momo false
}
}
obj.getName();
三、getter 赋值器、setter 取值器
let cat = {
name: '喵喵',
get name(){ return this.name },
set name(value){
if(Object.prototype.toString.call('xxx') == '[object String]'){
this.name += value
}
}
}
四、Object.is(): 用于对比两个数字或字符串是否相等,相当于 === ,可以正确比较 -0和0,NaN和
'=='与'==='的缺点:
相等运算符(==)缺点: 自动转换数据类型
和严格相等运算符(===)缺点: NaN不等于自身,以及+0等于-0
Objetc.is(0, -0); // false
Object.is(NaN, NaN); // true
五、Object.assign(目标对象, 被合并对象B, 被合并对象C): 合并对象
/* 注意: 被合并对象与合并目标对象的属性相同会赋盖掉前面的对象的值 */
var objA = {a: 1, b:2}, objB = {b: 3, c: 4};
let req = Object.assign(objA, objB); // {a:1, b:3, c:4}
添加对象的方法:
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2){
// ...
},
anotherMethod(){
// ...
}
})
相当于
SomeClass.prototype.someMethod = function(arg1, arg2){ // ... }
SomeClass.prototype.anotherMethod = function(){ // ... }
克隆对象:
function clone(obj){
return Object.assign({}, obj);
}
注意点:
1、assign 是浅拷贝
2、同名属性替换
六、getPrototypeOf(object)、setPrototype(object, 谁的prototype): 获取、设置对象的prototype
var Cat = function(name){
this.name = name;
}
Cat.prototype.showName = function(){
return this.name;
}
var c1 = new Cat('momo');
c1.showName();
console.log(Object.getPrototypeOf(c1))
// 设置prototype
var Person = function(nationality){
this.nationality = nationality;
}
Person.prototype = {
showNationality: function(){
return this.nationality;
}
}
Object.setPrototypeOf(c1, Person.prototype);
console.log(Object.getPrototypeOf(c1));
七、keys()、values()
获取对象的所有keys或所有值, 并返回一个数组
var obj = {name: 'siguang', age: 33};
console.log(Object.keys(obj)); // [name, age]
console.log(Object.values(obj)); // ['siguang', 33]
八、__proto__属性
用来读取或设置当前对象的prototype对象
var Person = function(name){
this.name = name;
}
Person.prototype = {
constructor: Person,
getName(){
console.log(this.name);
}
}
var op = new Person('lulu');
// 继承
var PersonChilder = function(){};
PersonChilder.__proto__ = op;
var opc = new PersonChilder();
console.log(opc.getName())
增强的对象字面量
// 通过对象字面量创建对象
var human = {
breathe() {
console.log('breathing...');
}
};
var worker = {
__proto__: human, //设置此对象的原型为human,相当于继承human
company: 'freelancer',
work() {
console.log('working...');
}
};
human.breathe(); // 输出 ‘breathing...’
// 调用继承来的breathe方法
worker.breathe(); // 输出 ‘breathing...’
九、遍历属性的方法
1、for...in 循环
2、Object.keys(obj): 返回obj对象的所有key, 返回是一个数组
字符串对象扩展
1、repeat(): 复制字符串
var str = '哈哈哈!'.repeat(3); // str输出 '哈哈哈!哈哈哈!哈哈哈!'
2、includes()、startsWith()、endsWith(): 查找三个方法
var str = 'siguang 1983';
str.includes('o'); // 查找字符串中是否包含值,包含返回true否则返回false
str.startsWith('s'); // 第一个字符是不是s,如果是返回true
str.endsWith('d'); // 最后一个字符是不是 d,返回布尔值
3、padStart(): 补全长度从开头, 'x'.padStart(4, 'ab') // 'abax'
4、padEnd(): 补全长度从结尾, 'x'.padEnd(4, 'ab') // 'xaba'
Number、Math对象扩展
一、Math扩展
1、trunc(): 去除小数部分 Math.trunc(123.123123); // 123
2、sign(): 判断是正数还是负数,如果是正数返回1,负数返回-1,0返回0
3、Math.sign(-234); // -1
4、hypot(): 返回所有参数的平方和的平方根,Math.hypot(3,4); // 5 勾股定理
二、Number对象扩展
1、isFinite(): 是否是无穷数
2、Number.isNaN(): 是否是NaN
3、parseInt('12.34'): es5的写法 Number.parseInt('12.34'): es6的写法,为了减少全局方法
4、Number.isInteger(num): 判断是否是一个整数
数组扩展 Array
一、form(): 将对象转成数组
var obj = {'0': 'a', '1': 'b', '2': 'c'};
var arr = Array.form(obj); console.log(arr); // [a, b, c]
二、of(): 将一组值转成数组
var arrA = new Array(1, 2, 3); // 生成一个[1,2,3]
var arrB = new Array(3); // arrB.length 等于3 如果传一个参数这样会生成一个3个空值
var arrC = Array.of(3); // [3] 解决了new Array的问题
三、find(): 找出第一个符合条件的数据元素
// 找出数组中值大于3的第一个数
var arr = [1,2,3,4,5,6];
var n = arr.find(function(value, index){
return value > 3;
})
console.log(n); // 4
四、findIndex(): 找出第一个符合条件的位置,也就是所引值
五、fill(填充内容, 填充开始的位置, 填充结束的位置): 填充数组
var arr = [1,2,3,4,5,6];
arr.fill(7); // 数组里全部为7
arr.fill(7, 1, 3); // 数组下标从1-3的值为7
console.log(arr);
六、for...of: 遍历数组、字符串的值,但不能遍历对象
// var arr = 'sdfsfdasdfasdf';
var arr = [1,2,3,4,5,6];
for(var value of arr){
console.log(value); // 1,2,3,4,5,6 只能将遍历出数组的值
}
七、keys()和values(): 返回数组的Key或value
// var arr = 'sdfsfdasdfasdf';
var arr = [1,2,3,4,5,6];
for(var value of arr.key()){
console.log(value);
}
八、entries(): 将数组的key和value一块输出
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
for(var [key, value] of arr.entries()){
console.log(key, value);
}
返回:
0 "a"
1 "b"
2 "c"
3 "d"
4 "e"
5 "f"
九、includes(): 查看数组中是否包含指定的值
var arr = [1, 2, 3, 4, 5];
arr.includes(3); // true
二进制数组 ArrayBuffer对象
二进制数组由三类对象组成:
ArrayBuffer对象: 代表原始的二进制数据。
TypedArray视图: 用来读写简单类型的二进制数据。
DataView视图: 用来读写复杂类型的二进制数据。
一、ArrayBuffer 对象
它不能直接读写,只能通过(TypedArray和DataView)来读写。
ArrayBuffer也是一个构造函数,可以分配一段可以存放数据的连续内存区域。
var buf = new ArrayBuffer(32); // 生成一段32字节的内存区域,每个字节默认为0
属性和方法:
1、byteLength: 返回分配内存的字节长度
var buffer = new ArrayBuffer(32);
buffer.byteLength; // 32
2、slice(): 拷贝字节
var buffer = new ArrayBuffer(8);
var newBuffer = buffer.slice(0, 3); //拷贝`buffer`对象的前三个字节(从0到3前结束),生成一个新的ArrayBuffer对象: newBuffer
3、isView(): 返回一个布尔值,表示参数是否为ArrayBuffer的视图实例
var buffer = new ArrayBuffer(8);
ArrayBuffer.isView(buffer) // false
var v = new Int32Array(buffer);
ArrayBuffer.isView(v) // true
二、TypedArray 视图
TypedArray数组只提供9种固定的构造函数
Symbol
JS新的数据类型,独一无二的值,凡是属性名属于Symbol类型,就是独一无二的
# 没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
# 有参数的情况
var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2 // false
一、不能与其它值进行运算
var sym = Symbol('My symbol');
console.log("your symbol is " + sym); // 报错
二、toString()转成字符串
let sym = Symbol('my symbol');
sym.toString() // "Symbol(my symbol)"
Proxy对象拦截器
可以监听对象身上发生变化,对操作对象属性读取时做一个拦截器
<script>
let obj = {
a: 1,
b: 2
}
// 相当于操作对象属性时的一个拦截器
let oProxy = new Proxy(obj, {
get(obj, key) {
return obj[key];
},
set(obj, key, value) {
// 这里来做拦截,如果修改的key=a 并且 value值小于10不会就将值修改
if (key == 'a' && value < 10) {
obj[key] = value;
}
}
})
// 设置属性
oProxy.a = 9; // {a: 9, b: 2}
oProxy.a = 20; // {a: 9, b: 2}
oProxy.b = 10; // {a: 9, b: 20}
// 获取属性值
console.log(oProxy.a, oProxy.b);
</script>
Promise异步
// resolve: 成功、reject: 失败
var pro = new Promise(function(resolve, reject){ // resolve成功, reject失败
// 将一个耗时长的任务放到执行器里
setTimeout(function(){
resolve(); // 4毫秒后执行成功
}, 400)
})
pro.then(
function(){ // reslove回调
console.log('成功执行');
},
function(){ // reject回调
console.log('失败执行');
}
)
.catch(function(e){ // 捕获异常,如果then中的两个方法成功失败有报错就会走catch
console.log(e)
})
// 如果不需要reslove的回调可以设置为null
por.then(null, functino(){
console.log('失败执行')
})
方法:
一、Promise.all([实例1,实例2,实例3]): 用于多个promise实例,当三个实例都为真的时候all这个结果为真
var p1 = new Promise(function(resolve, reject){
setTimeout(function(){
resolve();
console.log("p1完成");
}, 400);
})
var p2 = new Promise(function(resolve, reject){
setTimeout(function(){
resolve();
console.log("p2完成");
}, 1000);
})
var p3 = new Promise(function(resolve, reject){
setTimeout(function(){
resolve();
console.log("p3完成");
}, 4000);
})
var p4 = Promise.all([p1, p2, p3]);
p4.then(function(){
console.log('三个全部执行成功')
}, function(){
console.log('失败')
})
二、Promise.race([实例1,实例2,实例3]): 只要有一个为成功,p4为成功,与all()方法正反
https://www.jianshu.com/p/c98eb98bd00c
Generator
Generator是一个状态机,封装了多个内部状态, 也是一个遍历对象生成函数,返回遍历器对象
Example:
function* ouputGenerator() {
yield 'hello'; // 调用后不会马上执行,只有调用next()才会返回
yield 'world';
return 'ending';
}
let gen = ouputGenerator();
console.log(gen.next()); // {value: "hello", done: false} value就是返回值
console.log(gen.next()); // {value: "world", done: false}
console.log(gen.next()); // {value: "ending", done: true} done为true就是后面没有yeild的定义
一、Generator的特征:
1、function 关键字与函数名之间有一个"*"号
2、函数体内有 yield 语句
3、可以执行暂停
4、generator也可以不用yield, 但需要执行一次next()
二、属性和方法
1、next() 可以带一个参数,参数可以是上一个yield的返回值
done为true 表示结束 Object {value: "ending", done: true}
2、value: 就是next返回的值,done为false表示已经结束
3、yield: 定义表达式
三、Generator与Promise的区别
promise如果写多个嵌套会很麻烦:
getArticleList()
.then(articles => getArticle(articles[0].id))
.then(article => getAuthor(article.authorId))
.then(author => {
alert(author.email);
});
function getAuthor(id){
return new Promise(function(resolve, reject){
$.ajax("http://beta.json-generator.com/api/json/get/E105pDLh",{
author: id
}).done(function(result){
resolve(result);
})
});
}
function getArticle(id){
return new Promise(function(resolve, reject){
$.ajax("http://beta.json-generator.com/api/json/get/EkI02vUn",{
id: id
}).done(function(result){
resolve(result);
})
});
}
function getArticleList(){
return new Promise(function(resolve, reject){
$.ajax(
"http://beta.json-generator.com/api/json/get/Ey8JqwIh")
.done(function(result){
resolve(result);
});
});
}
Generator的写法:
function* run(){
var articles = yield getArticleList();
var article = yield getArticle(articles[0].id);
var author = yield getAuthor(article.authorId);
console.log(author.email);
}
var gen = run();
gen.next().value
.then(articles => {
gen.next(articles).value.then(article => {
gen.next(article).value.then(author => {
gen.next(author)
})
})
})
async、await
async 是ES7引入的函数,使的异步变得更加方便
await: 命令后面是一个Promise对象
Generator函数执行必须靠执行器,也就是需要调next(),async函数有自带的执行器,async返回的是Promise对象
一、async的多种声明
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
// 箭头函数
const foo = async () => {};
二、async函数返回一个Promise对象,函数内部有return返回值,可以通过then方法来接收
async function f(){
return 'hello world'
}
f().then( v => {
console.log(v);
})
Example:
async function getStockPriceByName(name) {
var symbol = await getStockSymbol(name);
var stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
| http://www.ruanyifeng.com/blog/2016/01/babel.html
| http://es6.ruanyifeng.com/#docs/style
| http://babeljs.cn/