搜索
前端知识
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 / children 适用父子组件通信
ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;
如果用在子组件上,引用就指向组件实例;
children:访问父/子实例
(3) EventBus(on / $off)适用于父子、隔代、兄弟组件通信
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
(4) listeners 适用于隔代组件通信
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.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({ 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、页面渲染
- 解析HTML,并搭建DOM树
浏览器接收到 html 文件后将其解析成 DOM 树,这个解析从接收到 html 文件 的时候就已经开始了,并不是等到接收完成后才开始,解析的过程是自上而下,先解析当前节点的所有子节点,再解析兄弟节点及其子节点
- 解析CSS,并搭建样式树
浏览器将所有的 css 包括其自身的样式全部解析成样式树,解析的过程中会自动去掉浏览器不能识别的样式
- 将HTML和CSS结合,搭建Render树(渲染树)
将每个 HTML 节点与其对应的 CSS 样式结合,搭建 Render 树
- 根据渲染树计算布局
根据已经生成好的 Render 树 ,计算每个节点的颜色、尺寸及位置等信息
- 将元素绘制到页面上
将计算好的节点绘制到页面上,这个过程可能会产生 重绘 和 重排(回流),要尽量避免回流
注意:
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