ES6
let和const命令
let
块级作用域
变量作用域不会提前声明
相同作用域内不能重复声明同一个变量
for循环中的父子作用域const(内存地址不变,所以是常量)
与let的作用域相同
const一单声明常量就立即被初始化。
只声明不赋值也会报错
注意
const一般用在定义模块中的常量
let限制了变量的作用域,保证变量不去影响全局变量,所以尽量用let代替var
变量的解构赋值
数组的解构赋值
1 | //传统赋值 |
这种写法属于模式匹配,只要等号左右的模式相同,就会对号入座
对象的解构赋值
数组的元素是按次序排列的,变量的取值由特德位置决定的,而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
1
2
3 let {bar,foo}={foo:"123",bar:"222222"};
console.log(bar) //123
console.log(foo) //222222
如果变量名和属性名不一致就应该这样书写(类似重命名属性)
1
2
3
4
5
6
7
8
9
10
11
12 let obj = {less01:"00001",less02:"00002"};
console.log(obj) //{ less01: '00001', less02: '00002' }
let {less01:l1,less02:l2}=obj
console.log(l1) //00001
console.log(l2) //00002
//简写如下形式
let {rightNumber:R,leftNumber:L}=
{rightNumber:"r00001",leftNumber:"l00001"};
console.log(R)
console.log(L)
经验:对象的解构赋值的内部机制,是先找到同名属性 再赋给对应的变量 真正被赋值的是后者,而不是前者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 // 示例:
let {foo:baz}={foo:"aaa",bar:"bbb"};
console.log(baz); //aaa
console.log(foo) //foo is not defined
foo是匹配的模式
baz才是变量,真正被赋值的是变量baz,而不是模式foo
//对象的结构也可以使用默认值
let {x:y=1234}={};
console.log(y) //1234
let {x:y=1234}={x:5678};
console.log(y) //5678
上机训练
箭头函数
箭头函数起因
1 | //setInterval函数是在全局作用域window下执行的,window上找不到属性username和age |
箭头函数的定义
箭头函数和普通函数相比的优势
- 不绑定this和arguments
- 更简洁的代码语法
说明:不绑定this1
2
3
4
5
6
7
8
9
10
11//箭头函数的this在定义的时候就已经确定了,之后不管什么时候调用,this都是之前定义时的this,
function Person(name,age){
this.name=name;
this.age=age;
setInterval(()=>{
console.log(`我的名字叫${this.name}我今年${this.age}岁`)
},3000)
}
let p=new Person('chenhang',20);
说明:不绑定arguments1
2
3
4
5//所以在箭头函数中不能直接使用arguments对象,
//如果需要获得函的参数又该怎么办呢?可以使用余参数来取代arguments
let func=(...args)=>console.log(args.length);
func(1,2,3,4,5,6) // 显示打印 6
箭头函数不适应的场景
对象的方法中不建议使用箭头函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const Person={
username:"陈子",
age:20,
say:()=>{
console.log('111') //111
setInterval(()=>{
console.log(this.username+'----'+this.age)
},2000) //undefined----undefined
}
}
Person.say()
/*
输出结果有问题,因为方法 在了对象里,而对象的括号是不能封闭作用域的,所
以此时的 this 还是指向全局对象,而全局对象下没有 usemame age 属性,所以会出现
问题
*/不能作为构造函数
1
2
3
4/*
由于箭头函数的 this 具有不绑定的特点,不能使用箭头函数作为构造函数,如果这
样做了,也会报错。
*/定义原型方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Student(){
this.username="成成"
}
Student.prototype.sayName=()=>{
console.log(this.username) //报undefined
}
var p=new Student();
p.sayName()
/*
出现问题的原因是 his 指向 window 象,这和使用箭头函数在对象中定义方法十
分类似
*/
Map数据结构
js中的对象是键值对形式的集合(Hash结构),键只能是字符串类型
对象提供了’字符串-值’,Map提供了’值-值’的对应
创建Map
- Map 可以接受 个数组作为参数,该数组的成员是 个个表示键值对的数组
1
2
3
4
5const MapTree=new Map([
['name','chenhang'],
['age',20]
]);
console.log(MapTree) // { 'name' => 'chenhang', 'age' => 20 }
Map常用的属性和方法
size返回Map的成员总数
1
console.log(MapTree.size) //2
set 方法设置键名 key 对应的键值为 value ,然后返回整个 Map 结构。
- 如果 key有对应的键值,则键值会被更新,否则就新生成键值。
- set方法返回的是当前的 Map对象 因此可以采用链式写法。
1 | MapTree.set('address',"上海市闵行区").set('sex','男'); |
has方法 放回一个布尔值判断某个键是否在当前的Map对象中
1
2console.log(MapTree.has('sex')) //true
console.log(MapTree.has('sex2')) //falsedelete方法 删除键成功返true,删除失败返回false
1
2
3console.log(MapTree.delete("address")) //true
console.log(MapTree)
//Map { 'name' => 'chenhang', 'age' => 20, 'sex' => '男' }遍历方法
Map结构提供三个遍历器生成函数和一个遍历方法
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// keys() 返回所有键的遍历器
const a=MapTree.keys();
console.log(a) //MapIterator { 'name', 'age', 'sex' }
for(let key of MapTree.keys()){
console.log(key+"----这是key")
}
// values() 返回所有值的遍历器
const b=MapTree.values();
console.log(b) //MapIterator { 'chenhang', 20, '男' }
for(let value of MapTree.values()){
console.log(value+"----这是value")
}
//entries() 返回所有成员的遍历器
const c=MapTree.entries();
console.log(c) //MapIterator { [ 'name', 'chenhang' ], [ 'age', 20 ], [ 'sex', '男' ] }
for (let [key,value] of MapTree.entries()){
console.log(key,value)
}
/*
name chenhang
age 20
sex 男
*/
// forEach() 遍历Map所有的成员
MapTree.forEach((value,index)=>{
console.log(value+'--'+index);
})
/*
chenhang--name
20--age
男--sex
*/
Module语法
es6之前社区使用CommonJS规范(服务器端)和AMD规范(浏览器端),
ES6 模块的设计思想是尽量静态化,使得编译时就能确定模块的依赖关系,以及输
入和输出的变量。
export
1 | //第1种写法 |
import
1 | //main.js |
export default
使用 import 命令时,用户需要知道所要加载的变量名或函数名,否则将无法加载
1
2
3
4
5
6
7 // export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customName from './export-default
customName(); //foo
import 可以为匿名函数指定任意名字
,这时就不需要知道
原模块输出的函数名。需要注意的是,这时 import 令后面不使用大括号。
使用 export default 时,对 import
语句不需要使用大括号:不使用 export default 时,对应的 import 语句需要使用大括号。
export default 令用于指定模块的默认输出。显然 模块只能有 个默认输出,因此
expo default 令只能使用 所以 import 命令后面才不用加大括号,因为只能唯
对应 export default 命令
Promise对象
1 | const promise=new Promise(function(resolve,reject){ |
项目的路由配置
在 HTML5 history
API 出现之前,前端路由都通过 hash 实现, hash 能够兼容低版本的浏览器 如果把
节的 阳例子用 hash 来实现的话,它的 URI 规则中需要带上呀”。
什么是前端路由
1 | /* |
前端路由的使用场景
1 | 主要适用于单页面,spa基本是前后端分离,所以后端不会提供路由 |
前端路由优缺点
1 | 优点 |
Vue-Router的使用
1.安装路由1
2
3
4
5
6
7
8
9
10cnpm install vue-router --save
//index.js
import Vue from 'vue';
import VueRouter from 'vue-router'
Vue.use(VueRouter);
// main.js
import router from "./router"
2.建立路由器模块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// index.js
import Vue from 'vue';
import VueRouter from 'vue-router'
import Login from "@/components/Login"
import Home from "@/components/Home"
Vue.use(VueRouter);
export default new VueRouter({
routes:[
{
path:"/home",
name:"Home",
component:Home,
},{
path:"/login",
name:"Login",
component:Login
}
//.....
]
})
3.启动路由器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/*
在main.js入口文件中启用路由器,创建和挂载根实例,通过
router配置参数注入路由,从而让整个应用都有路由功能
*/
import Vue from "vue";
import App from "./App";
import router from "./router/index.js"
new Vue({
el:"#app",
router,
template:"<App/>",
components:{App}
})
// App.vue中对用的router-view会渲染
4.路由重定向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
34export default new VueRouter({
routes:[
{
path:"/",
redirect:"/home"
}
]
})
//重定向的目标也可以是一个命名的路由
export default new VueRouter({
routes:[
{
path:"/",
redirect:{name:'home'}
}
]
})
//重定向的目标甚至可以是一个方法,动态的返回重定向的目标
export default new VueRouter({
routes:[
{
path:"/",
redirect:to=>{
//方法接收“目标路由”作为参数
return //重定向的“字符串路径/路径对象”
}
}
]
})
5.路由懒加载
结合 Vue 的异步组件和 Webpack 的代码分割功能,可以轻松实现路由组件的懒加载
6.router-link1
2
3
4
5
6
7
8
9
10
11
12
13
14
<router-link :to="home">Home</route-link>
<!-- 同上--->
<router-link :to="{path:'home'}">HOme</router-link>
<!-- 命名的路由--->
<routet-link :to="{name:'user',params:{userID:123}}">User</router-link>
<!--带参数的查询--->
<router-link :to="{name:'register',query:{plan:'private'}}">Register</router-link>
<!--结果为/register?plan=private-->
7.路由的对象属性
$router.path
字符串,对应当前路由的路径 总是解析为绝对路径,如“/foo/bar “
$router.params
一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数 就为空对象
$router.query
一个key/value对象,表示url的查询参数,/foo?id=1 表示$router.query.id==1,如果没有查询参数就为空对象
- $router.hash
当前路由的hash值(不带#),如果没有hash值则为空字符串
- $router.fullPath
完成解析后的 URL ,包含查询参数 hash 完整路径
- $router.matched
一个数组,包含当前路由的所有嵌套路径片段的路由记录
页面之间的导航
借助router实例的一些方法实现编程路由
$router.push
1 | //参数可以是字符串路径 |
$router.replace
1 | /* |
$router.go
1 | this.$router.go(1) ==> history.forward() |
Vue.js 知识点
特点
解耦视图和数据
前端路由
可复用的组件
状态管理
Virtual DOM
MVVM特点
- 低耦合
- 可重用视图逻辑
- 独立开发 专注于业务逻辑和数据的开发
Vue实例的生命周期
实例对象从构造函数时开始执行(被创建)到被GC回收销毁的整个存在的时期,在生命周期中被自动调用的函数称之为生命周期函数,也形象的称之为生命周期钩子函数
生命周期函数 | 含义 |
---|---|
beforeCreate(创建前) | 组件实例刚被创建,组件属性计算之前 比如data属性 |
created (创建后) | 组件实例刚刚创建完成,属性已经绑定,此时DOM尚未生成,$el属性还不存在 |
beforeMount(载入前) | 模板编译、挂载之前 |
mounted(挂载后) | 模板编译、挂载之后 |
beforeUpdate(更新前) | 组件更新之前 |
updated(更新后) | 组件更新之后 |
beforeDestroy(销毁前) | 组件销毁前调用 |
destroyed(销毁后) | 组件销毁后调用 |
beforeCreate在组件刚刚被创建的时候增加一些loading事件
created调用时结束loading事件,完成一些初始化,实现函数自执行等
mounted是比较重要的函数,可以发起后端请求数据,接受页面之间传递的参数,由子组件向父组件传递参数等
class和style的绑定
当:class的表达式过长或逻辑复杂的时候,可以绑定一个计算属性,这是一种很友好和常见的做法
- 对象语法
1
2
3
4
5
6
7 <div :class="{active:isActive,....}"></div>
data(){
return{
isActive:true
}
}
数组语法
1
2
3
4
5
6
7
8<div :class="[activeClass,errorClass]"></div>
data(){
return{
activeClass:"active",
errorClass:"static"
}
}绑定内联样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<div :style="{border:activeColor,fontSize:fontSize+'px'}"></div>
data(){
return{
activeColor:"1px solid #ffc",
fontSize:22
}
}
//实际开发中写在data或者计算属性中
<div :style="styleList"></div>
data(){
return{
styleList:{
border:"1px solid #fff",
fontSize:22+"px"
}
}
}
项目中与服务端通信
1.connect-mock-middleware工具的使用
config中的index.js中添加middleware,实际项目会换成后台提供的地址
1
2
3
4
5
6
7proxyTable:{
"/api":{
target:"http://127.0.0.1:3721",
changeOrigin:true,
secure:false
}
}写mock文件
1
2
3
4
5
6
7/*
mock文件支持两种请求
1.get/api/xxx
2.post/api/<id>/123
<id>代表路由链接表达式 如/api/:id/123 id的值会发生变化
*/
2.Mock.js语法
- 优点
- 根据数据模板生成模拟数据
- 模拟Ajax请求返回模拟数据
- 基于html模板生成模拟数据
- 语法规范
数据模板定义规范 (Data Template Definition—– DTD)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/*
属性名 name
生成规则 rule
属性值 value
'name|rule':value
rule包括七种格式
'name|min-max'
'name|count'
'name|min-max.dmin-dmax'
'name|min-max.dcount'
'name|count.dmin-dmax'
'name|count.dcount'
'name|+step'
生成规则是可选的
*/数据占位符定义规范(Data Placeholder Definition —–DPD)
3.snail mock工具的使用
- 上面定义好了模拟的后台数据,现在需要通过生成的url来调用这些数据,snail mock可以模拟服务器的功能。生成的url
安装 cnpm isntall snail-cline -g
开启mock服务(在项目目录下打开cmd执行 ‘snail mock’ 命令会看到之前配置好的api地址)
1 | 经验:本地全局安装了snail-cline 其内部实现依赖很多其他的包,打开本地的package.json, |
4.Axios安装和配置
项目服务端通信配置
1 |