嗯,之前之做项目大概了解一些,之后看Vue实战里讲一些,简历里写了这个,所以决定系统学习,第一次接触大佬阮一峰是讲Flex布局的一篇博文,感觉很好,居然把书开源,嗯,嘻嘻,真好,生活加油. 2020.2.01
嗯,记得都是书里的笔记,和一些常见的Demo,适合温习,面试的时候看看,后端可以看看,前端不适合,还是系统的学习好。
电子档网址:http://es6.ruanyifeng.com/
pdf百度云资源:链接:https://pan.baidu.com/s/100G-QDBtNFrQPlp8vdthBQ 提取码:cffe
嗯,最近看的书摘一句:
一切一切,凡已属于和能属于这个世界的一切,都无可避免得带有以主体为条件[的性质],并且也仅仅只是为主体而存在的.世界即是表象 。
-----------《作为意志和表象的世界》
简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。即
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
webpack的核心优势在于它从入口文件出发,递归构建依赖关系图。通过这样的依赖梳理,webpack打包出的bundle不会包含重复或未使用的模块,实现了按需打包,极大的减少了冗余。
随同NodeJS一起安装的包管理工具,为你和你的团队打开了连接整个 JavaScript 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)。来自各大洲的开源软件开发者使用 npm 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。
类似于maven的一个依赖工具,用 JavaScript (运行在 Node.js 上)写的 npm,全称是 Node Package Manager,
npm install --save app 与 npm install --save-dev app有什么区别?
npm install --save app: 保存需要加载的依赖的信息到package.json里面,该模块使用时,该依赖被调用
npm install --save-dev app: 开发测试时使用的依赖,当需要测试时,可以调用该依赖
Node.js 是由一个在德国工作的美国程序员 Ryan Dahl 写的。他写了 Node.js,但是 Node.js 缺少一个包管理器,于是他和 npm 的作者一拍即合、抱团取暖,最终 Node.js 内置了 npm。
//转码前
input.map(item =>{item + 1});
//转码后
input.map(function(item){return item + 1;});
let用于声明变量,用法类似于var,用于声明局部变量,即指在当前代码块里可见,
适用场景:for循环:
for(var i = 0; i < 10; i++){ a[i] = function(){console.log(i);}}
a[6](); //输出10;变量i是全局的,在全局范围内有效,赋值给数组内部的console.log(i)中的i是全局的。即所有的i在经过最后一次循环之后都是10.
for(let i = 0; i < 10; i++){ a[i] = function(){console.log(i);}}
a[6]();//输出6,对于let声明的,在循环块里才有效,即每一次都是新的值
既然是新的值,为啥会记住呢?因为javaScript引擎会记住上一轮的值,对于for循环来讲,就是设置循环变量的那部分是父作用域,循环的那部分是子作用域。
for(let i = 0; i < 3; i++){let i = 'liruilong'; console.log(i)};
// 会输出3次liruilong
不存在变量提升:
暂时性死区(TDZ):
不允许重复声明.
ES5 只有全局作用域和函数作用域,没有块级作用域,这导致很多场景不合理。 let 实际上为 JavaScript 新增了块级作用域.
块级作用域与函数声明
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明 。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。 ES6 规定,在块级作用域 之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用。
do表达式:
do表达式
let x = do{
let t = f();
t * t + 1;
};
// 书上说变量x会得到整个作用域的值,那他是得到的值经过t * t + 1;这个运算没。
const声明一个只读的常量,一旦声明,常量的值就不能改变。所以必须初始化。
const 的作用域与 let 命令相同:只在声明所在的块级作用域内有效。也不会发生常量提升,同样存在暂时性死区,只能在声明后使用.
con st 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。 对于简单类型的数据(数值、字符串、布尔值〉而言,值就保存在变量指向的内存地址中,因此等同于常量。但对于复合类型的数据(主要是对象和数组)而言,变量指向的内存地址保存 的只是一个指针, const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的, 这完全不能控制
var a = 1;
//如果在Node的REPL环境,可以写成global.a
//或者采用通用的方法,写成this.a
window.a // 1
let b= 1;
window.a //undefined
使用global的写法.
//CommonJs的写法
require('system.global/shim')();
//ES6模块的写法
import shim form 'system.global/shim';shim();
ES6 允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构 ( Destructuring)。
ES6允许写出类似于python的 直接赋值的语法,模式匹配
let [a,b,c] = [1,3,4];
function* fibs(){
let a = 0;
let b = 0;
while(ture){
yield a;
[a,b] = [b,a + b];
}
}
let [first, second, third, fourth, fifth, sixthl] =fibs();
sixth // 5
//yield也必须在Generator函数中才有意义,脱离了Generator就没意义了,fibs被定义为一个Generator函数,具有原生的Iterator接口。结构赋值会依次从这个接口获取值。运行.next(),遇到一个yield命令,就暂停.
import { getRequest } from "./api";
/*
* 对菜单路由进行处理
* */
export const initMenu = (router, store) => {
if (store.state.routes.length > 0) {
return;
}
getRequest("/system/config/menu").then(data => {
if (data) {
let fmtRoutes = formatRoutes(data);
//添加路由
router.addRoutes(fmtRoutes);
//初始化数据
store.commit('initRoutes', fmtRoutes);
}
})
}
// *
// 菜单数据的格式话 *
export const formatRoutes = (routes) => {
let fmRoutes = [];
routes.forEach(router => {
// 数组的解构赋值
let {
path,
component,
name,
meta,
iconcls,
children
} = router;
if (children && children instanceof Array) {
children = formatRoutes(children);
}
//对象的解构赋值
let fmRouter = {
path: path,
name: name,
iconcls: iconcls,
meta: meta,
hidden: false,
children: children,
component (resolve) {
if (component.startsWith("Home")) {
require(['../views/' + component + '.vue'], resolve);
} else if (component.startsWith("Emp")) {
require(['../views/emp/' + component + '.vue'], resolve);
} else if (component.startsWith("Per")) {
require(['../views/per/' + component + '.vue'], resolve);
} else if (component.startsWith("Sal")) {
require(['../views/sal/' + component + '.vue'], resolve);
} else if (component.startsWith("Sta")) {
require(['../views/sta/' + component + '.vue'], resolve);
} else if (component.startsWith("Sys")) {
require(['../views/sys/' + component + '.vue'], resolve);
}
}
}
fmRoutes.push(fmRouter);
})
return fmRoutes;
}
字符串的解构赋值,字符串也可以解构赋值,因为此时字符串被转换为类似的数组的对象。
const {a,b,c,d,e} = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
let{lenth:len} = 'hello';
len //5
let {prop:x} = undefined;
let {prop:y} = null;
//函数参数的解构赋值
function add([x,y]){return x + y;}
add([1,2]); // 3
[[1,2],[3,4]].map(([a,b] => a + b ));
//[3,7]
function move({x = 0, y = 0} = {}){ return[x,y];}
交换变量的值:从函数返回多个值.(数组+对象);
let x = 1;
let y = 2;
[x,y] = [y,x]
// 交换变量的值
//从函数返回多个值
// 返回数组
function example(){return [1,2,3];}
let [a,b,c] = example();
// 返回对象
function example(){return foo:1,bar:2};}
let {foo, bar} = example();
函数参数的定义提取Json数据
//函数参数的定义
function f([x,y,z]){...}
f([1,2,3]);
//参数是一组没有顺序的值
function f({x,y,z}){...}
f({z:3,y:2,x:1});
解构赋值对于提取JSON对象种的数据尤为有用:
//提去JSON数组的值
let jsonData = {id:42, status:"OK"data:[876,5309]};
let { id, status, data: number } = jsonData;
遍历Map结构
//遍历Map解构
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for(let [key,value] of map){
console.log(key + "is" + value);
}
可以只写或者键或者值的写法。
输入模块的指定方法
加载模块时,往往需要指定输入的方法。解构赋值使得输入语句非常清晰。
const ( SourceMapConsumer, SourceNode } = require (”source-map");
基本用法:
函数参数的默认值:
ES6之前
function log(x, y){
y = y || 'world';
console.log(x,y);
}
ES6之后可以使用参数设置默认值,即直接写在参数定义的后面。也可以于解构赋值结合使用。
function log(x,y = 'World'){console.log(x,y)}
函数的length属性,
指定了默认值之后,函数的length属性将返回没有指定的默认值的参数个数,
ES6之后可以使用参数设置默认值,即直接写在参数定义的后面。也可以于解构赋值结合使用。
function log(x,y = 'World'){console.log(x,y)}
(function (a) {}).length // 1
(functi on (a= 5){}).length // 0
(function (a, b , c = 5){}).length // 2
作用域:
一旦设置了参数的作用域,函数进行声明初始化时,参数会形成一个单独的作用域,等到初始化结束,这个作用域就会消失,这种语法在不设置参数作用域不会出现.
let x = 1;
function f(x,y = x){
console.log(y);
}
f(2) // 2
let x = 1;
function f(x,y = x){
let x = 2;
console.log(y);
}
f()// 1
let foo = 'outer';
function bar(func = x => foo){
let foo = 'inner';
console.log(func());
}
bar() // outer
function bar(func = () => foo){
let foo = 'inner';
console.log(func());
}
bar() //ReferenceError:foo is not defined;
ES6引入了rest,即类似Java的可变参数,用于获取多个参数.
//rest参数的使用
function add(...values){
let sum = 0;
for(var val of values){
sum += val;
}
return sum;
add(1,23,4) //28
//使用argument对象
function sortNumbers(){ return Array.proptotype.slice.call(arguments).sort();}
//使用rest参数
const sortNumbers = (...numbers) => numbers.sort();
函数的name属性返回函数的函数名
function foo (){};
foo.name // foo
基本用法:
ES6 允许使用“箭头”(=>)定义函数。类似于Java8的lambda表达式.
var f = v => v;
var f = function(v){return v}
// 正常函数写法 [l , 2 , 3].map (function (x) { return x * x; ., ) }
//箭头函数写法 [1, 2 , 3 ].map(x => x * x );
下面是另一个例子。
//正常函数写法 var result= values . sort (function (a, b) { return a - b; . , ) }
//箭头函数写法 var result = values . sort ((a, b) => a - b);
箭头函数有以下几个使用注意事项。
1. 函数体内的 this 对象就是定义时所在的对象,而不是使用时所在的对象。
function foo(){
setTimeout( () =>{
console.log('id:',this.id);
},100);
}
var id = 21;
foo.call({id:42});
// id:42
2. 不可以当作构造函数。 也就是说, 不可以使用 new 命令, 否则会抛出一个错误。
3. 不可以使用 arguments 对象, 该对象在函数体内不存在。如果要用,可以用 rest 参数 代替。
4. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
嵌套的箭头函数
//ES6之前
function insert(value) {
return {into: function (array) {
return {after: function (afterValue) {
array.splice(array.indexOf(afterValue) + 1,0,value);
return array; }
} ;
}} ;
insert(2).into([l, 3]).after(l) ; //[1, 2, 3)
//ES6
let insert= (value) => ({into: (array) => ({after: (afterValue) => { array.splice(array. indexOf(afterValue) + 1 , 0, value);
return array; } } ) } };
insert(2).into([l, 3]).after(l) ; //[l, 2 , 3)
箭头函数可以绑定 this 对象,大大减少了显式绑定 this 对象的写法( call、 apply、 bind)。但是,箭头函数并非适用于所有场合,所以 ES7 提出 了“函数绑定”( function bind) 运算符,用来取代 call、 apply、 bind 调用。虽然该语法还是 ES7 的一个提案( github.com/ zenparsing/es- function-bind),但是 Babel 转码器已经支持。
尾调用(Tail Call)(钩子函数)
是函数式编程的一个重要概念, 就是指某个函数的最后一步是调用另一个函数。也称钩子函数,在Javal里JVM中有钩子线程.在jvm进程结束的调用,尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、 内部变量等信息都不会再用到了,直接用内层函数的调用帧取代外层函数的即可。
尾调用的优化
“尾调用优化” (Tail Call Optimization),即只保留内层函数的调用帧。 如果所有函数都是尾调用,那么完全可以做到每次执行时调用帧只有一项,不需要在维护调用它的栈,这将大大节省内存。这就是 “尾调用优化”的意义。
function f(){
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 优化之后
function f(){
return g(3);
}
函数调用自身称为递归。如果尾调用自身就称为尾递归。 递归非常耗费内存,因为需要同时保存成百上千个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
严格模式:ES6 的尾调用优化只在严格模式下开启,正常模式下是无效的。
函数参数的尾逗号:,允许函数的最后一 个参数有尾逗号(trailing comma)。
扩展运算待
ES6 提供了新的数据结构一-Set。 它类似于数组,但是成员的值都是唯一的,没有重复。
const s =new Set() ;
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)) ;
for (let i of s) { console.log(i)};
// 2 3 5 4
Set 函数可以接受一个数组。或者具有迭代器接口的其他的数据结构作为参数,用来初始化
const set = new Set([1,2,3,4,4]);
[...set] // [1,2,3,4]
set.size //4
Set 结构的实例有以下属性。
Set 实例的方法分为两大类:
WeakSet 结构与 Set 类似,也是不重复的值的集合。 但是,它与 Set 有两个区别。ES6规定WeakSet是不可遍历的.
const ws =new WeakSet();
const a = [ (1 , 2], (3, 4));
const ws =new WeakSet(a) ; // WeakSet {[l, 2), [3, 4))
WeakSet 结构有以下 3 个方法。
ES6 提供了 Map 数据结构。它类似于对象,
const m =new Map() ;
const o = {p:’Hello World’} ;
m.set(o,’content ’);
m.get(o) // ”content”
m.has(o) //true
m.delete(o) //true
m.has(o) // false
Map 原生提供了 3 个遍历器生成函数和 l 个遍历方法。
const map= new Map([ [’ F ’,’no ’] , [’ T’,’yes ’ ] ,]);
for (let key of map.keys() ) {
console .log (key); }
// ” F”
// ” T”
for (let value of map.values()) {
console.log(value) ;}
// ”no”
// ” yes”
for (let [key, value] of map.entries()) {
console.log(key, value);}
// ”F””no”
// ”T” ” yes”
//等同于使用 map.entries ()
for (let [key, value] of map) { console . log(key,value)} ;
Map 结构转为数组结构的比较快速的方法是结合扩展运算符( ..)。
const map = new Map ( [ [ 1, ’ one ’], (2,’two ’] , (3,’three ’ ],]);
[...map.keys () ] //(1 , 2 , 3]
[...map.values(}] //[ ’ 。ne ’,’ two ’,’ three ’ ]
[...map.entries ()] I I [ [ 1,’one ’], (2,’two ’], (3,’three ’] ]
[...map] I I [ [ 1,’one ’], (2,’two ’], (3,’three ’ ]]
数组转Map:将数组传入Map构造函数就可以转为Map。
new Map([[true,7],[{foo:3},['abc']]]);
// map {true => 7, Object {foo:3} =>['abc']}
Map转为对象:如果 Map 的所有键都是字符串,则可以转为对象。
function strMapToObj(srtMap){
let obj = Object.create(null);
for( let [k,v] of strMap){
obj[k] = v;
}
return obj;
}
const myMap = new Map().set('yes',true).set('no',false);
strMapToObj(myMap) //{yes:true, no:false }
Map 转为 JSON
一种情况是, Map的键名都是字符串,这时可以选择转 为对象 JSON。
function strMapToJson(strMap){return JSON.stringify(strMapToObj(strMap));}
let myMap =new Map().set(’yes’,true).set(’no ’,false);
strMapToJson(myMap)
// ’{”yes”:true ,”n。”: false }’
另一种情况是,Map 的键名有非字符串,这时可以选择转为数组 JSON。
function mapToArrayJson(map) {
return JSON.stringify([ ... map]);}
let myMap =new Map().set(true,7).set({foo : 3),[’ abc ’]);
mapToArrayJson(myMap)
// ’[( true,7 ], [{ ” foo”: 3}, [”abc”]]]’
JSON 转为 Map,正常情况下所有键名都是字符串 。
function jsonToStrMap(jsonStr) {
return objToStrMap (JSON.parse(jsonStr) );
jsonToStrMap (’{” yes” : true ,”no”: false } ’ )
// Map {’ yes ’=> true,’no’ => false}
WeakMap 结构与 Map 结构类似,也用于生成键值对的集合。
第一, WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
第二, WeakMap 的键名所指向的对象不计入垃圾回收机制。
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编 程”(meta programming),即对编程语言进行编程。
Proxy 可以理解成在目标对象前架设一个“拦截”层
外界对该对象的访问都必须先通过 这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。
ES6 原生提供 Proxy 构造函数,用于生成 Proxy 实例。
var proxy= new Proxy(target, handler) ;
Proxy 对象的所有用法都是上面这种形式,不同的只是 handler 参数的写法。 其中,
var obj = new Proxy({}, {
get:function (target, key){
console.log();
return Reflec.get(tafget, key);
},
set:function(target, key){
console.log();
return Reflec.get(tafget, key);
}
});
new Proxy (),表示生成一个 Proxy 实例, target 参数表示所要拦截的目标对象, handler 参数也 是一个对象,用来定制拦截行为。
下面是 Proxy 支持的所有拦截操作。 对于可以设置但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。
const service = createWebService("url");
service.employees().then(json =>{const employees = JSON.parse(json);});
//Proxy 可以拦截这个对 象的任意属性,所以不用为每一种数据写一个适配方法,只要写一个 Proxy 拦截即可。
function createwebService(baseUrl){
return new Proxy({},{
get(target, propKey, receiver) { return () => httpGet (baseUrl+’ / ’ + propKey) ; })}
Reflect 对象与 Proxy 对象一样,也是 ES6 为了操作对象而提供的新的 API. Reflect 对象的设计目的有以下几个。
try{
Object.defineProperty(target,property,atttribute);
//success
}catch(e){
//failure
}
if(Reflect.defineProperty(target,property,atttribute)){
//success}else{
//failure
}
Promise 是异步编程的一种解决方案,比传统的解决方案一一回调函数和事件→一更合理且 更强大。 ES6 将其写进了语言标准,统一了用法,并原生提供了 Promise 对象。
所谓 Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个 异步操作)的结果。从语法上来说, Promise 是一个对象,从它可以获取异步操作的消息。 Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
var promise= new Promise(function(resolve, reject) {
// ... some code
if (/*异步操作成功*/){ resolve(value) ; }
else { reject(error); } }) ;
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。 它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
promise.then(function (value){//success},function (error){//failure})
then 方法可以接受两个回调函数作为参数。
Promise 对象的简单例子。
function timeout(ms){return new Promise((reslve,reject) =>{setTimeout(recelve,ms,'done')})}
timeout(100).then((value) =>{ console .log (value); });
Promise 新建后就会立即执行。
let promise= new Promise(function(resolve, reject){console.log(’Promise’); resolve(); })
promise.then(function(){console.log (’Resolved.’);});
console.log(’Hi!’);
// Promise
// Hi!
// Res。lved
用 Promise 对象实现的 AJAX 操作的例子。
var getJSON = function(url) {
var promise= new Promise(function(resolve, reject) {
var client= new XMLHttpRequest() ;
client.open(” GET”, url);
client.onreadystatechange = handler;
client.responseType = ” json”;
client.setRequestHeader (”Accept”,”application/json” ) ; client.send() ;
function handler(){
if(this.readyState !== 4){
return;
}
if (this.status === 200) {
resolve(this.response) ; }
else { reject(new Error(this.statusText)} ;
};});
return promise ;
getJSON (”/posts.Json”).then(
function(json){
console.log ( ’Contents:’+ json);
},
function(error} { console. error (’出错了’, error);});
一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 上面的请求也可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
export const postRequest = (url, params) => {
return axios({
method: 'POST',
url: `${base}${url}`,
data: params,
})
}
// put请求封装
export const putRequest = (url, params) => {
return axios({
method: 'put',
url: `${base}${url}`,
data: params,
})
}
// get请求封装
export const getRequest = (url, params) => {
return axios({
method: 'get',
url: `${base}${url}`,
data: params,
})
}
// delete请求封装
export const deleteRequest = (url, params) => {
return axios({
method: 'delete',
url: `${base}${url}`,
data: params,
})
使用 then
时,你将接收下面这样的响应 :
axios.get('/user/12345')
.then(function(response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
学习网站:http://www.axios-js.com/zh-cn/docs/
Promise 实例具有 then 方法,即 then 方法是定义在原型对象 Promise .prototype 上 的。它的作用是为 Promise 实例添加状态改变时的回调函数。 前面说过, then 方法的第一个参数是 Resolved 状态的回调函数,第二个参数(可选)是 Rejected 状态的回调函数。 then 方法返回的是一个新的 Promise 实例(注意,不是原来那个 Promise 实例)。因此可 以采用链式写法,即 then 方法后面再调用另一个 then 方法。
方法是 . then(null, rejection)的别名,用于指定发 生错误时的回调函数。: 如果异步操作抛出错误,状态就会变为Rejected ,然后调 用 catch 方法指定的回调函数处理这个错误。另外, then 方法指定的回调函数如果在运行中抛出错误,也会被 catch 方法捕获。
Promise.all() :Promise.all 方法用于将多个 Promise 实例包装成一个新的 Promise 实例。异步并发情况.
var p = Promise.all([pl,p2,p3]);
//p 的状态由 pL p2 、 p3 决定, 分成两种情况。
1. 只有 pl 、 p2 、 抖的状态都变成 Fulfilled, p 的状态才会变成 Fulfilled,此时 pl、 p2、 p3 的返回值组成一个数组,传递给 p 的回调函数。
2. 只要 pl、 p2、 p3 中有一个被 R可ected, p 的状态就变成 Rejected, 此时第一个被 R句ected 的实例的返回值会传递给 p 的回调函数。
Promise.race() :Promise.race 方法同样是将多个 Promise 实例包装成一个新的 Promise 实例。Promise . race 方法的参数与 Promise . all 方法一样,如果不是 Promise 实例,就会先 调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。
Promise.resolve() :有时需要将现有对象转为 Promise 对象, Prom工se.resolve 方法就起到这个作用。
Promise.reject() :Promise.reject(reason )方法也会返回一个新的 Promise 实例,状态为 Rejected。
ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令 输入。这种加载称为“编译时 加载”或者静态加载,即 ES6 可以在编译时就完成模块加载
import { stat, exists, readFile } from ’ fs ’ ;
ES6 的模块自动采用严格模式,不管有没有在模块头部加上“use strict ”。
模块功能主要由两个命令构成: export 和 import。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果希望外部能 够读取模块内部的某个变量,就必须使用 export 关键字输出该变量。下面是一个 JS文件,里 面使用 export 命令输出了变量。
//profile.js
export var f irstName =’Michae l ’ ;
export var lastName =’Jackson ’;
export var year = 1958;
// profile.js
var firstName =’ Michael’;
var lastName =’Jackson ’ ;
var year = 1958;
export {firstName, lastName, year} ;
export 命令除了输出变量,还可以输出函数或类 (class)。 export 输出的变量就是本来的名字,但是可以使用 as 关键字重命名
使用 export 命令定义了模块的对外接口以后,其他 JS 文件就可以通过 import 命令加 载这个模块了。
// main.js
import {firstName, lastName, year} from '. lprofile ’;
function setName(element} { element.textContent = firstName +’’+ lastName; }
除了指定加载某个输出值,还可以使用整体加载(即使用*来指定一个对象,所有输出值都加载在这个对象上)。模块整体加载所在的对象(上例是 circle )应该是可以静态分析的,所以不允许运行时改变。
// circle.js
export function area(radius) {
return Math.PI*radius * radius;
export function circumference(radius) {
return 2 * Math.PI * radius ;
// main.js
import * as circle from ’ .lcircle ’;
console .log ( ’ 因面积:’+ circle.area(4));
console . log ( ' 圆周长:’+ circle.circumference(l4)) ;
使用 export default 命令为模 块指定默认输出。export default 命令用于指定模块的默认输出。显然, 一个模块只能有一个默认输出, 因此 export deaul t 命令只能使用一次。所以 import 命令后面才不用加大括号,因为只可 能对应一个方法。
//modules.js
function add(x, y) {
return x * y;
export {add as default);
//等同于
// export default add;
// app.js
import { default as xxx ) from ’modules ’ ;
// 等同于
// import xxx from ’ modules ’;
如果在一个模块之中先输入后输出同一个模块, import 语句可以与 export 语句写在 一起。
export { foo , bar } from ’my_module ’;
//等同于
import { foo, bar J from ’my_module ’;
export { foo, bar };
模块之间也可以继承。
假设有一个 circleplus 模块继承了 circle 模块。
// circleplus . js
export * from ’ circle ’ ;
export var e = 2.71828182846;
export default function(x) {
return Math . exp (x) ;
上面的 export *表示输出 circle 模块的所有属性和方法。
import 命令会被 JavaScript 引擎静态分析, 先于模块内 的其他模块执行(称 为“连接”更合适)。
// 报错
if (x === 2 ) {
import MyModual from ’./lmyM odual ’ ; }
引擎处理 import 语句是在编译时,这时不会分析或执行if 语句,所以 import 语句放在 if 代码块之中毫无意义,因此会报句法错误, 而不是执行时错误。也就是说, import 和 export 命令只能在模块的顶层,不能在代码块之中 (比如,在 if 代码块之中, 或在函数之中)。 这样的设计固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条 件加载不可能实现。如果 import 命令要取代 Node 的 require 方法,这就形成了一个障碍。 因为 require 是运行时加载模块, import 命令无法取代 require 的动态加载功能。
import ()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用 。它是运行 时执行,也就是说,运行到这一句时便会加载指定的模块。另外, import ()函数与所加载的 模块没有静态连接关系,这点也与 import 语句不相同。import ()类似于 Node 的 require 方法,区别主要是,前者是异步加载,后者是同步 加载。
import(specifier);
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
import(f())
.then(...);
import()
加载模块成功以后,这个模块会作为一个对象,当作then
方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口。
import('./myModule.js')
.then(({export1, export2}) => {
// ...·
});
上面代码中,export1
和export2
都是myModule.js
的输出接口,可以解构获得。
如果模块有default
输出接口,可以用参数直接获得。
import('./myModule.js')
.then(myModule => {
console.log(myModule.default);
});
上面的代码也可以使用具名输入的形式。
import('./myModule.js')
.then(({default: theDefault}) => {
console.log(theDefault);
});
嘻嘻,剩下的每天看一点