面试

166 阅读28分钟

搜索

前端知识

1.VUE生命周期、执行顺序及其执行阶段

(1) beforeCreate
创建实例之前:在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。

(2) created
创建实例之后:在这个周期函数中发送数据请求,从服务器获取需要绑定的数据。这样可以保证第一次渲染的过程中,数据已经在请求中了,当第一次渲染完用不了多久真实数据就回来了,此时在重新渲染视图,这样保证真实数据可以更快的出来

(3) beforeMount
挂载前:完成模板编译,虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。

(4) mounted
挂载完成:将编译好的模板挂载到页面 (虚拟DOM挂载) ,可以在这进行异步请求以及DOM节点的访问,在vue用$ref操作。

(5) beforeUpdate
更新数据前:组件数据更新之前调用,数据都是新的,页面上数据都是旧的 组件即将更新,准备渲染页面 , 可以在当前阶段进行更改数据,不会造成重渲染。

(6) updated
组件更新:render重新渲染 , 此时数据和界面都是新的 ,要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。

(7) beforeDestroy
组件卸载前:实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。

(8) destroyed
组件卸载后:组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

(9) activated
keep-alive专属,组件被激活时调用。

(10) deactivated
keep-alive专属,组件被休眠时调用。

初次渲染触发的生命周期:

beforeCreate() -> created() -> beforeMount() -> mounted() ->beforeUpdate()-> updated()

从Vue父子组件的生命周期执行顺序上理解

加载渲染过程

父 beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created ->子beforeMount -> 子mounted -> 父mounted

组件更新过程

父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

销毁过程

父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

2.列举七个常用vue指令及其含义!**

v-text 把数据解析成文本信息

v-html 把数据中的html字符串识别成html标签

v-if/v-else-if/v-else 与javaScript中的一样,用于判断,为true创建,false销毁

v-show 通过控制元素的display来控制元素的显示与隐藏

v-for 循环动态创建元素,循环的元素都要设定“唯一的id”

v-on 实现事件绑定,简写为@

v-bind 简写为: 给元素的某个属性动态绑定值,用于动态更新html上元素的标签内容

v-slot 插槽,简写为#

v-pre 跳过自己以及子元素的编译过程,一般给静态节点设置

v-model 数据的双向绑定 -> :value 和 @input

v-clock 可以保证vue没有完成模板编译之前,页面是隐藏的(这样就看不到小胡子那些括号了),编译完成后在显示

v-once 只渲染一次,后续视图更新不会在渲染

3、vue是MVVM框架还是MVC框架,并简单描述这个词的概念!

MVVM是 M:Model数据层 V:View视图层 VM:ViewModel 双向监听层(Vue框架核心)

ViewModel:保证数据和视图的一致性

VM会监听数据改变,通知视图重新渲染

VM也监听视图层改变,更改对应的数据,这就实现了数据的双向绑定…

Vue数据双向绑定的原理

通过数据劫持结合发布者-订阅者模式的方式实现的,利用了Object.defineProperty()重新定义了对象获取属性值(get)和设置属性值(set)

4、computed与watch有什么区别?以及运用场景?

Watch:

是监听属性的变化

函数是不需要调用的

不支持缓存,只要数据变化就会出发相应的操作

需要在数据变化时执行异步操作或者开销较大的操作时使用

监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,

① immediate:组件加载立即触发回调函数执行,

② deep: 深度监听,

Computed

通过属性计算而得到某个属性

内部的函数需要调用,并且不需要加括号

Computed的值有缓存,只有所依赖的属性发生变化,才会重新计算

一般处理复杂的逻辑或者多个属性的变化会影响一个属性的变化

使用场景:

一般来说需要依赖别的属性来动态获得值的时候可以使用 computed,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用 watch。

Computed: 当一个属性受多个属性影响时,(例如购物车结算)

Watch: 一个属性的变化影响多个属性,例如路由监听,搜索

5. v-show与v-if有什么区别?

相同点:v-show和 v-if都是 控制 dom元素的显示和隐藏的。

不同点:

(1)v-show是通过控制元素的样式属性display的值,来完成显示和隐藏;

v-if是通过对dom元素的添加和删除,完成显示和隐藏

(2) v-show:使用在dom元素频繁切换的场景

v-if:当dom元素的切换不频繁,可以使用。特别是,首次元素处于隐藏的情况下。

(3) v-if:有更高的切换消耗 v-show:有更高的初始化的渲染消耗

6. 说说你对 SPA 单页面的理解,它的优缺点分别是什么?

****SPA( single-page application )仅在 Web页面初始化时加载相应的 HTML、JavaScript 和 CSS,一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML 内容的变换,UI与用户的交互,避免页面的重新加载。

优点:

(1)用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;

(2)基于上面一点,SPA 相对对服务器压力小;

(3)前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

缺点:

(1)初次加载耗时多:为实现单页Web 应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面按需加载;

(2)前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;

(3)SEO难度较大:由于所有的内容都在一个页面中动态替换显示,所以在SEO上其有着天然的弱势

7. 阐述 v-model 的原理

v-model实现了MVVM中“视图更新,影响数据”

视图更新:一般指表单元素内容改变 影响数据:指自动修改对应的数据

原理:

(1)把响应式数据赋值给文本框的value

(2)监听文本框的input事件,在方法中,根据文本框最新的内容,手动更改状态值(响应式数据),这样就实现了数据改变,视图更新

8. 为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?

Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x 里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象才是更好的选择。

Proxy可以劫持整个对象,并返回一个新的对象。Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。

Proxy 的优势如下:

(1)Proxy 可以直接监听对象而非属性;

(2)Proxy 可以直接监听数组的变化;

(3)Proxy 有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,是Object.defineProperty不具备的;

(4)Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;

(5)Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

Object.defineProperty 的优势如下:

兼容性好,支持IE9,而Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy重写;****

9. Vue 组件 data 为什么必须是函数 ?

组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一个新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

10. 谈谈你对 keep-alive 的了解?

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染,其有以下特性:

(1) 一般结合路由和动态组件一起使用,用于缓存组件;

(2) 提供include和exclude属性,两者都支持字符串或正则表达式,include表示名称匹配的组件会被缓存,exclude表示名称匹配的组件都不会被缓存,其中exclude的优先级比include高;

(3) 对应两个钩子函数activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被休眠时,触发钩子函数 deactivated

11. Vue 组件间通信有哪几种方式?

(1) props / $emit 适用父子组件通信

(2) ref / parent/parent / children 适用父子组件通信

ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;

如果用在子组件上,引用就指向组件实例;

parent/parent / children:访问父/子实例

(3) EventBus(emit/emit / on / $off)适用于父子、隔代、兄弟组件通信

这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

(4) attrs/attrs / listeners 适用于隔代组件通信

attrs:包含了父作用域中不被prop所识别(且获取)的特性绑定,当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定,并且可以通过vbind="attrs:包含了父作用域中不被prop所识别 (且获取) 的特性绑定,当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定,并且可以通过v-bind="attrs"传入内部组件,通常配合inheritAttrs选项一起使用;

$listeners:包含了父作用域中的(不含 .native 修饰器的)v-on事件监听器,它可以通过

v-on="$listeners"传入内部组件;

(5) provide / inject 适用于隔代组件通信

祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。provide / inject

API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系;

(6) Vuex适用于父子、隔代、兄弟组件通信

Vuex是一个专为Vue.js应用程序开发的状态管理模式,每一个Vuex应用的核心就是store(仓库),

“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 (state);

Vuex的状态存储是响应式的,当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新;改变store中的状态的唯一途径就是显式地提交(commit)mutation,这样使得我们可以方便地跟踪每一个状态的变化;

12. 请介绍一下你对vuex的理解?

Vuex是一个vue插件,用来解决组件间数据交互问题

vuex五大核心属性:state,getter,mutation,action,module

state:存储数据,存储状态;在根实例中注册了store后,用this.$store.state来访问;对应vue里面的data;存放数据方式为响应式,vue组件从store中读取数据,如数据发生变化,组件也会对应的更新。

getter:可以认为是 store 的计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

mutation:更改 Vuex 的store中的状态的唯一方法是提交mutation。通过commit来触发mutations里面的方法进行数据的修改 this.$store.commit(‘函数名’,参数)

action:专门操作异步请求的数据和业务逻辑的地方,它不能直接变更state中的状态,而是通过commit来调用mutations里的方法来改变state里的数据

通过dispatch来触发actions里面的方法。this.$store.dispatch(‘函数名’,参数)

module:将 store 分割成模块,每个模块都具有state、mutation、action、getter、甚至是嵌套子模块。

13. 请介绍一下你对vue-router的理解?

vue-router 路由模式有几种?

Hash模式和History模式

Hash其原理是通过hashChange()事件监听hash值的变化

(1)只需要前端配置路由表,不需要后端的参与

(2)兼容性好,浏览器都能支持

(3)hash不会触发视图更新

History:利用的是popstate()事件,和pushState()/replaceState()方法

Window.addEventListener(‘popstate’,()=>{})会让视图刷新

pushState、replaceState不会让视图刷新

vue-router 中的导航守卫函数

全局前置守卫:权限(登录/访问)校验、修改title

router.beforeEach((to,from,next)=>{})

to:即将要进入的目标路由对象

from:当前导航正要离开的路由

next:钩子函数,里面定义参数,确认下一步路由要做什么

全局解析守卫:router.beforeResolve

这和 router.beforeEach类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

全局后置守卫:router.afterEach(to,from)路径跳转完后执行

守卫不同的是,后置钩子不会接受next函数也不会改变导航本身:

路由独享守卫:beforeEnter(to,from,next)(next必须执行)

组件内的守卫:

beforeRouteEnter(to,from,next)

beforeRouteUpdate(to,from,next)

beforeRouteLeave(to,from,next)

14. Vue 中的 key 有什么作用?

key是为Vue中vnode的唯一标记,通过这个key,我们的diff操作可以更准确、更快速;

Vue的diff过程可以概括为:oldCh和newCh各有两个头尾的变量oldStartIndex、oldEndIndex 和

newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有4种比较方式:

newStartIndex和oldStartIndex 、newEndIndex和oldEndIndex 、newStartIndex和oldEndIndex

、newEndIndex和oldStartIndex,如果以上4种比较都没匹配,如果设置了key,就会用key再进行比较,在比较的过程中,遍历会往中间靠,一旦StartIdx>EndIdx表明oldCh和newCh至少有一个已经遍历完了,就会结束比较!

所以Vue中key的作用是:

key是为Vue中vnode的唯一标记,通过这个key,我们的diff操作可以更准确、更快速

更准确:因为带key就不是就地复用了,在sameNode函数 a.key === b.key 对比中可以避免就地复用的情况,所以会更加准确;

更快速:利用key的唯一性生成map对象来获取对应节点,比遍历方式更快;

15. 怎样理解 Vue 的单向数据流?

(1)从传递属性方面理解

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行,这样会防止从子组件意外改变父级组件的状态;额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值,这意味着你不应该在一个子组件内部改变 prop;如果你这样做了,Vue会在浏览器的控制台中发出警告;子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改;

(2) 从Vue父子组件的生命周期执行顺序上理解

加载渲染过程 、组件更新过程 、销毁过程

16. 组件中有个数组ary,通过 this.ary[1]=11; 可以触发视图更新吗?如果不能,怎样才能,写出两种办法!

不能,set方法:this.set 方法:this.set(this.array,index,newValue)

$forceUpdate()强制更新

17. 父组件可以监听到子组件的生命周期吗?

(1)在父组件中定义一个事件,在子组件中用$emit去触发

(2)父组件引用子组件时,给父组件添加@hook来监听

@hook 方法不仅仅是可以监听mounted,其它的生命周期事件,例如:created,updated等都可以监听

18. 你有对 Vue 项目进行哪些优化?

****(1) v-if和v-show区分使用场景:频繁切换使用v-show,不频繁使用v-if(这样不显示的内容不渲染)

(2) computed:基于计算属性实现数据缓存

(3) v-for遍历必须为item添加key(且不建议使用索引作为key),避免同时使用v-if

(4) 对于后期不需要修改的数据,基于 Object.freeze 冻结

(5) Vue组件销毁时,会自动清理它与其它实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件;如果在js内使用addEventListene等方式是不会自动销毁的,我们需要在组件销毁时手动移除这些事件的监听,以免造成内存泄露;

(6) 图片资源懒加载

(7) vue-router路由懒加载:Vue是单页面应用,可能会有很多的路由引入,这样使用webpcak打包后的文件很大,当进首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验;如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了,这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来;

(8) UI组件库按需引入

(9) 基于vue-virtual-scroll-list优化无限列表(长列表)

(10) 基于事件委托处理事件绑定、以及对某些操作进行防抖和节流处理

(11) 基于keep-alive实现组件缓存

(12) 基于vuex缓存不经常更新的数据

(13) 对于没有使用vue语法的模块,用v-pre指令来提升编译效率

(14) data尽可能扁平化处理(vue的数据劫持方面优化)

(15) 使用字体图标代替切图

(16)提取公共样式和方法

(17)销毁定时器

(18)减少重绘回流

服务端渲染SSR

Webpack层面的优化,例如:提取公共代码、模板预编译、优化SourceMap...

还可以从网络层优化,例如:资源的清缓存和数据缓存

19. 简述 vue3.0 和 vue2.0 的区别!

(1) Performance

重写了虚拟DOM的实现(跳过静态节点,只处理动态节点)

update性能提高1.32倍 SSR速度提高了23倍

(2) Tree shaking:可以将无用模块“剪辑”,仅打包需要的

(3) Fragment:不再限于模板中的单个根节点

(4) :译作传送门

(5) :可在嵌套层级中等待嵌套的异步依赖项

(6) TypeScript:更好的TypeScript支持

(7) Custom Renderer API:自定义渲染器API,用户可以尝试WebGL自定义渲染器

(8) Composition [ˌkɒmpəˈzɪʃn] API

组合式API,替换原有的 Options API

根据逻辑相关性组织代码,提高可读性和可维护性

更好的重用逻辑代码(避免mixins混入时命名冲突的问题)

但是依然可以延用 Options API

(9) Proxy:响应式原理不再基于 Object.defineProperty

(10) 优先采用函数式编程开发

20. scoped属性的作用!

当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,通过该属性,可以使得组件之间的样式不互相污染。

在DOM结构以及css样式上加上唯一的标记,行内属性选择器(data-v-xxx),保证唯一性来达到样式私有化,不会污染全局

21. ref的作用!

ref添加在普通DOM上,就可获取DOM对象

添加在子组件身上,可获取子组件,子组件身上的属性和方法统统可以被父组件调用

22. 路由懒加载如何实现?

(1)vue异步组件加载 例如:在页面中异步加载home.vue组件

components:{

home:()=>import('../home.vue的路径')}

(2)es6提案的import()

{path:’/home’,

name:’home’,

component: () => import(/* webpackChunkName: 'home' */ '../home.vue')}

(3)webpack的require.ensure()

{ path: '/home',

name: 'home',

component: r => require.ensure([], () => r(require('../home')), 'demo') }

23. 在vue中渲染DOM是同步的还是异步的?如何拿到DOM更新后的数据?

异步, $nextTick()

24. 动态组件如何实现的?

(1)可以通过 Vue 的 元素加一个特殊的 is 特性来实现;

Component标签是vue内置的,作用:组件的占位符

is属性值,表示要渲染的组件名字

(2)通过v-if来进行条件渲染,同样能实现。

25. 谈谈你对动态路由的理解?

涉及到权限问题时,配合后端传递数据,后端返回哪个页面,就循环加载那个路由

this.$router.addRoute({

path:’/aaa’,

component:AAA})

router.addRoute() //应用程序已经运行的时候添加路由

router.removeRoute() // 应用程序已经运行的时候删除路由

26. 小程序的生命周期函数?

onLoad() 页面加载时触发,只会调用一次,可获取当前页面路径中的参数

onShow() 页面显示/切入前台时触发,一般用来发送数据请求

onReady() 页面初次渲染完成时触发, 只会调用一次,代表页面已可和视图层进行交互

onHide() 页面隐藏/切入后台时触发, 如底部 tab 切换到其他页面或小程序切入后台等

onUnload() 页面卸载时触发,如redirectTo或navigateBack

28. vue的响应式原理

Vue2:当你把一个普通的JavaScript对象传入Vue实例作为data选项,Vue将遍历此对象所有的 property,并使用Object.defineProperty把这些 property 全部转为getter/setter

这些 getter/setter 对用户来说是不可见的(在控制台中可以查看),但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。

每个组件实例都对应一个watcher实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

Vue无法检测 property的添加或移除。由于Vue会在初始化实例时对property执行getter/setter 转化,所以property必须在data对象上存在才能让Vue将它转换为响应式的

Data中的某个属性还是对象,默认基于递归的方式,把data中每一层级都进行深度的监听劫持。

如果属性值是个数组,没有对数组的索引项进行监听劫持,但是重写了七个数组方法(push、pop、shift、unshift、splice、sort、reverse),基于这几个方法修改数组,也会触发视图重新渲染

Vue3的响应式原理:

(1)以ref为主的get/set劫持(核心还是Object.defineProperty())

(2)以reactive为主的数据劫持,是基于ES6中的Proxy实现的

除了做get/set劫持外,还可以实现其它方面的劫持:
getPrototypeOf/setPrototypeOf/isExtensible/preventExtensions/getOwnPropertyDescriptor/defineProperty/has/deleteProperty/ownKeys/apply/construct
Vue3中实现了:get/set/deleteProperty/has/ownKeys等劫持 ­> Vue3响应式实现的功能要强于Vue2
也像Vue2一样,基于递归对“对象”做了深层次劫持ES6新增的API,不兼容IE

29. webpack?

了解,我们工作中会配置vue.config.js:
经常会配置devServer来实现代理,这个配置项其实就是webpack-dev-server的配置,
webpack有几个基础的配置: mode模式、entry入口、output出口、module模块、plugin插件
module rules 用来配置各个loader的
plugins 是用来配置各个插件的
经常用的loader有:
css-loader:加载CSS,支持模块化、压缩、文件导入等特性
postcss-loader:扩展CSS语法,使用下一代CSS,可以配合autoprefixer插件自动补齐CSS3前缀
babel-loader:把ES6转换成 ES5
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL去引用输出的文件 (处理图片和字体)
url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件base64 形式编码 (处理图片和字体)
vue-loader:加载 Vue.js 单文件组件
mini-css-extract-plugin提供的loader: 使用link标签引入外联的css

常用的插件有:

html-webpack-plugin:设置渲染页面的模板

terser-webpack-plugin:支持压缩ES6(Webpack4)

mini-css-extract-plugin:分离样式文件,CSS提取为独立文件,支持按需加载

clean-webpack-plugin:目录清理

define-plugin:定义环境变量

DllPlugin:此插件用于在单独的webpack配置中创建一个dll-only-bundle。此插件会生成一个名为manifest.json的文件,这个文件是用于让DllReferencePlugin能够映射到相应的依赖上

还配置过configerWebpack,这个属性里边的配置其实就是webpack的配置,在这个里边我配置过resolve下的alias的api路径

还配置过externals来实现通过cdn引入某些三方插件

30. Vuex页面刷新丢失怎么解决?

****(1)localStorage

(2)window.beforeunload页面关闭前在存

31. computed原理?

每一个计算属性本质都是一个Watcher实例,
这个实例会被当前使用的那个元素收集到自己的subs中。
每当依赖更新时,会把当前Watcher实例的dirty属性重置成true。
那么再去使用reName时,会触发watcher的evaluate函数。
这个函数的执行会更新watcher实例的value值,我们使用的reName属性对应的值其实就是watcher.value,所以说若依赖没有更新,那么调用rename属性时就不会触发evaluate,那也就不会更新这个value。
也就是说用的是之前算出来的value

32. 全局组件一次导入注册完

以前全局组件都是一个个导入注册,有点麻烦,

let qqq=require.context(‘./component’,false,/.vue$/); //返回一个函数qq

qqq.keys().forEach(r=>{ //qqq.keys()就是 .vue 组件们,r是每一个组件

let obj=qqq(r).default; //导出每个组件所有的内容,字符串形式

Vue.component(obj.name,obj); //组件名,组件

})

require.context(‘搜索的目录’,是否还搜索其子目录,匹配文件的正则表达式)这个函数创建自己的context,返回一个函数

keys()是一个函数,它返回一个数组

33. nextTick 使用场景和原理

在下次DOM更新循环结束后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。使用场景是:可以在created钩子函数中拿到dom节点

1、nextTick是一个微任务。

2、nextTick中的回调是在下次Dom更新循环结束之后执行的延迟回调

3、可以用于获取更新后的Dom

4、Vue中的数据更新是异步的,使用nextTick可以保证用户定义的逻辑在更新之后执行

5、nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法

35. Echarts使用:

****(1) 安装Npm install echarts

(2)在使用的页面的导入:import {init} from ‘echarts’

(3)在页面创建

(4)this.myCharts=init(this.$refs.box);

(5)let option={option的配置 -> 去echarts官网抄}

(6)this.myCharts.setOption(option);

36. Set/Map

Set: (1)Set是ES6提供的一种类似于数组的数据结构

(2)不同于数组的是,它的成员的值都是唯一的,不会有重复。

Set对象的操作方法:size、add、delete、has、clear

Set对象的遍历方法:keys()、values()、entries()、forEach()

由于set对象键名和键值都是同一个值,所以keys()和values()方法完全一致。

Map: (1)map数据结构是一种类似于对象的键值对数据结构

(2)不同于对象的是Map的键可以为任意类型的值,而不仅仅为字符串

任何基于Iterator接口且每个成员都是一个双元数组的数据结构都可以当做Map构造函数的参数。

Map对象的操作方法:size、set(key,value)、get(key)、delete(key)、has(key)、clear()

Map对象的遍历方法:key()、values()、entries()、forEach()

37. 移动端适配

posscss-pxtorem是一款 PostCSS 插件,用于将 px 单位转化为 rem 单位

postcss.config.js在这个文件里面写:

module.exports = {

plugins: {

'postcss-pxtorem': {

rootValue:37.5, //根据设计稿宽度:750就写成75;375就写成37.5

propList: ['*'],

},

},

};

lib-flexible用于设置 rem 基准值

lib-flexible点击拿到js代码,放到index.html文件中即可(script里)

生产依赖?项目开发完是需要用的就是生产依赖 -S

开发依赖?项目开发时用到的就是开发依赖 -D

38、delete和Vue.delete删除数组的区别

普通的delete删除一个数组中的元素,该元素会成为空值(empty)。数组长度不变。

vue.delete删除会直接删除一个数组元素,长度会减少。

39、px、em与rem的区别?

px像素相对于显示器屏幕分辨率是固定不变的,不受浏览器缩放影响

em相对于父元素的字体大小font-size

rem相对于根元素html的字体大小font-size

40、vue.mixin的使用场景和原理?

Vue的mixin的作用就是抽离公共的业务逻辑,原理类似对象的继承,当组件初始化的时候,会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。

如果混入的数据和本身组件的数据有冲突,采用本身的数据为准。

缺点:命名冲突、数据来源不清晰

41、vue的route和router的区别?

route是用来获取路由信息的,router是用来操作路由的。

(1)

$route.path:对应当前路由的路径,总是解析为绝对路径

$route.params:一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。

$route.query:一个key/value对象,如果没有路由参数就是一个空对象。

$route.hash:当前路由的hash值(不带#),如果没有hash值,则为空字符串

$route.fullPath:完整的路径信息,包括参数

$route.matched:数组,包含当前匹配的路径中所有片段所对应的配置参数对象。

$route.name:当前路径名字

$route.meta:路由元信息

(2)router路由实例方法

1、push

this.router.push(路径)/this.router.push(路径) / this.router.push({ path:路径 ,params: {参数})

push方法和是等同的。

注:push会添加一条历史记录

2、go 页面路由跳转:

前进或后退this.$router.go(-1)

3、replace

push方法会向history添加一个新记录,而replace方法是替换当前页面

4、一般使用replace来做404页面

this.$router.replace(‘/’)

配置路由时path有时候会加“/”,有时候不加“/”,以“/”开头的会被当作根路径,就不会一直嵌套之前的路径。

42、MVVM和MVC的区别

C即Controller指的是页面业务逻辑。使用MV的目的就是将M和V的代码分离。MVC是单向通信,也就是View和Model,必须通过Controller来承上启下。

1、mvc和mvvm都是一种设计思想。 主要就是mvc中Controller演变成mvvm中的viewModel。 mvvm主要解决了mvc中大量DOM操作使页面渲染性能降低,加载速度变慢的问题 。

2、MVVM与MVC最大的区别就是:它实现了View和Model的自动同步:当Model的属性改变时,我们不用再自己手动操作Dom元素来改变View的显示,它会自动变化。

3、整体看来,MVVM比MVC精简很多,我们不用再用选择器频繁地操作DOM。

MVVM并不是用VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。

1、说一下http和https

基本概念:

http:超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从www服务器传输超文本到本地浏览器的传输协议,他可以使浏览器更加高效,是网络传输减少。

https:是以安全为目标的http通道,简单来说是http的安全版,即http下加入ssl层,https的安全基础是ssl,因此加密的详细内容就需要ssl。

https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。

主要区别:

https协议需要ca证书,费用较高

http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

使用不同的链接方式,端口也不同。http协议的端口号是80,https的端口号为443,ftp的端口号是21

http的连接很简单,是无状态的;https协议是ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全

特点:

http:常用。快

https:更安全的http,有ssl加密,特点:安全

ftp:文件传输。特点:传输内容大

2、TCP和UDP的区别?

(1)tcp是面向连接的,udp是无连接的即发送数据前不需要先建立链接。

(2)tcp提供可靠的服务。也即是说,通过tcp连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP 尽最大努力交付,即不保证可靠交付。 并且因为 tcp 可靠,面向连接,不会丢失数据因此适合大数据量的交换。

(3)TCP 是面向字节流,UDP 面向报文,并且网络出现拥塞不会使得发送速率降低

(因此会出现丢包,对实时的应用比如 IP 电话和视频会议等)。

(4)TCP只能是1对1的,UDP支持1对1,1对多。

(5)TCP 的 首 部 较大为 20 字节,而 UDP 只 有 8 字节。

(6)TCP 是面向连接的可靠性传输,而 UDP 是不可靠的。

3、localstorage、sessionstorage、cookie的区别?

Localstorage本地存储,不会自动清除,大小在5兆左右

Localstorage和sessionstorage的区别在local是永久存储,不主动删除永远在

Sessionstorage是会话存储,页面一旦关闭,会立即清空。

Storage只能前端操作,后端操作不了。

Cookie是前后端都能设置的一个属性,存储空间大概是4kb左右,会默认随着请求发送给后端。

设置cookie:document.cookie=‘xxx=xxx;expires=过期时间’

获取:document.cookie

删除:设置一个过期时间即可。

4、js数据类型

(1)基本数据类型:number、string、boolean、null、undefined、Symbol、bigInt

(2)引用数据类型:对象:普通对象、数组、正则、日期对象Date、数字对象Math(Math.random():获取0~1之间的随机数)

函数

基本数据类型和引用数据类型的区别?

基本数据类型按值操作,引用数据类型按地址空间操作

5、js类型检测数据类型的四种方法:

typeof:检测基本引用数据的类型;返回字符串

instanceof:检测某个实例是否隶属某个类

constructor:构造函数原型指向,如果手动改变原型指向,就不准确了

Object.prototype.toString.call()

6、数组方法:

push:向数组末尾追加一项;可添加多项;返回新数组的长度,改变原数组

pop:删除数组最后一项;无参数;返回删除的项;改变原数组

shift:删除数组第一项;无参数;返回删除的项,改变原数组

unshift:向数组的开头添加内容;可添加多项;返回新数组的长度;改变原数组

splice:删除、新增、修改;

(n,m,x)n:代表从那个索引开始删除;m:删除的项;x:把删除的内容替换

返回一个数组,里面是删除的每一项

改变原数组

slice:从原有数组中原定特定的数组;

(n,m)n:从n(包含)开始选中,选到m(b不包含)的项

返回的是复制的每一项

不改变原数组

concat:实现多个数组或值的拼接;参数是数组或值;返回拼接后的新数组;不改变原数组

toString:把数组转换为字符串;无参数,返回转换后的字符串,不改变原数组

join:把数组通过指定的连接符转换为字符串;参数是连接符;返回转换后的字符串;不改变原数组

reverse:把数组倒序;无参数;返回排序后的新数组;改变原数组

sort:排序;无参数或是个函数;返回排序后的新数组;改变原数组

indexof/lastIndexof:

(n,m)n:是检测的项,m:indexof代表从m开始检索;lastIndexof代表到m停止检索

返回-1,或具体的索引值

不改变原数组

includes:检测数组中是否包含某一项;参数是具体项;返回boolean;不改变原数组

forEach:循环遍历数组的每一项;参数是函数;返回undefined;不改变原数组

map:循环遍历数组的每一项;参数是函数;返回符合条件的新数组;不改变原数组

filter:把符合条件的拿过来,返回一个数组

find:把符合条件的第一项返回

some:有一个符合条件,就不再遍历,返回true

every:所有的项都符合条件,才返回true

7、字符串常用方法:

注:因为字符串是值数据类型,是按值操作,所以都不会改变原数据

charAt:获取对象位置的字符;返回对应的字符

chatCodeAt:获取对象的ASCII码值

indexof/lastIndexof:首次/末次出现的索引;有则返回索引,无则返回-1

slice(n,m):查找字符串特定位置的字符;

参数从n(包含)开始,到m(不包含)结束。支持正负数索引

subString(n,m):n包含,m不包含

subStr(n,m):n开始,m:截取m个字符

toUpperCase:字符串转大写

toLowerCase:字符串转小写

replace(str1,str2):替换,将str2替换str1;参数字符串或正则

split:按照指定的字符,把字符串分割成数组;参数是分隔符

8、slice、substring、substr的区别

slice支持正负数索引

subString不支持负数索引

subStr支持负数索引

9、闭包

闭包就是能够访问其他函数内部变量的函数

作用:保护和保存

保护:保护里面的私有变量不被外界干扰

保存:形成不被销毁的作用域,可以把里面的变量保存起来

暴露:1、通过window添加属性,暴露到全局

2、把自执行函数通过return,将返回的结果在外面用一个变量接收

闭包使用场景 任何闭包的使用场景都离不开这两点:

  • 创建私有变量(好比vue里的data 每个data都是一个闭包所以他们互不干扰)
  • 延长变量的生命周期

优缺点:它的优点就是可以实现封装和缓存,缺点就是可能会造成内存泄漏的问题

10、作用域,作用域链 & 原型、原型链

(1)作用域:就是变量与函数的可访问范围;分为:全局作用域、私有作用域、块级作用域(也是私有作用域,let、const)

作用域链查找机制:在私有作用域中查找一个变量,先看当前作用域是否有这个变量,如果没有,就会向上一级作用域查找……一直找到全局

如果全局也没有:(1)查询:报错

(2)赋值:就等于给全局添加一个这样的变量,变量值就是赋的值

上级作用域是谁,跟函数在哪执行没关系,跟函数在哪定义有关系

(2)原型:一般情况下所有的函数都有一个属性prototype,指向自己的原型

prototype这个原型上天生自带一个属性constructor,指的是当前的构造函数本身

所有的对象都天生自带一个属性__proto__,它指向当前实例所属类的原型

原型链查找机制:

当我们要查找或操作实例上的某个方法或属性的时候,我们会先查找实例的私有属性,看看私有属性上是否有,如果有停止查找;如果没有,就会基于__proto__向上查找,如果找到就是公有属性,如果还没有继续基于__proto__原型向上查找,直到object基类,如果还是没有,就是操作方法或属性不存在,即null

11、堆栈内存

栈内存:存储基本数据类型的值;给js提供可运行的环境,让js代码可以运行;

堆内存:存引用数据类型;对象存的是键值对;函数存的是字符串

栈内存释放:全局栈内存,当整个页面关闭之后,就销毁了

栈内存:销毁:函数执行完一会就销毁了

不销毁:一个函数在执行时,里面有一个引用数据类型被外界的变量占用就不销毁

不立即销毁:当函数执行完毕后销毁

堆内存释放:让所有引用这个堆内存的变量赋值为null,堆内存地址不再被引用,浏览器在空闲的时候就会把堆内存释放

12、改变this指向:call、bind、apply

call:fn.call(obj,1,2,3);

apply:fn.apply(obj,[1,2,3]);

bind:f1 = fn.bind(obj,1,2,3); f1()是新函数执行

返回一个新的函数体,新函数执行的时候,才让fn执行

1、相同点

(1)三个都是用于改变this指向; (2)接收的第一个参数都是this要指向的对象; (3)都可以利用后续参数传参。

2、不同点

(1)call和bind传参相同,多个参数依次传入的;

(2)apply只有两个参数,第二个参数为数组;

(3)call和apply都是对函数进行直接调用,而bind方法不会立即调用函数,而是返回一个修改this后的函数。

13、new执行和普通函数执行执行的区别?

new执行的时候,会开辟一个堆内存

并且当前函数中的this指向这个堆内存,

返回时,若return的不是引用数据类型,则返回的是this

14、箭头函数和普通函数的区别?

(1)箭头函数没有this,所以需要通过查找作用域链来确定this的值

(2)箭头函数没有arguments对象,但是可以访问外围函数的arguments对象

(3)不能通过new关键字调用,同样也没有new.target值和原型

arguments的理解

arguments是类数组对象,有length属性,不能调用数组方法

可用Array.from()转换

箭头函数获取arguments(可用…rest参数获取)

15、var、let、const的区别?

(1)var声明的变量会挂载在window上,而let和const声明的变量不会

(2)var声明变量存在变量提升,而let和const不存在变量提升

(3)let和const声明形成块作用域,var声明不形成块作用域

(4)同一作用域下let和const不能声明同名变量,而var可以声明同名变量

(5)暂存死区

(6)let声明的变量允许重新赋值,const不允许

null 和 undefined 的区别?

相同

1、在 if 语句中 null 和 undefined 都会转为false两者用相等运算符比较也是相等

2、首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。

不同:

undefined代表的含义是未定义

(1)定义了形参,没有传实参,显示undefined

(2)一般变量声明了但还没有定义的时候会返回 undefined

(3)对象属性名不存在时,显示undefined

(4)函数没有写返回值,即没有写return,拿到的是undefined

(5)null 代表的含义是空对象。也作为对象原型链的终点

(6)null 主要用于赋值给一些可能会返回对象的变量,作为初始化。

16、状态码

200:标准成功 206:断点续传

301:永久转移(永久重定向)=>域名迁移 302:临时转移

307:临时重定向 =>服务器负载均衡 304:服务器资源未更新

400:参数错误 401:权限有问题

403:服务器拒绝请求,但是为什么不告诉你,因为原因可能很多

404:地址错误 405:请求的方式不允许 408:请求超时

500:未知服务器错误 502:网关或代理服务器出现问题 503:超负荷,F5刷新解决

17、get请求和post请求的区别?

(1)传参方式不同,get是放在url后面,post是在请求体中

(2)post相对于get更安全,post是请求主体传参,相较于get的问号传参,不容易被劫持

(3)get传参的大小有限制(原因在url的长度限制)IE:2kb 谷歌:8kb

post理论上没有

(4)get请求有缓存,post没缓存:get请求一般会出现不可控的缓存,当请求地址及传参信息相同,浏览器可能会获取上一次请求的缓存内容,这样会导致第二次无法获取最新的内容,所以在开发项目中要清除这个缓存

解决办法:在请求地址末尾加上时间戳,或随机数,保证两次请求不完全一致

18、同源策略

同源策略是浏览器里的一种安全协议确保两页面间的协议、域名和端口都相同(一段脚本只能读取来自同一来源的窗口和文档的属性)

如何解决跨域问题

(1)jsonp(原理是动态插入script标签,但是只支持get请求)

(2)服务器上设置代理页面

(3)CORS(跨域资源共享——服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求,前后端都需要设置)

(4)window.name+ iframe

(5)window.postMessage

(6)document.domain+iframe

(7)websocket

(8)location.hash+iframe

19、display:none和visibility:hidden的区别

display:none在文档布局中不再给它分配空间

visibility:hidden隐藏后还在文档布局仍保留原来的空间

20、浏览器缓存机制

分为强缓存和协商缓存,根据响应的header内容来决定

强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互(不用请求服务器,直接使用本地缓存)-expires、cache-control

协商缓存:浏览器发送请求到服务器,服务器判断是否可使用本地缓存(浏览器发现本地有资源的副本,单不太确定要不要使用于是去问服务器)-Last-Modified/If-Modified-Since,Etag/If-None-Match

21、防抖:事件响应函数在一段时间之后才会执行,如果在这段时间之内,再次调用,则重新计算执行时间(通过setTimeout的方式,在一定的时间间隔内,将多次触发转变为一次触发)

应用场景:1、scroll时间滚动触发 2、搜索框输入查询 3、表单验证

4、按钮提交事件 5、浏览器窗口缩放

节流:如果持续触发事件,每隔一段时间,只执行一次操作(减少一段时间之内的事件触发频率)

应用场景:1、DOM元素的拖拽 2、射击类游戏 3、计算鼠标移动的距离

22、内存泄漏:指任何对象在您不在拥有或需要它之后仍然存在

垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

1、setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

2、闭包

3、控制台日志console

4、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

23、事件委托及冒泡原理

事件委托又名事件代理,事件委托就是利用事件冒泡(自里向外),就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了。

事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上,委托的优点是减少内存消耗,节约效率,动态绑定事件

事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束

24、数组去重

1、创建新数组,利用indexOf(去重)

2、ES6中利用new set(去重)

3、利用数组的sort()去重(相邻元素比较法)

4、利用数组的includes()去重

5、利用数组的filter()去重

25、宏任务和微任务

常见的微任务有:

(1)Promise.then/Promise.catch/Promise.finally

(2)MutaionObserver

(3)Object.observe(已废弃;Proxy 对象替代)

(4)process.nextTick(Node.js)

常见的宏任务有:

(1)script (可以理解为外层同步代码)

(2)setTimeout/setInterval

(3)调用ajax

(4)UI rendering/UI事件

(5)postMessage、MessageChannel

(6)setImmediate、I/O(Node.js)

26、for...in 迭代和 for...of 有什么区别

1、推荐在循环对象属性的时候,使用 for...in,在遍历数组的时候的时候使用for...of。

2、for in遍历的是数组的索引,而for of遍历的是数组元素值

3、for...of 不能循环普通的对象,需要通过和 Object.keys()搭配使用

4、for...in 遍历顺序以数字为先 无法遍历 symbol 属性 可以遍历到公有中可枚举的

5、从遍历对象的角度来说,for in会遍历出来的为对象的key,但for of会直接报错。

27、 Js中编码、解码及区别:

escape / unescape

encodeURL / decodeURL

encodeURLComponent / decodeURLComponent

1、如果只是编码字符串,不和URL有关系,那就用escape

2、如果需要编码整个URL,然后需要使用这个URL,那就用encodeURL

3、当需要编码URL中的参数时,那就用encodeURLComponent

28、 TypeScript

TS的基础类型有:

字符串(string)、数字(number)、布尔值(boolean)、空(null)、未定义(undefined)、数组(array)、对象(object)、元组(tuple)、枚举(enum)、any、void、never等12种。

29、axios

(1)、创建一个实例:axios.create([config])

实例方法: axios#request(config)
axios#get、axios#delete、axios#head、axios#options、axios#post、axios#put、axios#patch、axios#getUri([config])

(2)、请求配置

url: 用于请求的服务器url,只有url时必需的。

method:请求时用的方法,不指定默认为get

baseURL:将自动加在url前面,通过设置baseURL,便于为axios实例的方法传递相对url

transformRequest:允许在想服务器发送前,修改请求数据,只能用于put、post、patch这几个请求方法,

transformResponse:在传递then/catch之前,允许修改响应数据

headers:自定义请求头

params:是与请求一起发送的url参数,必需是一个简单的对象

timeout:指定允许超时的毫秒数

withCredentials:表示跨域请求时是否需要使用凭证,默认false

(3)、默认配置

全局axios默认值

axios.defaults.baseURL

axios.defaults.headers.common

axios.defaults.headers.post

自定义实例默认值

创建实例时配置默认值:

const instance = axios.create({

baseURL:’https://api/example.com

})

创建实例后修改默认值

instance.defaults.headers.common[‘Authorization’] = AUTH_TOKEN;

配置将按照优先级进行合并:

请求的config参数 > 实例的defaults属性 > 在lib/defaults.js中找到的库默认值

(4)、拦截器:在请求或响应被then或catch处理前拦截它们

// 添加请求拦截器

axios.interceptors.request.use(function(config){

// 在发送请求之前做些什么

return config;

},function(error){

// 对请求错误做些什么

returnPromise.reject(error);

});

// 添加响应拦截器

axios.interceptors.response.use(function(response){

// 2xx 范围内的状态码都会触发该函数。

// 对响应数据做点什么

return response;

}, function(error){

// 超出 2xx 范围的状态码都会触发该函数。

// 对响应错误做点什么

returnPromise.reject(error);

});

移除拦截器:先用一个变量接收这个拦截器,然后使用eject()移除

const myInterceptor=axios.interceptors.request.use(function(){/.../});

axios.interceptors.request.eject(myInterceptor);

(5)、错误处理

使用 validateStatus 配置选项,可以自定义抛出错误的 HTTP code。

axios.get('/user/12345',{

validateStatus:function(status){

return status <500;// 处理状态码小于500的情况

使用 toJSON 可以获取更多关于HTTP错误的信息。

axios.get('/user/12345')

.catch(function(error){

console.log(error.toJSON());

30、js和ts区别?

它们都是脚本语言。JavaScript 是轻量级的解释性脚本语言,可嵌入到 HTML 页面中,在浏览器端执行。而TypeScript 是JavaScript 的超集,即包含JavaScript 的所有元素,能运行JavaScript 的代码,并扩展了JavaScript 的语法。(ts包含了js的库和函数,ts上可以写任何的js,调用任何的js库,可以在ts中使用原生js语法)。相比于JavaScript ,它还增加了静态类型、类、模块、接口和类型注解方面的功能,更易于大项目的开发。

区别:

1、TypeScript 引入了 JavaScript 中没有的“类”概念

2、TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。

3、js没有重载概念,ts有可以重载

4、ts增加了接口interface、泛型、类、类的多态、继承等

5、ts对比js基础类型上,增加了 void/never/any/元组/枚举/以及一些高级类型

js有的类型:boolean类型、number类型、string类型、array类型、undefined、null

ts新增的类型:tuple类型(元组类型)、enum类型(枚举类型)、any类型(任意类型)

void类型(没有任何类型)表示定义方法没有返回值

never类型:是其他类型(包括null和undefined)的子类型,代表从不会出现的值这意味着声明never变量只能被never类型所赋值

js变量是没有类型的,即age=18,age可以是任何类型的,可以继续给age赋值为age=”aaa”

Ts有明确的类型(即:变量名:number(数值类型)) eg:let age: number = 18

ts需要静态编译,它提供了强类型与更多面向对象的内容。

ts最终仍要编译为弱类型,基于对象的原生的js,再运行。故ts相较java/C#这样天生面向对象语言是有区别和局限的

ts是由微软牵头主导的,其语法风格与概念主要来自C#,理解起来学过java的更容易理解(c#我没学过)

ts优势

1、类型化思维方式,使开发更严谨,能帮助开发人员检测出错误并修改,提前发现错误,减少改Bug时间

2、类型系统提高了代码可读性,便于开发人员做注释,维护和重构代码更加容易

3、补充了接口、枚举等开发大型应用时JS缺失的功能

【JS的类型系统存在"先天缺陷",绝大部分错误都是类型错误(Uncaught TypeError)】

4、TypeScript工具使重构更变的容易、快捷。

5、类型安全功能能在编码期间检测错误,这为开发人员创建了一个更高效的编码和调试过程。

31、从输入url到渲染页面中间经历了什么?

url解析、DNS解析、缓存检查、TCP三次握手、数据传输、TCP四次挥手、页面渲染

32、页面渲染

  1. 解析HTML,并搭建DOM树

浏览器接收到 html 文件后将其解析成 DOM 树,这个解析从接收到 html 文件 的时候就已经开始了,并不是等到接收完成后才开始,解析的过程是自上而下,先解析当前节点的所有子节点,再解析兄弟节点及其子节点

  1. 解析CSS,并搭建样式树

浏览器将所有的 css 包括其自身的样式全部解析成样式树,解析的过程中会自动去掉浏览器不能识别的样式

  1. 将HTML和CSS结合,搭建Render树(渲染树)

将每个 HTML 节点与其对应的 CSS 样式结合,搭建 Render 树

  1. 根据渲染树计算布局

根据已经生成好的 Render 树 ,计算每个节点的颜色、尺寸及位置等信息

  1. 将元素绘制到页面上

将计算好的节点绘制到页面上,这个过程可能会产生 重绘 和 重排(回流),要尽量避免回流

注意:

CSS 不会阻塞 DOM 树 的搭建,但是会阻塞页面的渲染,这是因为页面渲染需要先计算好节点的样式

HTML 文件中的外部资源会提前加载,不会等到渲染完成后再加载

JS 会阻塞 HTML 的解析,因为浏览器不知道 JS 脚本的内容,但 JS 脚本有可能会操作 DOM ,为了避免重复渲染,浏览器会先加载 JS 脚本

CSS 会阻塞 JS 的执行,因此需要将

1、CSS哪些属性可以继承?哪些属性不可以继承?

可继承的样式:font-size、font-family、color、text-indent

不可继承的样式:border、padding、margin、width、height

2、CSS中 link 和@import 的区别是?

1、link属于HTML标签,而@import是CSS提供的;

2、页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;

3、import只在IE5以上才能识别,而link是HTML标签,无兼容问题;

4、 link方式的样式的权重 高于@import的权重

3、请列举几种清除浮动的方法

1、父级div定义 height x

2、结尾处加空div标签 clear:both x

3、父级div定义 伪类:after 和 zoom +

4、父级div定义 overflow:hidden +

5、父级div定义 overflow:auto x

4、盒子模型的理解

标准盒子模型 (content-box)

盒子总宽度 = width + padding + border + margin;

盒子总高度 = height + padding + border + margin

width/height 只是内容高度,不包含 padding 和 border值

IE 怪异盒子模型 (border-box)

盒子总宽度 = width + margin;

盒子总高度 = height + margin;

width/height 包含了 padding和 border值

5、画一条0.5px的线

采用transform: scale()的方式,该方法用来定义元素的2D 缩放转换(transform: scale(0.5,0.5);)

6、flex布局

采用flex布局的元素叫容器,他的子元素叫项目

容器的属性:

flex-direction:决定主轴的方向 row、row-reverse、 column、column-reverse

flex-wrap:轴线,nowrap不换行、wrap换行,第一行在上方、wrap-reverse

flex-flow:是flex-direction和flex-wrap属性的简写,默认是row nowrap

justify-content:决定项目在主轴上的对齐方式 flex-start、flex-end、center、space-between、space-around

align-items:定义项目在交叉轴上的对齐方式

flex-start、flex-end、center、baseline项目的第一行文字的基线对齐、stretch撑开

align-content:决定了多很轴线的对齐方式,如果只有一根轴线,该属性不起作用

flex-start、flex-end、center、space-between、space-around、stretch

项目的属性:

order:属性定义项目的排列顺序。数值越小,排列越靠前,默认为0

flex-wrap:属性定义项目的放大比例,默认为0,及如果存在剩余空间,也不放大

flex-shrink:项目的缩小比例,默认为1,如果空间不足,该项目将缩小

flex-basis:定义了在分配多余空间之前,项目占据的主轴空间

flex:flex-wrap、flex-shrink和flex-basis的简写,默认值是0 1 auto,后两个属性可选

align-self:允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。

默认为auto,表示继承父元素的align-items,如果没有父元素,则等同于stretch