介绍 ES就是JS的原名,ES6发布于2015年
let let与var的差别
let不能重复声明
1 2 3 4 5 6 7 8 9 var j = 10 ;var j = 20 ;let i = 10 ;let i = 20 ;
let有块级作用域,即使是非函数的花括号范围,使用let在其中定义的变量也只能在其中访问
1 2 3 4 5 6 7 { var ii = 19 ; let ik = 10 ; } console .log (ii);console .log (ik);
let不会预解析进行变量提升
没有声明之前先访问,var会将改变量赋值为undefind,let会报错(not defind)
let定义的全局变量不会作为window的属性
var 一个变量的时候,改变量会变为window对象的属性
let在es6中推荐使用
const 特性与let相同,除此以外
模板字符串 解决换行和字符串拼接复杂问题
以 `` 号包裹
可通过${}填入变量
注意变量需要在模板字符串之前定义并赋值,且模板字符串之后再去更改变量,模板字符串的内容并不会更新
1 2 3 4 5 let you = "ES6" ;let a = `你好 ${you} ` console .log (a)
你好 ES6
解构表达式 解构数组 1 2 3 4 5 let arr = [11 , 12 , 13 , 14 , 15 ];let [a, b, c=4 , d, e, f=16 , g] = arr;
解构对象 需要解构变量名与对象中的属性名一致
1 2 3 4 5 let person = { name :"zhangsan" , age :15 } let {name, age} = person;
连续结构赋值
1 2 3 4 5 6 7 8 9 10 11 12 let obj = { a :{ b :{ c : 1 } } } const {a :{b :{c}}} = objconsole .log (c)const {a :{b :{c :name}}} = objconsole .log (name)
形参解构 1 2 3 4 5 6 let arr = [1 ,2 ,3 ,4 ];function arrjg ([a,b,c,d,e=10 ] ){ console .log (a,b,c,d,e); } arrjg (arr);
1 2 3 4 5 6 7 8 9 let person = { name :"zhangsan" , age :15 } function objectjg ({name,age} ){ console .log (name,age); } objectjg (person);
扩展运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const arr = [1 , 2 , 3 ];const arr2 = [...arr, 4 , 5 , 6 ];const obj = { a : 1 , b : 2 ,c :{name :'zhangsan' }};const newObj = { ...obj};obj.c .name ="lisi" console .log (newObj);const newObj = { ...obj, a : 5 };console .log (newObj); const sum = (...args ) => { return args.reduce ((a, b ) => a + b, 0 ); }; const res = sum (1 , 2 , 3 , 4 );console .log (res);
箭头函数 与java中lambda几乎相同
1 2 3 4 let fun1 = function ( ){};let fun2 = ( )=>{};let fun3 = (x,y ) => x+y;let fun4 = x => console .log (x);
this问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let person = { name : "张三" , f1 :function ( ){ console .log (name); }, f2 :function ( ){ console .log (this .name ); }, f3 :()=> { console .log (name); }, f4 :()=> { console .log (this .name ); } } person.f1 ();person.f2 ();person.f3 ();person.f4 ();
箭头函数的this是其外层所处的上下文的环境中的this,如上案例中,箭头函数中的this并不是person的this,因为person只是其外层,箭头函数中的this还需要往外找person所处的上下文。
在实际测试中,在对象里包着的lambda的this都是window ,在方法中嵌套的普通方法的this为window,在方法中嵌套的箭头函数满足以上规则。
由于this传递,甚至可以一直用箭头函数嵌套传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let person = { name : "张三" , f3 :function ( ){ let f4 = ( )=>{ let f4 = ( )=>{ let f4 = ( )=>{ console .log (this .name ); }; f4 (); }; f4 (); }; f4 (); }, } person.f3 ();
rest 相当于Java中的可变参数
由于参数长度不定,可变参只能有一个且必须在最后一位
1 2 3 4 5 let f = (a,b,c,...d )=>{ console .log (a,b,c,d); } f (1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 );
spread 相当于实参用rest
就是把数组拆开后放到了参数列表中
1 2 3 4 5 6 7 8 9 10 11 12 let f = (a,b,c )=>{ console .log (a,b,c); } let arr = [1 ,2 ,3 ,4 ];f (...arr);let f = (a,b,c )=>{ console .log (a,b,c); } let arr = [1 ,2 ,3 ,4 ];f (6 ,...arr);
spread用来合并数组
1 2 3 4 5 let arr1 = [1 ,2 ,3 ];let arr2 = [4 ,5 ,6 ];let arr3 = [0 ,...arr1,3.5 ,...arr2,7 ];console .log (arr3)
spread用于合并对象
1 2 3 4 5 6 let name={name :"张三" };let age={age :10 };let gender={gender :"boy" };let person = {...name,...age,...gender};console .log (person);
面向对象的语法糖 类的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person { name; age; eat (food ){ console .log (`${this .age} 岁的${this .name} 在吃${food} ` ) } static add (a,b ){ console .log (a+b); } }
创建实例
给对象的属性赋值
实例方法的定义方式 类中实例方法有两种定义方式,一种是直接定义,一种是属性定义
直接定义的实例方法放在实例对象的原型对象上,而属性方法直接放在实例对象的上
如果将属性定义的方法改为箭头函数,则由于箭头函数的this会指向外层所在的this,故箭头函数中的this会指向实例对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Person { eat ( ){ console .log ('eat' ); } speak = function ( ){ console .log ('speak' ); } speak2 = () => { console .log ('speak2' ); } } const p = new Person ();console .log (p);
调用实例方法 在类中定义的方法被放在了类的原型对象上,供实例使用
在实例调用自身的实例方法时,实例方法中的this为当前实例
但比如使用call去调用实例方法时,可以更改方法中的this指向,下面的call方法中如果使用了this,this会指向传入的{"name":"zs"}
1 p.eat .call ({"name" :"zs" })
调用静态方法 注意无法从类的实例上调用静态方法
get和set方法 get/set + 空格 + 属性名
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person { name; get name (){ console .log ("get Name" ); return this .name ; } set name (name ){ console .log ("set Name" ); this .name = name; } }
但是在外部向对象取值或者赋值时,不会通过get或者set方法,而是会直接向属性赋值。get与set方法的触发条件为真实属性名与get后的属性名不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person { n; get name (){ console .log ("get Name" ); return this .n ; } set name (name ){ console .log ("set Name" ); this .n = name; } }
使用:
1 2 3 4 let p = new Person ();p.name = "jack" ; console .log (p.name );
虽然看似是在操作属性,但实际是在操作get与set方法:
在操作某个对象的属性时,首先拿着该属性名去对象中寻找是否有该属性,若有,则尝试直接操作属性,若没有,则寻找是否有对应的get&set方法。
private属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Person { #n; get name (){ console .log ("get Name" ); return this .#n; } set name (name ){ console .log ("set Name" ); this .#n = name; } } let p = new Person ()p.#n = "张三" p.name = "张三"
在es6中,属性名以#开头的属性为私有属性
在实际测试中,发现edge浏览器可以直接赋值,但是firefox会报错
构造器 方法名命名为constructor即可
构造器中的this为当前的实例对象
构造方法也会存放在原型链上
1 2 3 4 5 6 7 8 9 10 class Person { name; age; constructor (name, age ){ this .name = name; this .age = age; } } let p = new Person ("张三" ,15 )
继承 子类在继承父类后,子类的构造器可以不写,可以直接使用父类的构造器。
若在子类中定义了构造器,则必须调用父类的构造器,且必须在子类构造器最开始调用
其实父类就是放在了子类对象的原型链上,所以子类可以直接调用父类的方法
但是父类的属性不会直接继承到自身,可能会通过构造方法获得跟父类类似的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Person { #name; #age; constructor (name, age ){ this .#name = name; this .#age = age; } set name (name ){ this .#name=name; } get name (){ return this .#name; } set age (age ){ this .#age = age; } get age (){ return this .#age; } } class Student extends Person { #score; constructor (name,age,score ){ super (name, age); this .#score = score; } set score (score ){ this .#score = score; } get score (){ return this .#score; } good ( ){ console .log (`${this .age} 岁的${this .name} 考了${this .score} 分` ) } } let s = new Student ("李四" ,15 ,99 )s.good ();
对象拷贝 浅拷贝 就是传地址,两个变量指向一个对象
1 2 3 4 5 let arr1 = [1 ,2 ,3 ];let arr2 = arr1;let p1 = new Person ("张三" ,15 )let p2 = p1
深拷贝 可通过解构表达式
1 2 3 4 5 let arr1 = [1 ,2 ,3 ];let arr2 = [...arr1];let p1 = new Person ("张三" ,15 )let p2 = {...p1};
如过是对象,可通过json序列化和反序列化
会丢失私有属性、方法等
1 2 let p1 = new Person ("张三" ,15 )let p2 = JSON .parse (JSON .stringify (p1));
模块化 导入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import * as math from './Math.js' ;import {add,diff} from './Math.js' ;import {add as ad,diff} from './Math.js' ;import {add, add as ad,diff} from './Math.js' ;import * as math from './Math.js' ;math.default or math.default () import {default as add} from './Math.js' ;import add from './Math.js' ;
html以模块的方式引入js文件
1 <script src ="" type ="module" > </script >
分别导出 在想要暴露的属性之前添加export关键字
1 2 export function add ( ){};export class Person {};
统一导出 1 2 3 function add ( ){};class Person {};export {add,Person }
默认导出 指定引入某个js文件时默认引入的对象,默认导出只能有一个
1 2 class Person {};export default Person
动态对象属性key 1 2 3 4 5 6 7 8 9 const user = { username : "john" , password : "password" } const key = "username" user[key] = "jane" const newUser = {[key]:"zs" }console .log (user)console .log (newUser)
函数柯里化 一个函数的返回值是一个函数
promise 回调函数
回调函数是基于事件的自动调用函数,其他的代码不会等待回调函数执行完毕才向下走,所以回调函数的执行是异步的。
回调函数是一种未来会执行的函数,回调函数以外的其他代码不会等这个函数的执行结果就会执行下去
回调函数相当于一种”承诺“,其从提出后有三种状态
针对承诺的三种状态要执行三种预案
什么是promise promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更加强大,ES6原生提供了Promise对象。Promise类似于一个容器,其中保存着某个未来才会结束的事件(通常是一个异步操作)的结果
有三种状态:
Pending 进行中
Resolved 已完成
Rejected 已失败
只有其异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
一旦状态改变就不会再改变。任何时候都可以得到这个结果,Promise的对象状态的改变,只有两种可能:Pending变为Resolved,或者从Pending变为Rejected,只要这两种情况发生,状态就凝固了,不会再改变了
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 let promise = new Promise (function ( ){});let promise = new Promise (function (resolve,reject ){});promise.then ( function ( ){ console .log (resolve); } ,function ( ){ console .log (reject); } ) let promise = new Promise (function (resolve,reject ){ resolve ("success" ); reject ("fail" ); }); promise.then ( function (value ){ console .log (value); } ,function (value ){ console .log (value); } ) let promise2 = promise.then ( function (value ){ console .log (value); } ) promise2.catch (function ( ){}) promise.then ( function (value ){ console .log (value); } ).catch (function (value ){ console .log (value); })
中断then链 返回一个pending状态的promise用于终端then链处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 fetch ('www.baidu.com' ).then ( response => { console .log ('这一步只能证明连接服务器成功了' ); return response.json (); }, error => { console .log ('连接服务器失败' , error); return new Promise (() => {}); } ).then ( response => { console .log ('服务器返回的数据' , response); }, error => { console .log ('服务器返回错误' , error); } )
async 1 2 3 4 5 async function a ( ){ } let a = async ( )=>{}
async 所标识的函数会被封装为返回结果是一个pomise对象的函数,async标识函数的方法体则是Promise对象声明时所接收的那个回调函数。
如果在a函数中返回结果,则该promise的状态会变为Resolved,返回的结果会放入resolve的参数中,
如果在a函数中抛出异常,则该promise的状态会变为Rejected,异常信息放入reject的参数中。
如果a函数return了一个promise对象,则该promise就是这个promise
1 2 let promise = a ();promise.then ().catch ()
await 用于快速获取promise对象在成功状态下的返回值,只能在async修饰的方法中使用
如果await操作的promise返回的是异常,则await操作会抛出异常
与await在同一个方法体中且在await后的代码会等待await执行结束
1 2 let res = await Promise .resolve (obj)
1 2 3 4 5 6 7 8 async function p ( ){ return 0 ; } async function fun ( ){ let res = await p (); console .log (res); } fun ()
使用await只能获取成功后的结果数据,那如何处理失败呢?答案是使用trycatch
1 2 3 4 5 6 7 8 9 async a ( ) { try { const response = await fetch ("www.baidu.com" ); const data = await response.json (); console .log (data); } catch (e) { console .log (e); } }
fetch 兼容性不高,老版本浏览器有不兼容,与xhr无关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 fetch ('www.baidu.com' ).then ( response => { console .log ('这一步只能证明连接服务器成功了' ); return response.json (); }, error => { console .log ('连接服务器失败' , error); return new Promise (() => {}); } ).then ( response => { console .log ('服务器返回的数据' , response); }, error => { console .log ('服务器返回错误' , error); } ) fetch ('www.baidu.com' ).then ( response => { console .log ('这一步只能证明连接服务器成功了' ); return response.json (); } ).then ( response => { console .log ('服务器返回的数据' , response); } ).catch ( error => { console .log ('服务器连接失败' , error); } );
Axios 用于发送请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <script setup> import { ref } from "vue"; import axios from "axios"; let msg = ref(""); function getMsg() { // 方法返回一个promise对象 axios({ // url url: "https://api.uomg.com/api/rand.qinghua?format=json", // method method: "get", // params会以键值对形式拼接到url后, params: {}, // data 会以json形式放入请求体 data: {} }) .then((response) => { /** * response的结构 * { * data:服务端响应的数据,如果是个json数据,会自动转为对象 * status:响应状态码 * statusText:响应描述 * headers:响应头 * config:本次请求的配置信息 * request:本次请求的XMLHttpRequest属性 * } */ console.log(response); console.log(response.data.content) msg.value = response.data.content; }) .catch((e) => { console.log(e); }); } </script> <template> <div> <h1>{{ msg }}</h1> <button @click="getMsg">变</button> </div> </template> <style scoped> </style>
Object.assign(a,b)
可将b中的属性赋予a对象,若a对象中已有,则覆盖,没有则创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <script setup> import { ref, reactive } from "vue"; import axios from "axios"; let data = reactive({}); function getMsg() { // 方法返回一个promise对象 axios({ // url url: "https://api.uomg.com/api/rand.qinghua?format=json", // method method: "get", // params会以键值对形式拼接到url后, params: {}, // data 会以json形式放入请求体 data: {} }) .then((response) => { /** * response的结构 * { * data:服务端响应的数据,如果是个json数据,会自动转为对象 * status:响应状态码 * statusText:响应描述 * headers:响应头 * config:本次请求的配置信息 * request:本次请求的XMLHttpRequest属性 * } */ console.log(response); console.log(response.data.content) Object.assign(data,response.data) }) .catch((e) => { console.log(e); }); } </script> <template> <div> <h1>{{ data.content }}</h1> <button @click="getMsg">变</button> </div> </template> <style scoped> </style>
简写 由于await后的代码会等待await执行结束,则若在提交按钮绑定的方法中使用await获取数据,通过获取到的数据来判断当前方法应该返回的值是可行的,因为return会等待await的执行结果
get
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <script setup> import { ref, reactive } from "vue"; import axios from "axios"; let showData = reactive({}); async function getMsg(){ // axios.get(url,{params,headers}) let promise = axios.get("https://api.uomg.com/api/rand.qinghua?format=json",{ params:{ name:"zs" } }) let {data} = await promise; Object.assign(showData,data) } </script> <template> <div> <h1>{{ showData.content }}</h1> <button @click="getMsg">变</button> </div> </template> <style scoped> </style>
post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <script setup> import { ref, reactive } from "vue"; import axios from "axios"; let showData = reactive({}); async function getMsg() { // axios.get(url,{params,headers}) let promise = axios.post( "https://api.uomg.com/api/rand.qinghua?format=json", // 这个对象是请求体 { username: "zs", password: "123456", }, { params: { name: "zs", }, } ); let { data } = await promise; Object.assign(showData, data); } </script> <template> <div> <h1>{{ showData.content }}</h1> <button @click="getMsg">变</button> </div> </template> <style scoped> </style>
拦截器 axios可通过creat方法生成一个实例,该实例有着与axios相似的方法调用,可在某具体js中生成该实例并将该实例暴露,且在js文件中给该实例添加拦截器,以下示例并没有单独抽离实例js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <script setup> import { ref, reactive } from "vue"; import axios from "axios"; let showData = reactive({}); async function getMsg() { // axios.get(url,{params,headers}) /** * baseURL 使用该实例发送的请求之前会拼接baseURL * timeout 请求超时时间,毫秒单位 */ let axiosins = axios.create({ baseURL: "https://api.uomg.com", timeout: 10000, }); // 设置请求拦截器,两个函数 axiosins.interceptors.request.use( config => { // 设置请求的信息,比如请求头、体等,最后需要返回这个config // config.headers.Accept="application/json,123" return config; }, error => { // 请求错误拦截,需要返回一个失败的promise return Promise.reject(error) } ); // 设置响应拦截器,两个函数 axiosins.interceptors.response.use( response => { // 响应状态码为200时执行,response需要返回,否则没有响应 console.log(123) return response }, error => { // 其他状态码执行, 最后需要返回一个失败的promise console.log(error) return Promise.reject(error) } ); let promise = axiosins.get("/api/rand.qinghua?format=json", { params: { name: "zs", }, }); let { data } = await promise; Object.assign(showData, data); } </script> <template> <div> <h1>{{ showData.content }}</h1> <button @click="getMsg">变</button> </div> </template> <style scoped> </style>
跨域 原因,浏览器当前请求的视图中的某个目标指向的地址与视图的地址不在同一个域。
方法一:前端服务器发请求
方法二:先发送预检请求,用于检查目标服务器是否安全
前端先发送一个option的预检请求(自动发送)
后端新增一个过滤器,如果收到的请求是预检请求,则拦截处理,正常请求则放行。在预检请求的响应头中设置是否允许跨域等的信息。