小实训面试题(2020/11/24)
- 1.为何组件的data必须是一个函数
- 2、vue常用指令:
- 3.v-if与v-show的区别
- 4.Vue生命周期的执行过程(极简版)
- 5.vue数据双向绑定原理。
- 6.Vue Virtual Dom 和 Diff原理(极简版)
- 7.什么是vuex
- 8.vue中Computed、Methods、Watch区别
- 9.MVC和MVVM的区别
- 10.vue组件封装
- 11.vue自定义指令
- 12.vue自定义指令的应用场景:
- 13.vue自定义过滤器filter
- 14.vue-Router实现原理
- 15.vue脚手架本地开发跨域请求设置。
- 16.keep-alive是什么?
- 17.1.slot
- 18.vue中的prop验证
- 19.Vue.js中this.$nextTick()的使用
- 20.vue3.0 与 vue2.0 的区别
- 21.vue中的provide和inject
- 22.vue中mixins(混入)的使用
- 23.vue项目如何部署到nginx服务器
- 24.渐进式框架的理解
- 25.兄弟组件如何通信
- 26.params和query的区别?
- 27.git的指令:
- 28.ES6
- 29.3.JavaScript中let、const、var 的区别
- 30.4.async、await
- 31.5.es6中的Generator函数详解
- 32.6.什么是Promise?
- 33.原型和原型链
- 34.vue 组件父子,子父,兄弟通信
- 35.21、 es6 有哪些拓展
- 36.什么是深拷贝,浅拷贝,如何实现
1.为何组件的data必须是一个函数
首先定义的 xx.vue文件在编译之后是一个类,每个地方使用这个组件的时候,相当于对这个类实例化,在实例化的时候执行data,如果不是一个函数的话,每个组件的实例的data都是同一个引用数据,当该组件作为公共组件共享使用,一个地方的data更改,所有的data一起改变。如果data是一个函数,每个实例的data都在闭包当中,就不会各自影响了。
2、vue常用指令:
v-model
多用于表单元素实现双向数据绑定
v-for
格式: v-for="(item,index) in/of 数组json"
循环数组或json
v-show
显示内容 ,通过display=block/none来控制元素隐藏出现
v-hide
隐藏内容 同上
v-if
显示与隐藏(dom元素的删除添加 同angular中的ng-if 默认值为false)
v-else-if
必须和v-if连用
v-else
必须和v-if连用 不能单独使用 否则报错 模板编译错误
v-bind
动态绑定 作用: 及时对页面的数据进行更改
v-on:click
给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面
v-text
解析文本
v-html
解析html标签
v-bind:class
三种绑定方法 1、对象型 ‘{red:isred}
’ 2、三元型 ‘isred?“red”:“blue”
’ 3、数组型 ‘[{red:“isred”},{blue:“isblue”}]
’
v-once
进入页面时 只渲染一次 不在进行渲染
v-cloak
防止闪烁 该属性需配合 样式使用。
v-pre
把标签内部的元素原位输出
3.v-if与v-show的区别
相同点:都可以动态控制着dom元素的显示隐藏
区别:
v-if
: 控制DOM元素的显示隐藏是将DOM元素整个添加或删除;
v-show
: 控制DOM 的显示隐藏是为DOM元素添加css的样式display,设置none或者是block,DOM元素是还存在的.
性能对比: v-if
有更高的切换消耗;
v-show
有更高的初始渲染消耗
使用场景:v-if
适合运营条件不大可能改变的场景下;
v-show
适合频繁切换;
4.Vue生命周期的执行过程(极简版)
简单粗暴的答案直接走起:
答: 总共分为8个阶段。创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated
阶段,vue实例的挂载元素
e
l
和
数
据
对
象
d
a
t
a
都
为
u
n
d
e
f
i
n
e
d
,
还
未
初
始
化
。
在
‘
c
r
e
a
t
e
d
‘
阶
段
,
v
u
e
实
例
的
数
据
对
象
d
a
t
a
有
了
,
el和数据对象 data 都为undefined,还未初始化。在`created`阶段,vue实例的数据对象data有了,
el和数据对象data都为undefined,还未初始化。在‘created‘阶段,vue实例的数据对象data有了,el还没有。
载入前/后: 在beforeMount
阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后: 当data变化时,会触发beforeUpdate
和updated
方法。
销毁前/后: 在destroy
阶段,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。destroyed
阶段,组件销毁
5.vue数据双向绑定原理。
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
6.Vue Virtual Dom 和 Diff原理(极简版)
先说Virtual Dom:用js来模拟DOM中的节点。传说中的虚拟DOM。
Diff:diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
普通话:diff的过程就是调用名为patch
的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
7.什么是vuex
vuex 是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态
五个属性: state
、getters
、mutations
、actions
、module
基本使用:
新建store.js文件,最后在main.js中引入,并挂载到实列上.
state
属性: 存放状态,例如你要存放的数据
getters
: 类似于共享属性,可以通过this.$store.getters
来获取存放在- state
里面的数据
mutations
: 唯一能改变state
的状态就是通过提交mutations
来改变,this.$store.commit()
actions
: 一步的mutations
,可以通过dispatch
来分发从而改变state
.
数据持久化:
vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage
或者sessionStorage
里面,进入页面时判断是否丢失,丢失再去localStorage
或者sessionStorage
里面取;
在app.vue根组件的created
里面判断是否丢失,在进行上面的操作;
vuex-persistedstate 插件
8.vue中Computed、Methods、Watch区别
computed
属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;methods
方法表示一个具体的操作,主要书写业务逻辑;watch
一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computed
和methods
的结合体;
9.MVC和MVVM的区别
MVVM:
MVVM是 Model-View-ViewModel 的缩写,分别对应着:数据,视图,视图模型。Model是我们应用中的数据模型,View是我们的UI视图层,通过ViewModle,可以把我们Modle中的数据映射到View视图上,同时,在View层修改了一些数据,也会反应更新我们的Modle。简单理解就是双向数据绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。
MVC:
View
:视图层;
Model
:业务数据层;
Controller
: 控制器。接收View层传递过来的指令,选取Model层对应的数据,进行相应操作。
特点:MVC有如下两种模式,不管哪种模式,MVC的通信都是单向的,由图也可以看出,View层会从Model层拿数据,因此MVC中的View层和Model层还是存在耦合的。
10.vue组件封装
答: 我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views
目录和一个commen
目录和一个feature
目录,views
目录中放页面级的组件,commen
中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature
目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend
方法创建一个组件,然后使用Vue.component
方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import
导入,并在components
中注册,子组件需要数据,可以在props
中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用$emit
方法。
11.vue自定义指令
自定义指令分为:全局自定义指令,局部自定义指令。
使用Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令
参数1 :指令的名称
参数2: 是一个对象,这个对象身上,有钩子函数.
钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind
:只调用一次,指令与元素解绑时调用。
12.vue自定义指令的应用场景:
使用自定义指令背景:
代码复用和抽象的主要形式是组件。
当需要对普通 DOM 元素进行底层操作,此时就会用到自定义指令
但是,对于大幅度的 DOM 变动,还是应该使用组件
常用案例:
- 输入框自动聚焦
- 下拉菜单
点击下拉菜单本身不会隐藏菜单
点击下拉菜单以外的区域隐藏菜单
- 相对时间转换
类似微博、朋友圈发布动态后的相对时间,比如刚刚、两分钟前 等等
13.vue自定义过滤器filter
过滤器就是一个数据经过了这个过滤器之后出来另一样东西。
vue中的过滤器分为两种:局部过滤器和全局过滤器。
全局过滤器:
{{ oldValue | global-filter }}
把 oldValue
的值原封不动的传递给 global-filter
在 global-filter
方法定义里,第一个参数 val
就是oldValue
。
局部过滤器(组件过滤器):
全局过滤器通过 Vue.filter('filtername',fliterFn)
来定义,它定义好了之后,在所有的组件内都可以使用.
局部过滤器,定义在组件内部 filters
属性上.它只能在此组件内部使用.
14.vue-Router实现原理
- 前端路由概念
通过改变 URL,在不重新请求页面的情况下,更新页面视图。 - vue-Router两种模式
更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式:
Hash
— 默认值,利用 URL 中的hash("#")
、
history
– 利用URL中的路径(/home
- HashHistory
hash("#")
的作用是加载 URL 中指示网页中的位置。#
号后面的hash
值,可通过window.location.hash
获取 - 特点:
hash
不会被包括在http
请求中,,对服务器端完全无用,因此,改变hash
不会重新加载页面。
可以为hash
的改变添加监听事件:window.addEventListener("hashchange",funcRef,false)
每一次改变hash(window.localtion.hash)
,都会在浏览器访问历史中增加一个记录。
利用hash
的以上特点,就可以来实现前端路由"更新视图但不重新请求页面"的功能了。
HashHistory
拥有两个方法,一个是push
, 一个是replace
- 两种模式比较
pushState
设置的新URL可以是与当前URL同源的任意URL;而hash
只可修改#
后面的部分,故只可设置与当前同文档的URL
pushState
通过stateObject
可以添加任意类型的数据到记录中;而hash只可添加短字符串
pushState
可额外设置title
属性供后续使用
history
模式则会将URL修改得就和正常请求后端的URL一样,如后端没有配置对应/user/id
的路由处理,则会返回404错误
15.vue脚手架本地开发跨域请求设置。
vue脚手架配置
在根目录创建vue.config.js
在module.exports
中配置devserver
的内容
devServer: {
host:'0.0.0.0',
port: 8080,//端口号
open: true,//运行项目自启
proxy:{
'/api':{
target:'http://localhost:3000/',//跨域请求资源地址
ws:false,//是否启用websockets
changeOrigin:true,//开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
pathRewrite:{
'^/api':''//注册全局路径
因为顺手注册了全局路径,取资源就可以使用/api,例如:
this.$ajax.get(/api/personalized?limit=6,{})
16.keep-alive是什么?
keep-alive
是Vue提供给我们一个内置组件,他可以用来保存我们路由切换时组件的状态
组件使用keep-alive
以后会新增两个生命周期 actived()
deactived()
,
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive
保存列表页面的滚动位置。
怎么使用keep-alive
,有两种方式,1. 路由配置 2. keep-alive
参数
- 全局保存在App.vue中
<keep-alive>
把<routerView/>
包裹起来 - 路由定义方式
- router.js中设置要缓存的页面
{
path: '/child1',
name: 'Child1',
component: Child1,
meta:{
keepAlive:true,//保存keep-alive状态
}
} ```
2. 用`v-if`来显示`router-view`是否在`keep-alive`中出现
````javascript
<keep-alive>
<router-view v-if="$route.meta.keepAliv"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
- 使用
keep-alive
的标签属性,include()
、exclude()
javascript<keep-alive inclue="list,detail" ></keep-alive>
include
包含标签名字被缓存exclude
包含的标签不被缓存
缓存名字组件中有个name
属性进行定义即可
17.1.slot
基本用法:
插槽指允许将自定义的组件像普通标签一样插入内容
2. 具名插槽
给具体的插槽命名,并在使用的时候传入插槽的名称
3. 作用域插槽
将定义插槽的变量作用域到使用插槽中
vue2.6以后对具名插槽和作用域插槽做了修改,但任然没有废弃之前语法
- 具名插槽 (2.6以后)
有时候我们希望在指定的位置输出我们的子元素,这时候具名插槽就排上了用场。 - 作用域插槽 (vue2.6以后)
作用域插槽的主要作用是在书写插槽内容时可以获取到插槽作用域的值。
总结:
v-slot
的出现是为了代替原有的slot
和slot-scope
简化了一些复杂的语法。
一句话概括就是v-slot
后边是插槽名称,=后边是组件内部绑定作用域值的映射。
18.vue中的prop验证
prop
验证,和默认值
所有的prop
都使得其父子prop
之间形成了一个单向下行绑定:父级prop
的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的prop
都将会刷新为最新的值
19.Vue.js中this.$nextTick()的使用
官方解释:将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。它跟全局方法Vue.nextTick
一样,不同的是回调的this
自动绑定到调用它的实例上。
新闻滚动列表中的this.$nextTick()
放哪里?
因为数据是根据请求之后获取的,所以应该放到请求的回调函数里面。
注意
this.nextTick()
this.nextTick(callback)
,当数据发生变化,更新后执行回调。
this.$nextTick(callback)
,当dom发生变化,更新后执行的回调。
20.vue3.0 与 vue2.0 的区别
- 性能提升
更小巧,更快速;支持摇树优化;支持跨组件渲染;支持自定义渲染器。
- API 变动
除渲染函数API和
scoped-slot
语法之外,其余均保持不变或者将通过另外构建一个兼容包来兼容
- 重写虚拟 DOM 随着虚拟 DOM 重写,减少运行时开销。
21.vue中的provide和inject
一、名词解析:
provide
:Object | () => Object
inject
:Array<string>
| { [key: string]: string | Symbol | Object }
provide
:提供依赖,是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。
inject
: 注入依赖一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from
和default
默认值。
说明:
provide
和 inject
主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
这对选项是成对使用的。子孙组件想要获取祖先组件得资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱。这个就是这对选项要干的事情。
22.vue中mixins(混入)的使用
一、来自官网的描述
混入 (mixins
): 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
二、项目中如何使用混入
在vue组件内,如果想将一些公共功能,如组件、方法、钩子函数等复用,混入是一个很好的选择。下面简单介绍一下混入的方式及特点。
你可以将一个对象作为混入的选项,在组件中复用。因为vue实例也是对象,所以你可以将vue实例作为混入选项传递进去。
- 定义混入对象
common.js 就是我们要混入其它组件的内容 - 定义使用混入的组件
test.vue组件用mixins
把common.js内容混入当前组件 - 存在的问题:
混入的对象中的msg
属性,和组件的msg
属性冲突,以组件的值优先。组件中没有的属性,混入对象中的生效。
同名钩子函数将会合并成一个数组,都会调用,混入函数先调用
值为对象的选项,如methods
,components
,directives
等,将会合并为一个新对象,如果键名冲突,组件的值优先
23.vue项目如何部署到nginx服务器
mac下安装nginx
安装工具:
homebrew(还没用过的小伙伴可以点链接进行了解或者自行百度)
步骤:
- 打开终端,习惯性命令:更新
brew update
- 终端继续执行命令:
brew search nginx //查询要安装的软件是否存在
- 这里我们多执行一步“废”命令,不过有利于我们后面的配置:
brew info nginx
我们可以看到,nginx在本地还未安装(Not installed
),nginx的来源(From),Docroot默认为/usr/local/var/www
,在/usr/local/etc/nginx/nginx.conf
配置文件中默认端口被配置为8080
从而使nginx运行时不需要加sudo,nginx将在/usr/local/etc/nginx/servers/
目录中加载所有文件,以及我们可以通过最简单的命令 ‘nginx
’来启动nginx。 - 正式开始安装:
brew install nginx
- 查看nginx安装目录(是否如info所说)
成功打开nginx目录,也可以看到如info所说servers目录以及nginx.conf的配置文件(后面会用到这个配置文件)。但我们并没有找到nginx被安装到了哪里。
终端继续执行:
open /usr/local/Cellar/nginx //其实这个才是nginx被安装到的目录
会看到一个以当前安装的nginx的版本号为名称的文件夹,这个就是我们安装的nginx根目录啦。进入1.12.2_1/bin目录,会看到nginx的可执行启动文件。
同样的,我们在1.12.2_1/目录下还可以看到一个名字为html的快捷方式文件夹(暂且就这么叫吧),进入该目录我们会发现其实它指向的就是/usr/local/var/www
目录,这个在上面我们查看的info信息中有提到(Dcroot) - 启动nginx,终端输入如下命令:
nginx
没有报错即为启动成功。 - 访问验证:
打开浏览器访问localhost:8080
,这里跟网上的一些教程会有些不一样,正常情况下到这一步就会能看到nginx的欢迎界面啦。
nginx的配置(nginx.conf):
cat /usr/local/etc/nginx/nginx.conf
多个Vue项目如何部署到服务器 - vue打包
在项目中输入npm run build
在这里插入图片描述
此时会生产一个dist目录 - 将dist目录上传至ngnix中的html目录中修改Nginx文件,找到nginx.conf
- 如果此时有多个vue项目,多加几个
location
即可 - 最后记得保存
- 重新启动Nginx
sudo nginx -s reload
- 终端运行:
sudo nginx -s reload // 修改配置后重新加载生效
sudo nginx -s stop // 快速停止nginx
24.渐进式框架的理解
Vue是一个MVVM的渐进式框架,,渐进式指的是先使用Vue的核心库,然后再根据需求逐渐增加所需要的插件,慢慢的组织成自己的项目,
我们在使用过程中主张最小化,Vue没有强主张,插件使用比较灵活,也就是没有做职责之外的事。
25.兄弟组件如何通信
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过
Bus.$emit(“事件名”,"参数")
来来派发事件,数据是以$emit()
的参数形式来传递 - 在接受的数据的一方 引入 Bus.js 然后通过
Bus.$on("事件名",(data)=>{data是接受的数据})
26.params和query的区别?
- 用法上的
query要用path
来引入,params要用name
来引入,接收参数都是类似的,分别是this.$route.query.name
和this.$route.params.name
- 展示上的
query更加类似于我们ajax中get
传参,params则类似于post
,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示 - params是路由的一部分,必须要有。query是拼接在
url
后面的参数,没有也没关系
27.git的指令:
- 提交步骤
git init
初始化git仓库 (mac中Command+Shift+.
可以显示隐藏文件)
git status
查看文件状态
git add 文件列表
追踪文件
git commit -m 提交信息
向仓库中提交代码
git log
查看提交记录 - 撤销
用暂存区中的文件覆盖工作目录中的文件:git checkout --文件名
将文件从暂存区中删除:git rm --cached 文件名
将 git 仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作目录:git reset --hard commitID
- 分支命令
git branch
查看分支
git branch 分支名称
创建分支
git checkout 分支名称
切换分支
git merge 来源分支
合并分支
备注:必须在master分支上才能合并develop分支
git branch -d 分支名称
删除分支(分支被合并后才允许删除)(-D 强制删除
- 暂时保存更改
在git中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。
使用场景:分支临时切换
存储临时改动:git stash
恢复改动:git stash pop
- 推送
git push 地址 master
备注:如果远程仓库有内容,要先git pull 地址 master
- 设置别名
git remote add origin https://github.com/teach-tian/ccc.git
添加远程仓库origin
(origin
是仓库别名)
git push origin master
git push -u origin master
-u
记住推送地址及分支,下次推送只需要输入git push
即可
备注: 首先本地已经进行git初始化等一系列操作之后再进行推送命令:
git push -u -f origin master
(提交到远程仓库,这个命令中的-f
是强制推送,因为远程仓库只有初始化的文件,所以强制推送上去就行了)
同样可以尝试这句:(从远程仓库拉取内容,同步本地仓库)
git pull origin master --allow-unrelated-histories
28.ES6
一、箭头函数与普通函数区别
2. 箭头函数是匿名函数,不能作为构造函数,不能使用new
3. 箭头函数内没有arguments,可以用展开运算符...
解决
4. 箭头函数的this,始终指向父级上下文(箭头函数的this取决于定义位置父级的上下文,跟使用位置没关系,普通函数this指向调用的那个对象)
5. 箭头函数不能通过call()
、 apply()
、bind()
方法直接修改它的this指向。(call、aaply、bind会默认忽略第一个参数,但是可以正常传参)
6. 箭头函数没有原型属性
二、解构赋值
解构赋值允许使用类似数组或对象字面量的语法将数组和对象的属性值赋给一系列变量 它左右结构必须一样,主要作用是快速的让我们在数据中抓取出我们想要的数据。
29.3.JavaScript中let、const、var 的区别
- 是否存在变量提升?
var
声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,let
和const
不存在变量提升。 - 是否存在暂时性死区?
let
和const
存在暂时性死区。即只要块级作用域内存在let
命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。 - 是否允许重复声明变量?
var
允许重复声明变量。
let
和const
在同一作用域不允许重复声明变量。 - 是否存在块级作用域?
var
不存在块级作用域。
let
和const
存在块级作用域。 - 是否能修改声明的变量?
var
和let
可以。
const
声明一个只读的常量。一旦声明,常量的值就不能改变。const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值。
30.4.async、await
async
和 await
是一种同步的写法,但还是异步的操作,两个内容还是必须同时去写才会生效不然的话也是不会好使,而且 await
的话有一个不错的作用就是可以等到你的数据加载过来以后才会去运行下边的 js 内容,而且 await
接收的对象必须还是个 promise
对象,如果是接收数据的时候就可以直接用一句话来接收数据值,所以这个 async
await
我的主要应用是在数据的接收,和异步问题的处理,主要是还是解决不同执行时机下的异步问题!
31.5.es6中的Generator函数详解
Generator 函数的定义
语法上,Generator
函数是一个状态机,封装了多个内部状态。
形式上,Generator
是一个函数。不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。
整个Generator
函数就是一个封装的异步任务,或者说是异步任务的容器,异步操作需要暂停的地方,都用yield语句。
什么是Generator函数
function
关键字和函数之间有一个星号(*
),且内部使用yield表达式,定义不同的内部状态。
调用Generator
函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象。
32.6.什么是Promise?
简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,promise
是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
Promise
是一个构造函数,对外提供统一的 API,自己身上有all
、reject
、resolve
等方法,原型上有then
、catch
等方法。
Promise的两个特点
Promise
对象的状态不受外界影响
pending
初始状态fulfilled
成功状态rejected
失败状态
Promise
有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态
- Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由
pending
变成fulfilled
或者由pending
变成rejected
有哪些状态和参数?如何使用?
- 主要用于异步计算
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
- 可以在对象之间传递和操作
promise
,帮助我们处理队列
resolve
作用是,将Promise
对象的状态从“未完成”变为“成功”(即从pending
变为resolved
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject
作用是,将Promise
对象的状态从“未完成”变为“失败”(即从pending
变为rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise 有三个状态:
pending
[待定]初始状态fulfilled
[实现]操作成功rejected
[被否决]操作失败
当promise
状态发生改变,就会触发then()
里的响应函数处理后续步骤
reject()方法:
上面样例我们通过 resolve
方法把 Promise
的状态置为完成态(Resolved
),这时 then
方法就能捕捉到变化,并执行“成功”情况的回调。
而 reject
方法就是把 Promise
的状态置为已失败(Rejected
),这时 then
方法执行“失败”情况的回调(then
方法的第二参数)
catch()方法:
它可以和 then
的第二个参数一样,用来指定 reject
的回调
它的另一个作用是,当执行 resolve
的回调(也就是上面 then
中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死js,而是会进到这个 catch
方法中。
33.原型和原型链
- 原型的概念
JavaScript 的所有对象中都包含了一个[proto]
内部属性,这个属性所对应的就是自身的原型JavaScript 的函数对象,除了原型[proto]
之外,还有prototype
属性,当函数对象作为构造函数创建实例时,该prototype
属性值将被作为实例对象的原型[proto]
- 原型链的概念
当一个对象调用自身不存在的属性/方法时,就会去自己[proto]
关联的前辈prototype
对象上去找,如果没找到,就会继续去他关联的前辈去找。依次类推,直到找到属性/方法或undefined
为止。从而形成了所谓的“原型链”。
34.vue 组件父子,子父,兄弟通信
第一种:父传子:主要通过 props
- 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
- 在子组件中通过
props
来接受数据,props
可以是数组也可以是对象,接收的数据可以直接使用props:["属性名"]``props:{属性名:数据类型}
第二种:子传父:主要通过$emit
来实现
4. 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
5. 在子组件的方法中通过this.$emit("事件")
来触发在父组件中定义的事件,数据是以参数的形式进行传递的
第三种:兄弟之间传值:有两种方法
- 通过 event bus 实现
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过
Bus.$emit(“事件名”,"参数")
来来派发事件,数据是以$emit()
的参数形式来传递- 在接受的数据的一方 引入 Bus.js 然后通过
Bus.$on("事件名",(data)=>{data是接受的数据})
- 通过 vuex 实现
35.21、 es6 有哪些拓展
- 新增了块级作用域(
let
,const
) - 提供了定义类的语法糖(
class
) - 新增了一种基本数据类型(
Symbol
) - 新增了变量的解构赋值
- 函数参数允许设置默认值,引入了
rest
参数,新增了箭头函数
数组新增了一些 API - 对象和数组新增了扩展运算符
- ES6 新增了模块化(
import
/export
) - ES6 新增了
Set
和Map
数据结构 - ES6 原生提供
Proxy
构造函数,用来生成Proxy
实例 - ES6 新增了生成器(
Generator
)和遍历器(Iterator
)
36.什么是深拷贝,浅拷贝,如何实现
深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。可以使用for in
、Object.assign
、扩 展 运 算 符...
、Array.prototype.slice()
、Array.prototype.concat()
、递归等递归函数实现深拷贝