ES6
介绍
ES6是ES5的升级版,兼容ES5和ECMAScript,新增了许多新特性,例如:解构、异步函数、承诺……,语法简单,功能更强。但是ES6在浏览器上兼容性差一些,在nodejs上可以完全兼容。
环境(node.js)
$ node -v 检测环境
$ v10.14.2 当前环境
-
安装vi及spf-13
$ vi demo.js
- 安装node.js
Linux
先将安装包解压
然后进行环境变量的配置即可
windows
直接点击安装即可 -
REPL环境
$ node
1+1
新特性
例如:
['terry','larry','tom'].forEach((item)=>{console.log(item)})
terry
larry
tom
undefined
模块化 (xxx.js上分模块)
ES6---babel/webpack(js插件运行在node.js上)--->ES5
区分:
dom驱动:~~~~
含义:通过ajax获取数据,创建结构,再将数据填充
真实dom机制,先渲染dom节点,再通过js操作dom
<div class="a">
数据驱动:(vue)
含义:来源于后台数据,通过ajax获取数据,创建虚拟dom节点,追加到页面中
虚拟dom机制,通过js创建一个dom
$(<div class="a"></div>
).appendTo($('body'))
高级脚本语言
<script>
jsx(javascript xml)
less/sass
</script>
模块化结构
Node.js采用模块化结构,按照 CommonJS 规范定义和使用模块。在Node中,以模块为单位划分所有功能,并且提供一个完整的模块加载机制,使得我们可以将应用程序划分为各个不同的部分,并且对这些部分进行很好的协同管理。通过将各种可重用的代码编写在各种模块中的方法,我们可以大大减少应用程序的代码量,提高应用程序开发效率以及应用程序的可读性。通过模块加载机制,我们也可以将各种第三方模块引入到我们的应用程序中。
其意图是应用程序开发人员能够使用CommonJS API编写应用程序,然后在不同的JavaScript解释器和主机环境中运行该应用程序。在兼容CommonJS的系统中,你可以使用 JavaScript程序开发。
模块定义:一个单独js文件,或一个目录,目录的嵌套也可以是一个模块
模块作用域:每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见
。如果想在多个文件分享变量,必须定义为global对象的属性。
模块交互:每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
定义模块:module.exports.x = x;
模块加载:var example = require('./example.js');
node_modules 是一个目录,用于存放第三方模块
module变量
在任意一个js文件中,都包含一个变量叫module,module表示当前模块的一些信息
id
filename 完整路径+文件名
paths require的时候去哪里寻找要加载的模块,当前模块node_modules-->上级模块node_modules
parent 父模块
children 子模块~~~~
exports 对外暴露的对象,require当前模块实际上就是require这个exports对象
require()
用于加载其他模块
1) 参数为路径
require('./module1')
按照指定路径加载需要的模块
2) 参数为模块名称
require('module1')
按照module.paths中指定的路径寻找该模块
模块作为一个目录
>$ mkdir module
>$ cd module
>$ npm init/npm init -y将该目录初始化为一个node模块,产生一个package.json文件
npm ——node的模块管理机制(node package manager
npm init )
Npm是的Js开发者能够更方便的分享和复用以及更新代码,被复用的代码被称为包或者模块,一个模块中包含了一到多个js文件。在模块中一般还会包含一个package.json的文件,该文件中包含了该模块的配置信息。一个完整的项目,需要依赖很多个模块。
1.将当前目录初始化为一个node模块
$ npm init -y
$ npm install xxx
2.安装第三方模块xxx,局部安装,将第三方依赖默认安装到当前目录的node_modules中
$ npm install jquery --save(默认)
$ npm install jquery -S(默认)
--save表示将模块安装到当前目录的node_modules;将这个依赖的信息添加到package.json中dependencies属性中,dependencies中的依赖为产品依赖
-S, –save
-D, --save-dev: Package will appear in your devDependencies.
从node_modules中删除不需要的模块
$ npm uninstall -g <package_name>$ npm install babel --save-dev
devDependencies 开发依赖,只在产品开发阶段才会使用到,在产品阶段无需这些依赖
npm install xxx -g
-g 全局安装,将第三方依赖安装
$NODE_HOME/lib/node_modules
$NODE_HOME/bin
$NODE_HOME/share
详见:npm中文文档
安装babel命令行转码
作用:将es6转换为es5,但是注意一点:如果你写的js代码运行在nodejs(如:服务器,插件)上无需转换;后期运行在浏览器上做dom操作的代码需要转换。
1. 安装babel
>$ cnpm install -g babel-cli
>$ babel --version
2. 本地安装预设(当前产品目录下安装)
>$ cnpm install --save-dev babel-preset-es2015
ES2015转码规则
$ npm install --save-dev babel-preset-es2015 =>es2015
3.安装预设并且添加配置文件配置.babelrc
在当前项目的根目录下创建该文件
>$ npm install --save-dev babel-preset-es2015
{ “presets”: [ "es2015"]}
4.运行babel xxx.js
babel-polyfill 垫片
产生原因:Babel 默认只转换新的 JavaScript 句法,而不转换新的 API
1.安装垫片
$ npm install --save babel-polyfill
2.在js文件中引用并且使用
import 'babel-polyfill'; // 或者 require('babel-polyfill');
安装cnpm淘宝镜像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
报错:
EACCES: permission denied, access '/opt/node-v10.14.2/lib/node_modules/cnpm/node_modules/address'
报错原因是因为当前用户是普通用户,普通用户不允许操作非家目录
解决方案:
1) sudo
2) 将/opt/node-v10.14.2/lib/node_modules,/opt/node-v10.14.2/bin,/opt/node-v10.14.2/share 这三个目录的拥有者设置为当前用户
//$ echo $(whoami) 查看当前用户
//$ echo $(npm config get prefix) 查看操作的文件
$ sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
$ cnpm -v 查看npm版本
基础知识
* let声明
·es5中 var变量声明
1)可以重复声明 2)变量声明会被提升 3)没有局部作用域
·let变量声明
1)不可以重复声明 2)变量声明不会被提升 3)具有局部作用域
·声明常量 const
特点:1)不可以重复声明 2)变量声明不会被提升 3)具有局部作用域 4)常量的值无法改变
例:const qs =require('qs');
·解构(模式匹配):可以一次性从对象或数组中获取多个值,并把这些值赋值给不同变量
1)对象解构
let {name,age:gender} = {name:"terry",age:12}
let obj = {
realname:"terry",
address:{
province:"山西省",
city:"太原市",
area:"尖草坪"
}
}
let {realname,address:{city}} = obj;
2)数组解构
//let [a,b,c] = [8,2,5];
let [a,a1,a2,[b,b2,b3]] = [8,2,5,[12,3],4];
console.log(a,b,b3);
3)字符串解构
解构时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = ‘hello’;//a=h;b=e;c=l;d=l;e=o 对数组的属性解构
let {length : len} = ‘hello’; //len = 5
4)解构默认值
默认值(默认值生效的条件是,对象的属性值严格等于undefined)
let {name,gender="male"}={name:"terry",age:12,gender:"female"};
console.log(name,gender);
function ajax({url,method="get",data={},success}){
console.log('url',url);
console.log('method',method);
console.log('data',data);
console.log('success',success);
}
ajax({
url:"http://www.baidu.com/",
method:"post",
success:function(){
}
})
* 对象拓展~~~~
- 对象简写
·属性简写
ES6允许直接写入变量和函数,作为对象的属性和方法。这时,属性名为变量名, 属性值为变量的值。
let name = "terry",
let age = 12;
let sayName = function(){
console.log(this.name);
}
let obj = {name, age ,sayName}
=>
let obj = {name:name, age:age ,sayName:sayName}
=>
let obj = {
name:"terry",
age:12 ,
sayName:function(){
console.log(this.name);
}
}
·方法简写
var o = { method() { return "Hello!"; } };
=>
var o = { method: function() { return "Hello!"; } };
2.对象api扩展
·Object.xxx
注意:一个实例可以调用该实例构造函数原型的方法
`var o =new Object();//o为实例;
Object为构造函数;
Object.prototype为构造函数原型`
·Object.is(val1,val2)
类似于===,对比值相等
·Object.assign(target,o1,o2……)
用于对象的合并,将源对象的所有可枚举属性,复制到目标对象(target)。 Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用,而不是值的引用。
let o ={sayname(){},sayage(){}}
let b ={sayhello(){}}
Object.assign(o,b)
{ sayname: [Function: sayname],
sayage: [Function: sayage],
sayhello: [Function: sayhello] }
o
{ sayname: [Function: sayname],
sayage: [Function: sayage],
sayhello: [Function: sayhello] }
将o,b中可枚举的属性合并到target中,返回target,用于对象克隆
·Object.setPrototypeOf(obj,prototype)
为obj对象指定一个新的原型等价于 obj.__proto__= prototype
·Object.getPrototypeOf(obj)
获取obj对象的原型也就是其构造函数的原型
let o = new Object();
o.__proto__ ===Object.prototype
true
o.__proto__ ===Object.getPrototypeOf(o)
true
·Object.keys(obj)
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键名。
·Object.values(obj)
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值
·Object.entries(obj)
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。
let o = {name:"terry",age:12}
Object.keys(o)
[ 'name', 'age' ]
Object.values(o)
[ 'terry', 12 ]
Object.entries(o)
[ [ 'name', 'terry' ], [ 'age', 12 ] ]
* 函数拓展~~~~
- 函数简写
函数声明在对象中
let obj = {
sayName(){
console.log(this.name);
}
}
==>
let obj = {
sayName:function(){
console.log(this.name);
}
}
函数声明在参数中(回调函数)【箭头函数】
一般为匿名函数
注意:箭头函数this的取值为该箭头函数外部函数的this,如果没有外部函数,就指向全局对象,尽量避免var a = (item)=>{return xxx}
1)极简模式
item表示形参,xxx为返回结果(方法体中只有这一个表达式)
item=>xxx
等价于
function(item){return xxx}
let arr =[{
name:"terry",
gender:"male"
},{
name:"vicky",
gender:"female"
},{
name:"larry",
gender:"male"
}]
/*
let result = arr.filter(function(item){
return item.gender ==="male"
})*/
let result = arr.filter(item=>item.gender === "male")
//从一个数组中筛选出满足条件的值
console.log(result);
2)普通模式
当方法体中有多个表达式,方法体一定要加大括号
当形参有多个的时候,参数必须加小括号
let result = arr.filter((item,index)=>{console.log(index);
return item.gender ==='male'
})
3)this指向
let obj ={
data:{
name:"one",
list:[1,2,3,4]
},
foo(){
/*
另一种方法:回调函数的this指向global,而我们需要访问obj对象,所以提前先将obj保存到变量o中
let o = this
this.data.list.forEach(function(item){
console.log(o.data.name)
})*/
//箭头函数this指向其外部函数的this即obj
this.data.list.forEach((item)=>{
console.log(this.data.name);
})
}
}
obj.foo();
知识点:rest操作符(...),具有剥离拆分效果,可以将字符串变为数组
let s = "hello wrold"
'hello wrold'
let arr = [...s]
[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'r', 'o', 'l', 'd' ]
s.split("")
[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'r', 'o', 'l', 'd' ]
* 数组拓展~~~~
- 数组创建方式
[...string];//rest创建
new Array(3);//长度为3的数组
new Array(3,2);//数组初始化
·数组新特性
Array.from 用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)
之前讲过:类数组对象到数组的转换 Array.prototype.slice.call(array-like,0)
let Arraylike ={"0":"terry","1":"larry",length:2}//创建类数组对象
//Arraylike[0];//访问第一个元素,不可以调用push()
console.log(Arraylike);
//从数组对象中解构出slice方法
let {slice}=[];
// 原始转换方法 let array = Array.prototype.slice.call(Arraylike,0);
let array=slice.call(Arraylike,0);
//使用Array.from转换
console.log(array);
console.log(Arraylike);
console.log(Array.from(Arraylike));
let set = new Set([1,2,3,4,1,2,3,4]);
//使用Array.from转换可遍历对象
console.log(set);
console.log(Array.from(set));
//例如:字符串去重
> new Set("hello")
Set { 'h', 'e', 'l', 'o' }
> Array.from(new Set("hello"))
[ 'h', 'e', 'l', 'o' ]
> Array.from(new Set("hello")).join()
'h,e,l,o'
>[...new Set("hello")]
['h','e','l','o']
2.**Array.of(p1,p2,…)**
用于将参数中元素转换为数组,放入初始化数组
主要目的是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。
Array.of(3, 11, 8) // [3,11,8]
3.Array.prototype.includes()
该方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似
>[1, 2, 3].includes(2); // true
>[1, 2, 3].includes(4); // false
>[1, 2, NaN].includes(NaN); // true
4.Array.prototype.find()/Array.prototype.findIndex()
数组实例调用
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined 。find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。类似于filter()方法
数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
let arr=[{name:'terry',age:12},
{name:'tom',age:12},
{name:'larry',age:22},
{name:'vicky',age:22}];
~~let result = arr.find(function(item){return item.age===12})//es5方法~~
let result = arr.find(item=>item.age===12);~~~~
let result1= arr.findIndex(item=>item.age===12);
console.log(result,result1);
5. Array.prototype.fill() 用于填充数组值
> new Array(3).fill(7); // [7, 7, 7]
6.Array.prototype.keys()/values()/entries()
用于遍历数组,返回值为一个迭代器对象(通过For-of进行遍历可遍历的对象)
它们都返回一个遍历器对象(详见《Iterator》一章),可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历,返回遍历索引迭代器,entries()是对键值对的遍历,返回遍历数组key-val迭代器,values()是对键值的遍历,返回遍历数组元素迭代器,
> let arr = ['terry','larry','tom']
> arr
[ 'terry', 'larry', 'tom' ]
> for(var key in arr){console.log(arr[key])}
terry
larry
tom
undefined
> let iterator = arr .values()
> iterator
Object [Array Iterator] {}
> iterator.next()
{ value: 'terry', done: false }
> iterator.next()
{ value: 'larry', done: false }
> iterator.next()
{ value: 'tom', done: false }
> iterator.next()
{ value: undefined, done: true }
使用迭代器:
let arr =["terry","larry","tom","vicky"];
//获取迭代器
let values_iterator = arr.values();
//通过迭代器获取数组元素
let item;
while(!(item = values_iterator.next()).done){
console.log(item.value);
}
//使用for-of遍历迭代器
let entry_iterator = arr.entries();
for(let entry of entry_iterator){
console.log(entry);
}
//使用for-of遍历数组
for(let item of arr){
console.log(item);
}
//如果为for-in则返回值为索引~~~~
### 集合api
##### 1. Set
无序不可重复的集合(数组中元素可以有序重复)
它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。
1)实例化Set对象
let set = new Set();
let set = new Set([1,2,3,12,3]);
2)通过api访问,Set.prototype.xxx
**属性**
Set.prototype.size 返回Set集合中元素的个数
**方法**
add(val) 向集合中添加value
delete(val) 从集合中删除value
has(val) 判断集合中是否存在value
clear() 清空
forEach() 迭代
keys() 获取迭代器对象
values() 获取迭代器对象
entries() 获取迭代器对象
> let s = new Set(["terry","larry","tom"])
Set { 'terry', 'larry', 'tom' }
> s.keys()
[Set Iterator] { 'terry', 'larry', 'tom' }
> s.values()
[Set Iterator] { 'terry', 'larry', 'tom' }
所以,Set集合没有索引,keys()与values()返回值相等
例子如下:
s.forEach(item=>{console.log(item)})
terry
larry
tom
undefined
for(let s1 of s){console.log(s1)}
terry
larry
tom
undefined
for(let s1 of s.values()){console.log(s1)}
terry
larry
tom
undefined
for(let s1 of s.entries()){console.log(s1)}
[ 'terry', 'terry' ]
[ 'larry', 'larry' ]
[ 'tom', 'tom' ]
undefined
s.add("vicky")
Set { 'terry', 'larry', 'tom', 'vicky' }
s.delete("vicky")
true
s
Set { 'terry', 'larry', 'tom' }
s.has("tom")
true
s.clear()
Set {}
##### 2. Map
Map类似于对象,也是键值对的集合,Object 结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,对于Map而言,key值可以为任意数据对象;但对于对象而言,key值必须是字符串
1)实例化Map对象
let map = new Map();
let map = new Map([key,value],[key,value]);
如何将对象转换为Map?
let obj = {
name:"terry",
age:12
}
let map = new Map(Object.entries(obj));
console.log(map);
2)通过api访问,Map.prototype.xxx
**属性**
Set.prototype.size 返回Map中键值对个数
**方法**
set(key,value) 向map中设置键值对,key不可以重复,如果重复,value更新
get(key) 通过key获取value
has(key) 判断map集合中是否存在指定的key
delete(key) 通过key从map集合中删除
clear() 清空map集合
keys() 返回迭代器对象
values() 返回迭代器对象
entries() 返回迭代器对象
##### 3. Iterator迭代器
Iterator的作用:一是为一切可迭代的对象,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环(for…of可以迭代可迭代的对象和迭代器对象)。
iterator可以调用指针对象的next()方法,可以将指针指向数据结构的第一个成员{value:done;}
原生具备 Iterator 接口的数据结构如下:
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
iterator接口如何附着在对象上?
通过Symbol()机制产生一个不会冲突的变量,这个变量用于向对象中插入一个属性而不对对象中其他属性造成影响。s.[Symbol.iterator]();
//通过数组迭代器遍历
> let iterator_arr=arr[Symbol.iterator]()
undefined
> iterator_arr
Object [Array Iterator] {}
> iterator_arr.next()
{ value: 'terry', done: false }
> iterator_arr.next()
{ value: 'larry', done: false }
> iterator_arr.next()
{ value: undefined, done: true }
//通过字符串迭代器遍历
> let str = "hello"
undefined
> let iterator_str=str[Symbol.iterator]()
undefined
> iterator_str
Object [String Iterator] {}
> iterator_str.next()
{ value: 'h', done: false }
> iterator_str.next()
{ value: 'e', done: false }
> iterator_str.next()
{ value: 'l', done: false }
> iterator_str.next()
{ value: 'l', done: false }
> iterator_str.next()
{ value: 'o', done: false }
> iterator_str.next()
{ value: undefined, done: true }
//for-of遍历数组
>let arr = ["terry","larry","tom"]
undefined
> for(let s of arr.values()){console.log(s)}
terry
larry
tom
undefined
> for(let s of arr){console.log(s)}
terry
larry
tom
undefined
##### 4. Promise承诺对象,用于封装异步操作
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
`
<script>
//不稳定
$.get("http://134.175.100.63:6677/customer/findAll",function(result){
console.log(result);//后打印,请求发出后台运行
$.get("http://134.175.100.63:6677/order/findAll",function(result){
console.log(result);//回调函数嵌套一个异步函数,产生回调噩梦
});
});
console.log("end");//先打印
</script>
`
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 Pending 变为 Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 Pending 变为 Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。
1. 实例化一个Promise对象
let promise = new Promise(function(resolve,reject){
//包含异步操作
1)当异步操作成功的时候执行resolve(),就可以将承诺的状态由pending -> resolved
2)当异步操作失败的时候执行reject(),就可以将承诺的状态由pending -> rejected
})
当promise实例产生,这个Promise中的回调函数就会执行。通过then方法监听承诺对象状态的改变
2.Promise.prototype.then()
Promise 实例具有then方法,它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是Resolved状态的回调函数,第二个参数是Rejected状态的回调函数。
then(resolved_callback,rejected_callback)
resolved_callback 当承诺对象状态 pending -> resolved
rejected_callback 当承诺对象状态 pending -> rejected
catch(rejected_callback)
rejected_callback 当承诺对象的状态pending -> rejected
不管是ajax交互中出现的404、500异常会被catch捕获,在then中的代码语法错误也会被catch捕获
finally(callback)
不管承诺的状态最终如何,该函数中的回调函数都会执行,一般用于关闭加载状态~~~~
3.Promise.all()
用于将多个Promise实例,包装成一个新的Promise实例。即将多个承诺对象合并为一个
` let promise = Promise.all([p1,p2,p3]);`
p的状态由p1,p2,p3决定,当p1,p2,p3全部成功执行才会执行.then();只要p1,p2,p3其中一个失败,执行.catch();
4.Promise.race() 随机状态
用于将多个Promise实例,包装成一个新的Promise实例。即将多个承诺对象合并为一个
` let promise = Promise.race([p1,p2,p3]);`
p的状态由p1,p2,p3决定,只要p1,p2,p3其中一个成功,就会执行.then(),p的状态就会变为resolve,此时状态为resolve的这个承诺就会将返回结果传给p的回调函数;
p的状态取决于第一个状态改变的那个承诺状态
5.Promise.resolve()
将现有对象装换为Promise对象,当参数是一个Promise实例,Promise.resolve将不做任何修改,返回这个实例;当参数对象具有.then()方法,Promise.resolve方法会将这个对象转为Promise对象。然会立即执行.then()方法;参数是不具有.then()方法的对象或根本不是一个对象,Promise.resolve返回一个新的Promise对象,状态为resolved
`let p = Promise.resolve($_ajax);
p.then((result)=>{return result})//参数为一个ajax
`
`let obj = {
name:"terry",
then:function(){
return "thenable"
}
}
let p1 = Promise.resolve(obj);//将一个对象转化为一个Promise对象
`
6.Promise.reject()用于返回一个新的Promise实例,状态为rejcted~~~~
7.Promise.any()
接受一组Promise实例作为参数,包装成一个新的Promise实例。只要参数实例有一个编程resolve状态,包装实例就会变成resolve状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
##### 5. Generator函数 异步操作同步化(React-Redux-saga中广泛应用)
一种异步编程的解决方案,它是一个普通函数,它有两个特点:1)function关键字与函数名之间有个‘*’
2)函数体内部使用yield表达式,产生不同的内部状态,默认情况下yield返回值为undefined,yield '值';yield '函数调用';
//生成函数
function* helloGeneator(){
yield 'hello';
yield 'world';
return 'end';
}
let val = helloGenerator();//调用结果为迭代器
iterator.next();
例子如下:
function* foo(){
yield 'one';
yield 'two';
yield 'three';
return 'end';
}
let result = foo();
//"hello"[Symbol.iterator]() 迭代器生成函数=> foo();
console.log(result.next());
console.log(result.next());
console.log(result.next());
console.log(result.next());//每次获取一个迭代器
/*let item;
while(!(item=result.next()).done){
console.log(item.value);
}*/
/*for(let r of result){
console.log(r)
}*/
Generator函数应用
- 可以生成迭代器对象
let obj = {"0":"terry","1":"larry"};
=>obj[Symbol.iterator]=[][Symbol.iterator];//obj变为可迭代对象
obj[Symbol.iterator]=迭代器生成函数
Q:如何将obj转换为一个可迭代对象?
A:
let obj={"0":"terry","1":"larry","2":"tom"};
let a ="3";
obj[a]="vicky";
obj[Symbol.iterator]= function* (){
for(let k in obj){
let val = obj[k];
yield [k,val];
}
}
obj.entries = obj[Symbol.iterator];
let iterator=obj.entries();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
/*
for(let o of obj){
console.log(o);
}*/
/*
var iterator=obj[Symbol.iterator]();
iterator.next();
iterator.next();
iterator.next();
iterator.next();*/
2.利用Generator实现异步操作同步化
重要案例如下:
<script>
let $ = {
// 基于promise的异步操作的封装
get(url){
// 将异步操作封装到一个承诺对象中
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.responseType = "json";
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.send();
xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
// 承诺成功
resolve(this.response)
} else {
// 承诺失败
reject(this)
}
}
}
})
}
}
/*异步操作
$.get("http://134.175.100.63:6677/customer/findAll");
.then((response)=>{
console.log("customers:",response);
})
.catch(()=>{
alert('异常')
})
$.get("http://134.175.100.63:6677/order/findAll");
.then((response)=>{
console.log("customers:",response);
})
.catch(()=>{
alert('异常')
})*/
function* foo(){
let c_url="http://134.175.100.63:6677/customer/findAll"
let customers= yield call ($.get,c_url);
console.log("customer:",customers);
let o_url="http://134.175.100.63:6677/order/findAll"
let orders= yield call($.get,o_url);
console.log("order:",orders);
let a_url="http://134.175.100.63:6677/address/findAll"
let addresss= yield call($.get,a_url);
console.log("address:",addresss);
}
//异步函数执行器(再上一个请求结束后再去调用下一个请求;将当前请求结果作为yield表达式返回)
function call(handler,params){
handler(params)
.then((response)=>{
iterator.next(response)//参数会赋值给上个yield,也就是说,会作为上一个yield表达式返回值 耦合性强,复杂
})
}
// let iterator = foo();
// iterator.next();
//查询顾客信息,根据id查询地址信息
function* bar(){
let customers = yield call($.get,"http://134.175.100.63:6677/customer/findAll");
console.log("所有顾客:",customers);
let id =customers.data[0].id;
let address=yield call($.get,"http://134.175.100.63:6677/address/findByCustomerId?id="+id);
console.log("地址信息",id,address);
}
let iterator = bar();
iterator.next();
</script>
~~~~
可以借助第三方模块co ,调用Generator函数
##### 6. Async函数 (Generator函数的语法糖)
用于异步函数的同步化
//vuex中使用
async function foo(){
let customers = await $.get("http://134.175.100.63:6677/customer/findAll")
console.log(customers);
let id = customers.data[0].id;
let addresses = await $.get("http://134.175.100.63/address/findByCustomerId?id"+id)
return [customers,addresses];
}
let f = foo();//返回Promise对象
f.then((result)=>{console.log(result)})
##### 7.axios 基于Promise的ajax框架
即可以运行在浏览器(封装XMLHttpRequest),又可以运行在node.js(封装http)
- ajax
1)XMLHttpRequest 不可以使用任何框架完成异步请求
2)JQuery.ajax 技术站:jquery,bootstrap,easyui,Echarts……
3)axios 技术站:vue+vuex+vueRouter+element
2.原理
例如
` let $ = {
// 基于promise的异步操作的封装
get(url){
// 将异步操作封装到一个承诺对象中
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.responseType = "json";
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.send();
xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
// 承诺成功
resolve(this.response)
} else {
// 承诺失败
reject(this)
}
}
}
})
}
}
`
3.导入方式
1)模块化导入
cnpm install axios --save
2)script标签导入
<script src="https://cdn.bootcss.com/axios...;></script>
4.底层接口
axios(config){
url,
method,
data,请求体参数(post)
params,请求行参数(get)
headers,默认为json
transformRequest:[//多个匿名函数(data,headers)={
//将data转换为查询字符串,qs库
return data;
}],转变请求,在请求发送到服务器端前允许对data进行处理,一般用于编码
transformResponse:[(data)=>{
return data;
}],响应结果到达then、catch前进行处理,data为后端返回的原始数据
responseType,默认为json
baseUrl,//基路径
timeout//请求超时最大时间
} ,返回值为一个ajax承诺对象
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})序列化params为查询字符串,get参数拼接在浏览器地址栏URL后,只能为查询字符串
},
withCredentials:false,默认不携带cookie
}
let axios = require('axios');
let qs = require('qs');
//默认基路径
axios.defaults.baseURL="http://134.175.100.63:6677"
axios.defaults.headers.post["Content-Type"]="application/x-www-form-urlencoded"
axios.defaults. transformRequest=[(data)=>{return qs.stringify(data)}]
function saveCustomer(){
let data = {
realname:"张三",
telephone:"12344321"
}
axios({
url:"/customer/saveOrUpdate",
method:"post",
data,
})
.then((response)=>{console.log(response.data)})
.catch(()=>{console.log("error")})
function findAllCustomer(){
axios({
url:"/customer/findAll",
method:"get"
})
.then((response)=>{console.log("顾客信息",response.data)})
}
saveCustomer();
findAllCustomer();
5.快捷接口
axios.get(url[,config])查询
axios.post(url,data)保存
axios.delete(url[,config)删除
axios.put(url,data)修改
-
response
1)response为then回调函数中的参数,也就是axios的请求成功的结果 ,这个结果不是后台返回的结果,而是二次封装的对象.then((response)=>{})
2)response架构
{
status,
statusText,
data,
headers,
config,
request
}- axios默认配置
$.ajaxSetup(config)
axios.defaults用于保存默认配置信息,这个配置对所有axios对象产生影响
axios.daefaults.baseURL
axios.daefaults.timeout
axios.daefaults.transformRequest
axios.daefaults.transformResponse
axios.daefaults.headers.common
axios.daefaults.headers.post
axios.daefaults.headers.get
8.拦截器
//请求拦截器
axios.interceptors.request.use(function(config){
//请求前执行代码
return config;
},function(error){
return Promise.reject(error)
})
//响应拦截器
axios.interceptors.response.use(function(response){
//响应获取后执行代码
return response;
},function(error){
return Promise.reject(error)
})
//常见配置
let axios = require("axios")
let qs = require("qs")
// 配置默认基路径
axios.defaults.baseURL = "http://127.0.0.1:6677";
// axios.defaults.baseURL = "http://134.175.100.63:6677";
axios.defaults.headers.common["Content-Type"] = "application/x-www-form-urlencoded"
axios.defaults.transformRequest = [(data)=>{
return qs.stringify(data);
}]
// 拦截器
axios.interceptors.response.use(function(response){
return response;
},function(error){
// 当任何一个ajax请求出现异常的话都会打印错误信息!
console.log("error!!!");
return Promise.reject(error);
});
##### 8.Class es5中构造函数语法糖
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。 ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
类中可以直接定义方法,实际上类的所有方法都定义在类的prototype属性上面。在类的实例上面调用方法,其实就是调用原型上的方法。
|对比 |
| 构造函数 | 类 |
| `
//构造函数
function Animal(name){
this.name=name;
}
//原型
Animal.prototype.sayName=function(){
console.log("my name is",this name)
}
//继承
function Dog(name,age){
//借用构造函数继承
Animal.call(this.name)
this.age=age
}
//原型链继承
Dog.prototype = new Animal();
Dog.prototype.sayAge = function(){
console.log("my age is",this.age);
}
let d = new Dog("多多",2);
d.sayName();
d.sayAge();|
class Animal{
//构造函数
constructor(name){
this.name=name;
}
//普通函数
sayName(){
console.log("my name is",this.name);
}
}
//原型链继承
class Dog extends Animal{
//借用构造函数
constructor(name,age){
super(name);
//子类B的构造函数之中的super(),代表调用父类的构造函数。 super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。
this.age=age;
}
sayAge(){
console.log("my age is",this.age) }}let d = new Dog("多多",2);d.sayName();d.sayAge();~~~~
` |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。