高频面试题

高频面试题

1.说说你对盒子模型的理解

当对一个文档进行布局(layout)的时候,浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型(CSS basic box model),将所有元素表示为一个个矩形的盒子(box)盒子由内外边距,内容和边框组成。

盒子分为标准盒子和怪异盒子

标准盒子:宽是由width+margin+padding+border,高是由height+margin+padding+border

怪异盒子:宽是由width+margin,高是由height+margin组成的。

2. 如何让一个盒子水平垂直居中,有哪些方法越多越好?

  • 利用文本居中text-align:center和行高:line-height 进行实现
  • 利用子绝父相和外边距margin实现
  • 利用flex布局实现
  • 利用定位
  • 利用margin:auto
  • 计算父盒子与子盒子的空间距离
  • 利用transform实现居中
  • 利用display:table-cell

3.说说javascript都有哪些数据类型,如何存储的?

js数据类型分为原始数据类型和(基本数据类型)和对象数据类型(引用数据类型)

基本数据类型:null、undefined、number、string、boolean、symbol

引用数据类型:object、array、function、date

基本数据类型存储在栈中,栈是有结构的,每个区块都是按照后进先出的方式次序存放,基本类型的数据相对是比较稳定的,占的内存也比较小,所有寻找速度比较快,如果基本类型复制的话,栈中重新开辟个新的内存空间来储存新复制的新值,所以两者是独立的,没有任何关联!

引用数据类型存储在堆中,堆是没有结构的,数据可以任意存放,引用类型的值是储存在堆中(heap),但是栈内存中保存着一个堆内存的对象的引用

栈:存储基本数据类型和指定代码的环境。

堆:存储引用类型值得空间。

注意:每个对象在堆中有一个引用地址,引用类型在栈中会保存其引用地址,以便快速查找到堆内存中的对象。

4.如何理解响应式,实现响应式的方法以及原理有哪些?有什么区别?

1、响应式设计

​ 是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台,屏幕尺寸,屏幕定向等)进行相应的响应和调整.

2.基本原理

​ 通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport

3.实现方式

  • 媒体查询
  • 百分比
  • vw/vh
  • rem

4.响应式布局的优缺点
优点:

​ 面对不同分辨率,灵活性强

​ 能够快捷解决多设备显示适应问题

缺点:

​ 仅适用布局、信息、框架并不复杂的部门类型网站

​ 兼容各种设备工作量大,效率低下

​ 代码累赘,会出现隐藏无用的元素,加载时间加长

​ 其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果

​ 一定程度上改变了网站原有的布局结构,会出现用户混淆的情况

5.Css性能优化有哪些常见的方法?具体如何实现?

异步加载css 文件压缩

除去无用的css

有效的使用选择器

减少昂贵的属性

排版与重绘

减少排版次数

不使用@import引入css

6.判断数据类型的方法有哪些?有什么区别?

Type of 可以对基本数据类型进行判断

Instanceof 判断是否在原型链上

Constructor 查看对象的原型

Object.prototype.tostring 默认返回调用者的具体类型

7.说说你对事件循环的理解

JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环,同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。

8.说说你对BOM的理解,BOM的核心都有哪些?作用是什么

BOM它是一个浏览器的一个对象模型,它指向的window的顶级对象,经常作为浏览器窗口的一些变化出现,比方说浏览器的前进、后退以及刷新使用。

BOM一共有5个对象分别为:history,location、navigator、screen、window

其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率,bom的核心对象是window,hash:url中#后面的字符串,没有返回空字符串 host:服务器名称和端口号 href:完整的url, port:端口号 search:字符串查询

9.Bind,call,apply有什么区别?如何实现一个bind方法?

call方法的第一个参数也是this的指向,后面传入的是一个参数列表跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

调用函数,第二个参数传入this指向,返回一个新的函数

通过fn.bing(obj,1,2)()可以实现bind改变this指向

10.如何理解闭包?闭包的应用场景是?

闭包就是有权访问另一个函数内部变量的函数。闭包产生的原因:内部函数存在对外部函数局部变量的引用就会导致闭包。

闭包的特性:1:函数套函数 2:内部函数可以直接访问外部函数的内部变量或参 3:变量或参数不会被垃圾回收机制回收

闭包的优点:1:变量长期驻扎在内存中2:避免全局变量的污染3:私有成员的存在

闭包的缺点:驻内存增大内存的使用量 使用不当会造成内存的泄露.

闭包应用场景:1.闭包解决索引值得问题2.函数防抖3.回调

函数中的局部变量在函数执行完后会被销毁,有时候,我们不希望这个局部变量会被销毁,我们还想在外部进行持续的操作和访问,我们就会用到闭包这种方式

11.说说你对同步和异步的区别的理解?

  • 同步:
    • 浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出0现,用户看到新内容,进行下一步操作
    • 代码从上往下依次执行,执行完当前代码,才能执行下面的代码。 (阻塞)
  • 异步
    • 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容
    • 代码从上往下依次执行,没执行完当前代码,也能执行下面的代码。 (非阻塞)

同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。

异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程

12.Css选择器有哪些?优先级是什么?哪些属性可以继承?

css的选择器分为:id选择器 class选择器 标签选择器 后代选择器 子选择器 相邻同胞选择器 群组选择器 伪类选择器

优先级:内联>id选择器>类选择器>标签选择器

可以继承的属性有:

字体系列属性(font-size,font-weight,color等)

  • 文本系列属性
  • 元素的显隐
  • 表格布局属性
  • 列表属性
  • 引用
  • 光标属性
  • 宽,高,行高等

13. 简单说一下什么是事件代理?

事件代理(Event Delegation),又称之为事件委托。是 JavaScript 中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。

使用事件代理的好处是可以提高性能:

  • ​ 可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒
  • ​ 可以实现当新增子对象时无需再次对其绑定

Js的数据流分为捕获阶段->目标阶段->冒泡阶段,事件委托就是在冒泡阶段执行的

14. 如何理解重绘和回流(重排)?什么场景下才能

重绘:当计算好盒模型的位置,大小以及其他属性后,浏览器会根据每个盒子进行绘制

回流(重排):布局引擎会根据各种样式计算每个盒子在页面上的大小与位置

重绘触发:颜色的修改 文本方向的修改 阴影的修改

回流(重排)的触发:添加或删除可见的dom 元素位置发生变化 元素的尺寸发生变化 内容发生变化 页面首次渲染 浏览器视口变化

回流一定触发重绘,但重绘不一定会触发回流

15. 什么是防抖和节流,有什么区别?如何实现?

(1)节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

function throttled1(fn, delay = 500) {
    let oldtime = Date.now()
    return function (...args) {
        let newtime = Date.now()
        if (newtime - oldtime >= delay) {
            fn.apply(null, args)
            oldtime = Date.now()
        }
    }
}

节流场景:

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

(2)防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

function debounce(func, wait) {
    let timeout;
    return function () {
        let context = this; // 保存this指向
        let args = arguments; // 拿到event对象
    	clearTimeout(timeout)
    	timeout = setTimeout(function(){
        	func.apply(context, args)
    	}, wait);
	}
}

防抖场景:

  • search搜索联想,用户在不断输入值时,用防抖来节约请求资源;
  • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

总结:

  • 函数防抖和函数节流都是防止某一时间频繁触发,但原理不一样。
  • 函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。

16.说说你对作用域链的理解?

当对象在查找某一个属性的时候,会先在当前作用域下去查找这个属性,如果没有找到 的话就会去上一个作用域下面去查找,如果还没有找到的话,就以此类推的去再上一个 里面去查找,直到查找到window的顶级对象还没有找到的话就会报错,或者是这个变 量时一个全局的一个隐式变量

17. 说说你对原型和原型链的理解?

原型分为显示原型和隐式原型

显示原型:每个函数身上都有一个 prototype 属性 (显示原型属性),函数都是由new Function 产生的包括他本身,每个构造函数身上都有一个 prototype 属性,对应的值是原型对象object (是由 new obiect所产生的)

隐式原型: 属性是_proto_,每一个实例对象身上都有一个_proto_属性。

实例对象的隐式原型指向其构造函数的显示原型

**原型链:**当一个对象调用的属性或者方法不存在的时候,就在实例的本身去找,找到后返回,没有找到继续去实例对象的原型对象上找。一直找到原型链的最顶端,直到找到属性或者方法,找不到返回 undefined。原型链的最顶端是 object.prototype。

原型链的最顶端:object.prototype

18. Vue的生命周期和含义有哪些?

Vue的生命周期四个阶段:创建阶段、挂载阶段、更新阶段、销毁阶段

创建阶段:

(1)beforeCreate: 创建前阶段,这个时候还不能使用data中的数据

(2)created: 创建完成阶段,最早可以使用data中的数据

挂载阶段:

(1)beforeMount: 挂载前阶段,相关的 render 函数首次被调用

(2)mounted: 挂载完成阶段,DOM节点挂载到实例上去之后调用

更新阶段:

(1) beforeUpdate: 更新前阶段,发生在虚拟 DOM 重新渲染和打补丁之前

(2) updated: 更新完成阶段,DOM更新完成后调用

销毁阶段:

(1) beforeDestroy: 销毁前阶段,实例销毁之前调用,在这里,实例仍然完全可用

(2) destroyed: 销毁完成阶段,实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定Vue

19. Vue自定义指令的钩子函数有哪些?

  • bind:当指令绑定到元素上时触发,只执行一次,可以做一些初始化的操作。
  • inserted:当绑定指令的元素插入到父节点时触发。
  • update:绑定指令的组件的vNode更新的时候触发。
  • componentUpdate:绑定指令的组件的vNode及子vNode更新的时候触发。
  • unbind: 当指令与元素解绑时触发。

20.Javascript本地存储有哪些?区别和使用场景?

本地存储方式有:cookie、sessionStorage、localStorage、indexDB

区别

存储大小:cookie一般为4kb比较小,sessionStorage、localStorage一般为5MB比较 大,indexDB一般存特别大的数据的时候使用

存储方式:cookie是在过期之前退出浏览器后就会消失,localStorage存储进去以后就 会一直存在在浏览器上面,退出浏览器以后还是会存在的。sessionStorage不管你到没 到过期的时间只要你退出浏览器后就会消失

应用场景:

Cookie:用户的标记跟踪的时候使用

localStorage:用于需要长期保存数据的时候使用

sessionStorage:用与比较敏感或者一次登录验证的时候使用

indexDB:存放超级大文本的时候使用

21.请简单叙述Vue2和Vue3的区别和变化至少说6点

  1. 双向数据绑定的方式不同

    vue2是采用ES5的object.definePropert()对数据进行劫持,结合发布订阅和观察者模式进行的

    ​ vue3是采用ES6的Proxy的数据代理来对数据进行代理,修复了v2中对象和数组的属性添加修改的问题

  2. 根节点数量不同

    ​ vue2中根节点只能有一个

    ​ vue3中可以有多个根节点,解决了多个div嵌套的问题

  3. vue3中增加了Composition API ,在script标签上添加setup 或者调用setup()函数

    ​ vue2中只有optiosAPI

  4. 生命周期钩子少许变化

    ​ vue2中的destoryed钩子在vue3中为unmounted

  5. 组件传值不太一样

    ​ vue3中在子组件中使用emits拦截事件,props拦截属性;

    ​ vue2中使用 e m i t ( ) 派发事件,父组件使用 emit()派发事件,父组件使用 emit()派发事件,父组件使用on监听,

  6. 定义全局变量的方法不一样

    ​ vue2中使用Vue.prototype.$http = axios

    ​ vue3中使用app.config.globalProperties.$http = axios

  7. 创建vue实例的方式不一样

    ​ vue2中3使用new Vue()的方式,来创建实例

    ​ vue3中使用createApp()方法来创建实例

  8. 插槽的写法不一样

    ​ vue2中父组件中使用 slot-scope=“”

    ​ vue3中使用v-slot=“” 或者#代替

  9. vue3中新增了teleport穿梭组件,实现组件的穿梭;比如dialog遮罩层可以直接挂到body上

  10. vue3中移除了filter过滤器

    ​ 官方建议直接使用计算属性或者方法调用来实现过滤

  11. vue3中移除了$childern属性

    ​ 不可以使用 c h i l d e r n 来获取子组件,而建议使用 r e f 和 t h i s . childern来获取子组件,而建议使用ref和this. childern来获取子组件,而建议使用refthis.refs来获取子组件上的属性和方法

  12. v-if和v-for优先级

    ​ 在v2中如果同时使用v-for 和 v-if 那么v-for的优先级是高于 v-if 的

    ​ v3中v-if 始终高于 v-for但是还是不建议一起使用

  13. vue3中移除了 .native 修饰符

22.Vue3中组件通信的方法有些,流程是什么?

  1. props传值

    ​ props适用于父传子,有两种写法,混合写法和纯vue3写法(语法糖)

  2. attrs传值(父传子)–attrs包含了父作用域里除 class 和 style 除外的非props 属性集合

  3. expose/ref (子传父)–父组件获取子组件的属性或者调用子组件方法

  4. v-model --支持多个数据双向绑定

  5. $emit --在 < template > 中使用的 $emit 方法不能在组件的 < script setup > 部分中使用。组件要触发的事件可以显式地通过 defineEmits() 宏来声明。

  6. provide / inject(跨代传值)

    ​ provide: 提供一个值,可以被后代组件注入。
    ​ inject: 注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。

  7. mitt --Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus

  8. vuex / pinia(跨代传值)

父子通信:在父组件的子组件上使用自定义属性,在子组件中使用props来接受、

子父通信:通过定义自定义事件,在子组件中使用$emit来触发该事件,进行通信、

兄弟通信:使用 e m i t 发送自定义事件,使用 emit发送自定义事件,使用 emit发送自定义事件,使用on来接受自定义的事件、

祖孙通信:使用inject和provide:通过在外部组件中定义procide传递属性,使用inject来接受属性、

全局通信:定义全局的数据使用vuex全局状态管理系统,可以吧store挂载到vue原型上,在vuex的state中定义全局的状态使用this.$store.state.属性访问

23. 对前端工程师这个职位是怎么样理解的?它的前景会怎么样

  1. 前端是最贴近用户的程序员,比后端、数据库、产品经理、运营、安全都近

    ​ 实现界面交互
    ​ 提升用户体验
    ​ 基于NodeJS,可跨平台开发

  2. 前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好,

  3. 与团队成员,UI设计,产品经理的沟通;

  4. 做好的页面结构,页面重构和用户体验;

前景:首先,在我看来,一切和用户交互的终端都可以属于前端。并且随着现在跨端开发框架的兴起,比如Electron框架等,也使得前端的那套开发技术栈以及开发流程可以复制到桌面端来,使得前端的范畴越来越广泛。
并且,随着AR,VR技术的兴起,手机app中应用了大量的3维场景来提高用户体验,比如手机app上看房,看车,甚至是看一个城市的街景,都已经有了3D的场景,并且用户还能进行简单的操作。而这些都对前端提出了更高的要求

24.请叙述Vue2和Vue3数据响应式原理的不同?

Vue2响应式原理

Vue2的响应式原理就是在js下的原生的object.definproty,通过改变数据来触发林里面的get和set方法,在通过消息订阅预发布的形式达到数据与视图的同步更新

​ 实现原理:

  • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
  • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

​ 存在问题:

  • 当对象中属性过多时Object.defineProperty()需针对每个属性进行遍历实现响应式,效率不高;
  • 新增属性、删除属性, 界面不会更新;
  • 只有configurable为true时候,该属性才能从对应的对象上被删除,但源数据不会响应删除;
  • 直接通过下标修改数组, 界面不会自动更新。

Vue3响应式原理

Vue3则采用了ES6的Proxy来实现数据劫持。通过创建一个代理对象,可以监听到对象属性的访问和修改,可以监听到数组下标的变化以及新增属性的变化。同时,Vue3还使用了WeakMap来进行依赖收集,比Vue2中使用的基于数组的依赖收集方式更加高效

​ 实现原理:

  • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
  • 通过Reflect(反射): 对源对象的属性进行操作。

25. 请叙述Vue2和Vue3的diff算法的区别?

  1. Vue2使用双向指针来进行虚拟DOM的比较,而Vue3则使用了单向链表的方式。
  2. 在计算key值不同时,Vue2会采用首尾两端比较的方法,而Vue3则采用了更高效的“Map”数据结构。
  3. 在节点移动时,Vue2通过splice函数进行数组操作,而Vue3则采用了更轻量级的移动节点算法。
  4. Vue3还增加了一种新的优化方式——静态提升,它可以将静态节点在编译阶段提前处理,避免在运行时进行比较。

总体来说,Vue3的diff算法相比Vue2更加高效,并且新增的静态提升优化方式可以进一步提升渲染性能。

26.Vue3中的生命周期函数的变化以及含义

创建阶段:

beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

​ 用途:通常在这个阶段可以用来进行一些初始的数据操作,比如对 data 中的数据进行修改。

created:实例创建完成后被立即调用。

​ 用途:通常在这个阶段可以用来进行一些数据的异步请求操作,比如请求后端接口获取数据。

挂载阶段:

beforeMount:在挂载开始之前被调用。

​ 用途:通常在这个阶段可以用来进行一些 DOM 操作,比如获取 DOM 元素进行一些操作。

mounted:实例挂载之后被调用。

​ 用途:通常在这个阶段可以用来进行一些 DOM 操作,比如使用 jQuery 对 DOM 元素进行一些操作。

更新阶段:

beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。

​ 用途:通常在这个阶段可以用来进行一些数据更新之前的操作,比如获取新的数据并进行一些操作。

updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

​ 用途:通常在这个阶段可以用来进行一些数据更新之后的操作,比如获取更新后DOM 元素进行一些操作。

销毁阶段:

beforeUnmount:实例销毁之前调用。

​ 用途:通常在这个阶段可以用来进行一些清理操作,比如清除定时器。

unmounted:实例销毁后调用。

​ 用途:通常在这个阶段可以用来进行一些清理操作,比如释放内存。

27.vue3中自定义指令生命周期的变化及含义

  • created : 在绑定元素的 attribute 或事件监听器被应用之前调用。在指令需要附加在普通的v-on事件监听器调用前的事件监听器中时,这很有用。
  • beforeMount :当指令第一次绑定到元素并且在挂载父组件之前调用。
  • mounted : 在绑定元素的父组件被挂载前调用
  • beforeUpdate :在更新包含组件的 VNode 之前调用
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用
  • beforeUnmount : 在卸载绑定元素的父组件之前调用
  • unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次

28. Vue3中的组合式Api有哪些? 和Vue2的Options Api又什么不同?

将同一逻辑关注点相关的代码收集到一起,这就是组合式API(composition-api)

  1. setup

    1. setup的作用:setup是一个函数,提供了组合式api的入口
    2. 执行时机:
      1. setup函数是在berforeCreate这个钩子函数之前执行,props属性解析之后执行\
      2. 在setup函数中是不能使用this的
    3. 两个参数
      1. props:获取props属性中的值的
      2. context:是一个对象,里面包含了vue实例对象创建之前的所有属性
  2. ref

    1. ref 作用 :在setup中实现数据的响应式
    2. ref基本语法:如果想要在 setup 函数中操作通过 ref 函数创建出来的值,必须要加一个 .value
  3. reactive

    1. refreactive的区别

      1. ref可以创建任何数据类型的响应式对象;reactive仅仅能创建对象类型(对象、数组和 Map 、Set这样的集合类型)的响应式对象;
      2. ref如果传递的是基本数据类型的数据,返回的是响应式数据;reactive如果传递的是基本数据类型的数据,会报错。基础类型数据推荐适用ref函数,引用类型数据推荐适用reactive函数
      3. 通过ref创建出来的数据,操作的时候要加一个 .value ;但是reactive创建出来的数据不需要
    2. reactive基本使用

      1. import { defineComponent, reactive } from 'vue';
        export default defineComponent({
        	setup(props, context) { // 组合式api的入口
        		let obj = reactive({ num: 10 })
        		console.log(obj.num)
        		return {
        			obj
        		}
        	}
        })
        

        ref创建的数据会自动解包

  4. toRef

    1. 基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步:改变

      源属性的值将更新 ref 的值,反之亦然

  5. toRefs

    1. 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref

    2. 当从组合式函数中返回响应式对象时, toRefs 相当有用。使用它,消费者组件可以解构/展开返

      回的对象而不会失去响应性

    3. toRefs 在调用时只会为源对象上可以枚举的属性创建 ref。如果要为可能还不存在的属性创建

      ref,请改用 toRef

      二者的区别在于:toRef是指定某一节点提取出来,toRefs是一次性将所有节点提取出来。但toRefs只能提取一级节点!

      toRefs返回的变量修改,与原始值无任何响应式关联。

  6. 计算属性computed

  7. 监听属性watch

  8. watchEffect

    1. watchEffect和watch的区别

      1. watch 是懒执行的,即只有当监听的数据发生变化时才会执行回调; watchEffect 则不管监

        听的数据有没有发生变化都会执行一次回调函数

      2. watchEffect 可以自动追踪到依赖的数据,当依赖的数据发生变化时就会再次执行回调函数

不同:

  • 在逻辑组织和逻辑复用方面,Composition API是优于Options API
  • 因为Composition API几乎是函数,会有更好的类型推断。
  • Composition APItree-shaking 友好,代码也更容易压缩
  • Composition API中见不到this的使用,减少了this指向不明的情况
  • 如果是小型组件,可以继续使用Options API,也是十分友好的

29.对于MVVM的理解

MVVM 是 Model-View-ViewModel 的缩写

  • **Model:**代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
  • View: 代表UI 组件,它负责将数据模型转化成UI 展现出来。
  • ViewModel: 监听数据模型的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。

在MVVM架构下,View 和 Model 之间并没有直接的联系

而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的,

因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,

而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,

因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,

复杂的数据状态维护完全由 MVVM 来统一管理。

双向绑定的原理

​ vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变,
​ vue双向数据绑定,其核心是 Object.defineProperty()方法,给Vue中的数据绑定get和set方法,当获取数据的时候,调用get方法,修改data中的数据的时候调用set方法,通过watcher监听器去更新视图,完成数据的双向绑定。

30.请详细说下你对vue生命周期的理解

Vue2和vue3的生命周期是不一样的,vue3把vue2的挂载阶段改成了setup(),更新阶段前面都加了on,比如onmounted,onbeforedistpry,卸载阶段也进行了相应的更新

31.Vue组件间的数据传递

Vue2和vue3都能使用props传值,需要在传值的地方写上:,一般在父组件中写,传值的时候要先定义一个名称,方便子组件接受,vue3还提供了provide和inject,这都在setup里面写,同样也得先传入一个自己拟定的变量名,方便子组件接受,还有消息订阅与发布,

还可以把数据都存入vuex中,实现组件之间的数据共享

32. Vue的路由实现:hash模式 和 history模式原理

Vue 的路由实现有两种模式:hash 模式和 history 模式。

Hash 模式:
Hash 模式是通过改变 URL 中的 hash(#)来实现路由的。比如,当访问的 URL 是 http://localhost:8000/#/home 时,就会渲染出 Home 组件。

在 Hash 模式下,Vue 会监听 window 对象的 hashchange 事件,一旦 URL 中的 hash 发生改变,就会重新渲染对应的组件。因为 hash 的改变不会触发浏览器向服务器发送请求,所以 Hash 模式的路由是纯客户端实现的,可以在不需要服务器支持的情况下进行部署。

History 模式:
History 模式是通过改变 URL 中的 path 来实现路由的。比如,当访问的 URL 是 http://localhost:8000/home 时,就会渲染出 Home 组件。

在 History 模式下,Vue 会监听 window 对象的 popstate 事件,一旦 URL 中的 path 发生改变,就会重新渲染对应的组件。因为 path 的改变会触发浏览器向服务器发送请求,所以 History 模式的路由需要服务器支持,即需要在服务器端配置一个捕获所有路径的候选资源,然后在所有资源返回 404 的情况下返回 index.html 页面,从而实现路由。

总的来说,Hash 模式和 History 模式的实现原理都是通过监听 URL 的变化来实现路由的。两者的区别在于 URL 中的标识符不同,以及是否需要服务器支持。Hash 模式的路由是纯客户端实现的,可以在不需要服务器支持的情况下进行部署;而 History 模式的路由需要服务器支持,需要在服务器端配置一个捕获所有路径的候选资源,并返回 index.html 页面,从而实现路由

33.vue路由的钩子函数

Vue路由提供了多个钩子函数,可以用于在路由切换的不同阶段执行相应的操作。以下是Vue路由中常用的钩子函数:

  1. beforeEach: 在路由切换开始之前执行,可以用来进行权限控制或者全局拦截等操作。
  2. beforeResolve: 在路由解析完毕之前执行,也就是在所有异步组件被解析完毕之前执行。
  3. afterEach: 在路由切换完成之后执行,可以用来进行一些全局的数据清理或者动画效果等操作。
  4. beforeEnter: 在路由进入之前执行,可以用来进行路由独享的权限控制等操作。
  5. beforeRouteUpdate: 在当前路由被复用时执行,例如在同一个路由中切换参数时执行。
  6. beforeRouteLeave: 在路由离开之前执行,可以用来进行离开确认等操作。

34. v-if 和 v-show 区别

V-if是通过DOM结点的添加或者删除来控制结点显示或者隐藏,

v-show是通过css样式来控制节点的显示或者隐藏,

v-if的切换频率较低的场景,不展示的DOM元素直接被删除,

v-show的切换频率较高的场景,不展示的DOM元素未被移除,仅仅是使用样式隐藏掉。

使用v-if时,元素可能无法获取到,但v-show一定能获取到

35. r o u t e 和 route和 routerouter的区别

l、$router是VueRouter的实例方法,可以认为是全局的路由对象,包含了所有路由的对象和属性

2、$route是一个跳转的路由对象,可以认为是当前组件的路由管理,指当前激活的路由对象,包含当前url解析得到的数据,可以从对象里获取一些数据。如name, path等

36.如何让CSS只在当前组件中起作用?

当前组件 < style >写成< style scoped>,,这个参数的作用就是让css只在当前组件中起作用,如果不加的话,就相当于引入全局样式了

37.keep-alive-keep-alive-的作用是什么

<keep-alive></keep-alive> 是 Vue 内置组件,用于缓存组件的实例,从而避免多次创建和销毁组件的开销。当包裹动态组件时,<keep-alive> 会在组件切换时保留该组件的状态,而不是重新渲染该组件。常见的用法是将需要缓存的组件包裹在 <keep-alive> 标签中

38.-在vue中使用插件的步骤

采用ES6import ... from ...语法或CommonJSrequire()方法引入插件
使用全局方法Vue.use( plugin )使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })

39.请列举出3个vue中常用的生命周期钩子函数

  1. created: 实例已经创建完成之后调用,在这一步,实例已经完成数据观测, 属性和方法的运算, watch/event事件回调. 然而, 挂载阶段还没有开始, $el属性目前还不可见
  2. mounted: el被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted被调用时 vm.$el 也在文档内。
  3. activated: keep-alive组件激活时调用

40.什么是Vue SSR

vue官网上对此ssr的定义:Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。

服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。

**通俗解释:**vue的组件是基于vnode的,整个html结构用js的vnode对象树来表达,那么服务端可以通过解析js对象树,在服务端提前生成具有实际表达作用的html字符串,在客户端(浏览器中)每次数据变化的时候通过新旧vnode对象树的对比用diff算法(vue diff算法不了解的可以去搜索一下)去寻找更新最小最优的变化集合,然后再去更新实际的dom。

关键点: 代码可以在客户端运行,也可以在服务端运行,服务端渲染通俗来说就是先在服务端运行,在服务端生成html结构并返回给客户端,接下里继续由客户端代码去完成交互。

解决的问题:

​ seo:搜索引擎的优先爬取级别是页面的html结构,当我们使用ssr的时候,服务端已经生成了与业务相关联的html,这样的信息对于seo是很友好的。

​ 内容呈现:客户端无需等待所有的js文件加载完成即可看见渲染的业务相关视图(压力来到了服务端这边,这也是需要做权衡的地方,需要区分哪些由服务端渲染,哪些可以交给客户端)。

相关的弊端:

​ 代码兼容:对于开发人员来讲,需要去兼容代码在不同环境的运行,vue ssr所需要的服务端环境是node,有一些客户端的对象,比如dom,windows之类的则无法使用。

服务器负载:相对于前后端分离模式下服务器只需要提供静态资源来说,ssr需要的服务器负载更大,所以在项目中使用ssr模式要慎重,比如一整套图表页面,相对于服务端渲染,可能用户不会在乎初始加载的前几秒,可以交由客户端使用类似于骨架屏,或者懒加载之类的提升用户体验。

41.Proxy 相比于 defineProperty 的优势

对于普通数据类型一般来说可使用defineproperty,但是对于复杂的数据类型比如说,数组,或者对象这类的引用数据类型来说,就要使用proxy,还有就是使用defineproperty来说无法检测数据的改变,如果想要修改数据的话还需要用到原生的$set等方法,修改完后页面的数据才会发生改变,但对于proxy来说不会发生这样的情况

42.vuex是什么?怎么使用?哪种功能场景使用它

Vuex就是要实现全局的组件实现组件之间的一个共享状态,一个组件更新之后,其他组件也能接受到一个更新的值,先下载vuex,在main,js中全局导入app.use,场景:就是发现有很多组件都用到某个属性或者方法,就可以存入到vuex中,store就是用来存储的,action就相当于执行的方法,这个里面写的是所要执行的函数,在通过dispatch的形式是各个组件都能拿到

43.Vue2.x 响应式原理

Vue2的响应式原理就是在js下的原生的object.definproty,通过改变数据来触发林里面的get和set方法,在通过消息订阅预发布的形式达到数据与视图的同步更新

44.ES5、ES6和ES2015有什么区别

三者区别:

ES2015特指在2015年发布的新一代JS语言标准,ES2015可以理解为ES5和ES6的时间分界线

ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。

ES5泛指上一代语言标准。

ES6新增特性:

let const 定义块级作用域
箭头函数
解构赋值
扩展运算符
常见的数组的方法,伪数组
模板字符串
class类
参数设置默认值
promise
for…of for…in

45.babel是什么,有什么作用?

Babel 是 JavaScript 编译器:他能让开发者在开发过程中,直接使用各类方言(如 TS、Flow、JSX)或新的语法特性,而不需要考虑运行环境,因为Babel可以做到按需转换为低版本支持的代码;Babel内部原理是将 JS 代码转换为 AST,对 AST 应用各种插件进行处理,最终输出编译后的 JS 代码。

Babel 编译流程:

  1. 解析阶段:Babel 默认使用 @babel/parser将代码转换为AST。解析一般分为两个阶段:词法分析和语法分析
    1. 词法分析:对输入的字符序列做标记化(tokenization)操作。
    2. 语法分析:处理标记与标记之间的关系,最终形成一颗完整的 AST 结构。
  2. 转换阶段:Babel 使用 @babel/traverse 提供的方法对 AST 进行深度优先遍历,调用插件对关注节点的处理函数,按需对 AST 节点进行增删改操作
  3. 生成阶段:Babel默认使用 @babel/generator 将上一阶段处理后的 AST 转换为代码字符串

46.let有什么用,有了var为什么还要用let

var是全局声明,let是块级作用的,只适用于当前代码块

var变量会发生变量提升,let则不会进行变量提升

var 会造成重复赋值,循环里的赋值可能会造成变量泄露至全局

let在一个块级作用只能赋一次值,并进行当前代码块的锁区,就是说当前块只有let声明的这个变量是有用的

let在一个块级内,只能声明一个一个相同的变量名

47.举一些ES6对String字符串类型做的常用升级优化?

优化部分:

ES6新增了字符串模板,在拼接大段字符串时,用反引号(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串看起来更加直观、优雅。

ES6模板字符串,允许换行和空格,读写性强

升级部分:

ES6在String原型上新增了includes()方法,用于取代传统只能用indexOf查找包含字符串的方法(indexOf返回-1表示没查到,不如includes()返回false更明确,语义更清晰),此外还新增了startsWith()、endsWith()、padStarts()、padEnd()、repeat()等方法,可更加方便的用于查找、补全字符串

48.举一些ES6对Array数组类型做的常用升级优化

优化部分:

数组的解构赋值

ES6可以直接以下形式进行变量赋值

在声明较多变量时,不需要再写很多let(或var),且映射关系清晰,支持赋默认值。

扩展运算符

ES6新增的扩展运算符(…),可以轻松的实现数组和松散序列(比如集合等)的相互转换,可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。(尤其是在ES5即传统js中,arguments不是一个真正的数组,而是一个类数组的对象,但是扩展运算符的逆运算却可以返回一个真正的数组)。扩展运算符还可以轻松实现数组的复制和解构。

升级部分:

ES6在Array原型上新增了find()方法,用于取代传统只能indexOf()查找数组项目的方法,且修复了indexOf查找不到NaN的bug

此外,还新增了copyWithin()、includes()、fill()、flat()等方法,可方便用于数组的查找,补全,和转换等。

49.说说你对Event Loop的理解?

事件循环:在js运行环境中是单线程的,遇到异步任务会阻塞,,事件循环通过判断同步异步任务放入到相对应的执行站中执行,依次的循环执行下去就形成了事件循环。

50. 浏览器的内核都有哪些,什么区别?

浏览器内核是指浏览器用来解析和渲染Web页面的核心组件,它是浏览器的重要组成部分,直接影响着浏览器的性能和兼容性。常见的浏览器内核主要有以下几种:

  • Trident(Trident Engine):Trident是微软开发的浏览器内核,被用于Internet Explorer浏览器。它的特点是渲染速度较快,但对标准的支持较差,不够规范。
  • Gecko(Gecko Engine):Gecko是Mozilla基金会开发的浏览器内核,被用于Firefox浏览器。它的特点是标准支持度高,但对于低端设备性能较差。
  • WebKit(WebKit Engine):WebKit是苹果公司开发的浏览器内核,被用于Safari浏览器、Chrome浏览器的早期版本和一些其他浏览器。它的特点是性能优异,但对标准的支持度较差。
  • Blink(Blink Engine):Blink是Google开发的浏览器内核,是在WebKit基础上开发的,被用于Chrome浏览器和Opera浏览器等。它的特点是性能较好,对标准的支持度也比较高。
  • EdgeHTML(EdgeHTML Engine):EdgeHTML是微软开发的浏览器内核,被用于Edge浏览器。它的特点是对标准的支持度较好,性能也比较出色。

这些浏览器内核之间的区别主要在于它们的开发者和开发宗旨不同,以及在对标准的支持度、性能和兼容性方面有所不同。对于Web开发人员来说,了解不同浏览器内核的特点和差异,可以更好地优化和兼容Web页面,提高页面的性能和用户体验。

51.说说浏览器的渐进增强和优雅降级的区别?

渐进增强可以理解为向上兼容,一开始针对较为低版本的浏览器来构建页面,保证页面的所有基本的功能点都能实现;然后根据更高版本的浏览器设计一些在用户体验上更为良好的交互界面、追加更多的功能。

优雅降级可以理解为向下兼容,一开始就对高版本的浏览器构建功能、性能、体验都较为完美页面,然后针对低版本的浏览器进行兼容补充。

两者的区别在于:渐进增强属于从基础的页面中增加更多的功能(加);优雅降级是属于从功能丰富的页面上慢慢地减少页面的功能、用户的体验等等。

52. 网站性能优化的方案都有哪些?

  1. 尽量减少HTTP请求次数
  2. 延迟加载内容
  3. 使用离线缓存
  4. CSS、JS放置正确位置
  5. 静态资源压缩
  6. 静态资源使用多个域名
  7. 静态资源使用cdn存储
  8. 预加载
  9. DOM操作优化
  10. 优化算法

53.Link和@import之间有什么区别?

本质的差别link 属于 XHTML 标签,而 @import 完全是 CSS 提供的一种方式。

加载顺序的差别: 当一个页面被加载的时候(就是被浏览者浏览的时候) ,link 引用的 CSS 会同时被加载,而 @import 引用的 CSS 会等到页面全部被下载完再被加载。所以有时候浏览 @import 加载 CSS 的页面时开始会没有样式(就是闪烁),网速慢的时候还挺明显。

兼容性的差别: @import 是 CSS2.1 提出的,所以老的浏览器不支持,@import 只有在 IE5 以上的才能识别,而 link 标签无此问

使用 dom控制样式时的差别:当使用 javascript 控制 dom 去改变样式的时候,只能使用 link 标签,因为@import 不是 dom 可以控制的。

54. null,undefined 的区别

他们的数据类型不一样:null的数据类型为object、而undefined为undefined

他们相等于但是不恒等于,null定义的数据表示数据为空

总结来说,undefined 表示的是变量未定义或未初始化,而 null 表示变量的值为空。 需要注意的是,在条件判断时,null==undefined 返回 true,但它们的数据类型不同,所以 null === undefined 返回 false。

55.说说css中元素脱离文档流的方式有哪些?定位的方式有哪些以及区别?

元素脱离文档流的方式有以下几种:

  • position: absolute:将元素从文档流中移除,相对于最近的已定位祖先元素定位。
  • position: fixed:将元素从文档流中移除,相对于浏览器窗口定位。
  • float:将元素从文档流中移除,允许文本和行内元素环绕它。

定位的方式有以下几种:

  • position: static:默认值,元素正常的文档流定位方式,不会受到 top、bottom、left、right 等属性的影响。
  • position: relative:相对定位,元素在正常的文档流中,相对于自己原来的位置进行定位,不会影响其他元素的位置。
  • position: absolute:绝对定位,元素脱离文档流,相对于最近的已定位祖先元素定位,如果没有已定位的祖先元素,则相对于 html 元素定位。
  • position: fixed:固定定位,元素脱离文档流,相对于浏览器窗口进行定位。
  • position: sticky:粘性定位,元素在跨越特定阈值前为相对定位,之后为固定定位。

相对定位和绝对定位的区别在于,相对定位是相对于元素原来的位置进行定位,不会影响其他元素的位置,而绝对定位是相对于最近的已定位祖先元素进行定位。

固定定位和绝对定位的区别在于,固定定位是相对于浏览器窗口进行定位,不会随着滚动而移动,而绝对定位是相对于最近的已定位祖先元素进行定位,如果没有已定位的祖先元素,则相对于 html 元素定位。

56.伪类和伪元素的区别有哪 些? Css3新增了哪些选择器

  1. 伪类本质上是为了弥补常规CSS选择器的不足,以便获取到更多信息;
  2. 伪元素本质上是创建了一个有内容的虚拟容器;
  3. CSS3中伪类和伪元素的语法不同;
  4. 可以同时使用多个伪类,而只能同时使用一个伪元素;

CSS3 新增了很多选择器,其中一些比较常用的包括:

  • :nth-child(n)选择器可以选中父元素下的第n个子元素,例如:nth-child(3)可以选中父元素下的第3个子元素。
  • :not(selector)选择器可以排除某些元素,例如:not(.class)可以选中除了具有class类名的元素以外的所有元素。
  • :first-child选择器可以选中父元素下的第一个子元素,例如:p:first-child可以选中父元素下的第一个p元素。
  • :last-child选择器可以选中父元素下的最后一个子元素,例如:p:last-child可以选中父元素下的最后一个p元素。
  • :before伪元素可以在元素内容前插入一些内容,例如:p::before { content: “前缀” }可以在每个p元素前插入一个“前缀”文本。

57. 说说Promise和async/await的区别是?

Promise是原生的解决异步代码的对象,promise中有三个状态分别是pedding等待中、rejected失败、resolve成功,根据三个状态可以拿到我们的异步任务执行的结果,其中通过链式的.then回调方法中操作。

Async/await是基于promise封装的解决异步编程带来的回调地狱的终极方案,当我们呢在有很多的异步任务相互嵌套执行时就会出现,无限的层级嵌套,代码相当不清晰,async和await的出翔解决了这个问题。

58.Javascript如何实现继承

1.原型链继承

​ 让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。

​ 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

优点:写法方便简洁,容易理解。

缺点:对象实例共享所有继承的属性和方法。传教子类型实例的时候,不能传递参数,因为这个对象是一次性创建的(没办法定制化)。

2.借用构造函数继承

在子类型构造函数的内部调用父类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上。

优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。

缺点:借用构造函数的缺点是方法都在构造函数中定义,因此无法实现函数复用。在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。

3.组合继承(经典继承)

原型链借用构造函数 的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性

优点: 解决了原型链继承和借用构造函数继承造成的影响。

缺点: 无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部

4.原型式继承

方法一:

借用构造函数在一个函数A内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。

方法二:Object.create()
Object.create() 是把现有对象的属性,挂到新建对象的原型上,新建对象为空对象

ECMAScript 5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的函数A方法效果相同。

优点:不需要单独创建构造函数。

缺点:属性中包含的引用值始终会在相关对象间共享,子类实例不能向父类传参

5.寄生式继承

寄生式继承的思路与(寄生) 原型式继承[工厂模式] 似, 即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。

优点:写法简单,不需要单独创建构造函数。

缺点:通过寄生式继承给对象添加函数会导致函数难以重用。使用寄生式继承来为对象添加函数, 会由于不能做到函数复用而降低效率;这一点与构造函数模式类似.

6.寄生组合式继承

前面讲过,组合继承是常用的经典继承模式,不过,组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数;一次是在创建子类型的时候,一次是在子类型的构造函数内部。寄生组合继承就是为了降低父类构造函数的开销而实现的。

优点:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要,多余的属性。与此同时,原型链还能保持不变;

缺点:代码复杂

7.ES6、Class实现继承

原理ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。 ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

优点:语法简单易懂,操作更方便。

缺点:并不是所有的浏览器都支持class关键字 lass Per

59.说说什么是严格模式,限制都有哪些

严格模式:当我们在开发项目时,难免会有写的不规范的js代码,当我们开启严格模式后就会提示我们当前的代码有需要改进的地方,比如定义了一个未使用的变量。

定义未使用的变量或方法、严格使用双引号、等等

严格模式的限制:

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性,否则报错
  • 不能使用with语句
  • 不能对只读属性赋值,否则报错
  • 不能使用前缀 0 表示八进制数,否则报错
  • 不能删除不可删除的属性,否则报错
  • 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
  • eval不会在它的外层作用域引入变量
  • eval和arguments不能被重新赋值
  • arguments不会自动反映函数参数的变化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局对象
  • 不能使用fn.caller和fn.arguments获取函数调用的堆栈
  • 增加了保留字(比如protected、static和interface)

60.从A页面跳转到B页面,缓存A组件,从A组件跳转到C组件,取消缓存,如何实现?

在vue中我们可以使用keep-alive组件来实现组件缓存,当我们在路由表中定义了是否缓存的标识,就可以实现想要缓存的组件了。

为了实现针对性的缓存,我们需要使用到组件自带的includes属性,则个属性标识的是在这个数组中的组件讲会被缓存,有了这个属性我们再配合vuex和路由守卫,vuex来存储需要缓存的组件的名称,而路由守卫用于判断是具体从哪个页面进来的是否进行缓存等。

61.Vue是如何实现实现权限管理的,按钮级别权限如何实现?

Vue 实现权限管理一般需要从前端和后端两个方面考虑,前端主要是 UI 的控制和请求的发送,后端主要是数据的处理和权限校验。

在前端中,Vue 可以通过路由守卫来进行权限控制,比如在 beforeEach 钩子中判断当前用户是否有权限访问该路由,如果没有则跳转到指定的错误页面。另外,也可以使用自定义指令来控制按钮的显示和隐藏,根据用户的权限动态地添加或移除对应的指令。

在后端中,需要对用户的身份进行认证和鉴权,可以通过 session、token 或者 OAuth 等方式实现。一般情况下,用户的权限信息会存储在数据库中,需要在服务器端进行查询和校验。对于按钮级别的权限控制,可以在后端通过权限拦截器对请求进行拦截,根据用户的权限信息来判断是否允许进行操作。

需要注意的是,前端的权限控制只是一种辅助手段,真正的权限控制应该在后端进行,因为前端的代码可以被修改和篡改,容易被绕过。

62.详解Vue3和Vue2中watch的异同

Vue 2 中的 watch

Vue 2.x 中,watch 是一个非常重要的 API。它可以用来观察和响应 Vue 实例对象上的特定数据变化。如果数据变化,那么 watch 就会执行一个回调函数,这个回调函数可以用来更新视图或者执行其他的操作。

Vue 3 中的 watch

  1. 可以使用新的 API Mounting API 中的 watch 来进行监听。
  2. 可以接收一个 ref 对象或者 reactive 对象作为参数。
  3. 可以使用一个回调函数或者一个监听对象。
  4. 可以监听数组和对象的改变,并在修改的时候进行相应的计算。
  5. 可以使用异步队列来处理回调函数,这样可以避免不必要的计算。

相同点

它们都可以用来观察特定的数据变化,并执行相应的逻辑。另外,它们的用法也是类似的,都可以接受一个回调函数或者一个监听对象。

不同点

  • Vue 3 中的 watch 使用起来更加简单易懂。Vue 2 中的 watch API 需要传入两个参数,一个是要观察的数据,另一个是回调函数。而在 Vue 3 中,只需要传入要观察的数据即可,回调函数可以在watch 函数内部定义。这样的话,代码更加简洁,易于维护和测试。
  • Vue 3 中的 watch 具有更多的功能。Vue 3 中的 watch 可以接收一个配置对象,并支持多个监听器。除了可以监听简单的数据变化之外,Vue 3 中的 watch 还可以监听 props、data、computedVue 实例对象的属性变化,这使得 watch 功能更加强大、灵活。
  • Vue 3 中的 watch 在性能方面也有所提升。Vue 2 中的 watch 会在每次数据变化时都执行回调函数,这样会导致不必要的计算和渲染,从而影响页面性能。而在 Vue 3 中,watch 使用了 Proxy 对象,可以精确地跟踪修改过的数据,避免不必要的计算和渲染,提高了页面的性能。

63.pinia和vuex的区别以及Vuex 和 Pinia 的优缺点

Pinia和Vuex都是Vue.js状态管理库,但它们在一些方面有所不同。

Vuex 和 Pinia 的优缺点:

Pinia的优点:

  • 完整的 TypeScript 支持:与在 Vuex 中添加 TypeScript 相比,添加 TypeScript 更容易
  • 极其轻巧(体积约 1KB)
  • store 的 action 被调度为常规的函数调用,而不是使用 dispatch 方法或 MapAction 辅助函数,这在 Vuex 中很常见
  • 支持多个Store
  • 支持 Vue devtools、SSR 和 webpack 代码拆分

Pinia的缺点:

  • 不支持时间旅行和编辑等调试功能

Vuex的优点

  • 支持调试功能,如时间旅行和编辑
  • 适用于大型、高复杂度的Vue.js项目

Vuex的缺点

  • 从 Vue 3 开始,getter 的结果不会像计算属性那样缓存
  • Vuex 4有一些与类型安全相关的问题

区别:

  1. pinia一个轻量级的状态管理库,它专注于提供一个简单的API来管理应用程序的状态。相比之下,Vuex是一个更完整的状态管理库,它提供了更多的功能,比如模块化、插件和严格模式等。

  2. pinia它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据

  3. pinia他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦一点

  4. pinia语法上比vuex更容易理解和使用,灵活。

  5. pinia没有modules配置,没一个独立的仓库都是definStore生成出来的

  6. pinia支持初始化工具,vuex不支持

  7. pinia state是一个对象返回一个对象和组件的data是一样的语法

64.vue路由原理

router-view组件;
通过Vue.observable在router实例上创建一个保存当前路由的监控对象current,
当浏览器地址变化的时候,改变监控对象current;
在router-view组建中监听监控对象current的变化,当current变化后,获取用户注册的相应component,并利用h函数将component渲染成vnodes,进而更新页面视图

hash模式:
它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,因此改变 hash 不会重新加载页面
但是会触发 onhashchange 事件,所以我们可以监听,然后渲染自己要渲染的组件,达到路由的效果

history模式:
通过 HTML5 中新增的 pushState() replaceState() 方法
应用于浏览器的历史记录,在已有的 go(),back(),forward() 的基础之上,它们提供了对历史记录进行修改的功能
当它们执行修改时,虽然改变了当前的 URL,但你浏览器不会立即向后端发送请求
我们可以通过 onpopstate 事件,监听 history 的变化,然后渲染自己要渲染的组件,达到路由的效果

65.Vue nextTick 原理

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

66.计算属性和methods的区别

1.计算属性是有缓存的,只有当它依赖的数据发生变化的时候才重新渲染,函数只要调用就会去执行
2.计算属性本质上是一个属性,必须要返回一个结果,函数就是一个函数,可以没有返回值
3.计算属性只能获取值,但是不能设置值

67.计算属性和watch的区别

1、computed擅长处理的场景: 一个数据受多个数据影响; watch擅长处理的场景: 一个数据影响多个数据.
2、功能上: computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
3、是否调用缓存:computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作。
4、是否调用return: computed中的函数必须要用return返回,watch中的函数不是必须要用retumn.
5、computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化;而watch支持异步。
6、computed默认第一次载的时候就开始监听,watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true (immediate:true)

68.webpack和vite区别

1.底层的语言

webpack是基于nodejs构建,js是以毫秒计数。
vite是基于esbulid预构建依赖,esbulid是采用go语言编写的,go语言是纳秒级别的。

因为js是毫秒级别,go语言是纳秒级别。所以vitewebpack打包器快10-100倍。

2.打包过程

webpack:分析各个模块之间的依赖=>然后进行编译打=>打包后的代码在本地服务器渲染。随着模块增多,打包的体积变大,造成热更新速度变慢。
vite:启动服务器=>请求模块时按需动态编译显示。(vite遵循的是ES Modlues模块规范来执行代码,不需要打包编译成es5模块即可在浏览器运行。)

vite启动的时候不需要分析各个模块之间的依赖关系、不需要打包编译。vite可按需动态编译缩减时间。当项目越复杂、模块越多的情况下,vite明显优于webpack

3.热更新

webpack:模块以及模块依赖的模块需重新编译
vite:浏览器重新请求该模块即可

4.使用方面

vite开箱即用,更加简单,基于浏览器esm,使得hmr更加优秀,达到极速的效果;

webpack更加灵活,api以及插件生态更加丰富。

5.原理不同

webpack是bundle,自己实现了一套模块导入导出机制。

vite是利用浏览器的esm能力,是bundless。

69. 说说你都用过css3中的那些新特性?

1)选择器
2)阴影
3)形状转换(2D <-> 3D)
4)变形
5)动画(过渡动画、帧动画)
6)边框
7)多重背景
8)反射
9)文字
10)颜色函数(rgba/hsl/hsla)
11)滤镜(filter)
12)弹性布局
13)多列布局
14)栅格布局
15)盒模型
16)Web字体
17)媒体查询

70. 说说你对flex布局的了解,使用场景?常用属性?

​ 1;是一种浏览器提倡的布局模型。

​ 2:避免浮动脱标的问题 (flex布局不会脱标)。

​ 3:注意:如果子盒子没有设置高度,子盒子将会拉伸填满父盒子高度。

flex-direction:用于改变弹性布局的主轴方向。 加display:flex会默认添加flex-direction:row属性,所以加弹性布局后,子元素的默认主轴方向会从上到小变为从左到右。 --场景:上图标下文字展示,设置主轴方向为column

flex-wrap:用于控制元素是否换行,默认nowarp不换行。–场景:在弹性布局中,子元素的宽的总和大小大于父元素时,默认不换行,会对子元素造成压缩导致数据显示不全的问题。

justify-content:用于控制元素在主轴上的对齐方式。默认flex-start左对齐。–场景:常用于元素的两端对齐。

align-items:用于控制元素在交叉轴上对齐方式。–场景:配合justify-content属性使用,完成子元素的垂直水平居中

71.如何快速的让一个打乱一个数组的顺序,比如 var arr = [1,2,3,4,5,6,7,8,9,10];

1.时间复杂度O(n^2)

2.时间复杂度O(n)

原理:主要是将数组里的索引值随机打乱,然后将当前的索引值与随机变化之后的索引值互换。

(1).首先遍历的开始是从最大的索引开始,然后逐次递减;

(2).然后选取一个随机值randomIndex,这个随机值的产生是在0-len(即数组的长度)之间产生,由于这个值不能为len(因为数组的索引是从0开始的),只能为len-1,故只能向下取整Math.floor;

(3).取到随机值之后,将这个随机值对应的数组值即arr[randomIndex]赋值给当前遍历的i对应的数组值即arr[i];

3.sort 是对数组进行排序,每次从数组里面挑选两个数 进行运算。

  • 如果传入的参数是0,两个数位置不变
  • 如果参数小于0,就交换位置
  • 如果参数大于0,就不交换位置

我们利用 Math.random-0.5,这个运算的结果要么是大于0,要么是小于0.这样要么交换位置,要么不交换位置。当然大于或者小于0是随即出现的。所以数组就被随即排序了。

72. 说说箭头函数和普通函数的区别?

  1. 语法上的区别:箭头函数使用箭头符号(=>)来定义函数,而普通函数使用 function 关键字定义。
  2. this 指向不同:箭头函数没有自己的 this,它的 this 指向的是定义时的作用域中的 this;而普通函数的 this 指向的是调用时的上下文对象。
  3. 箭头函数没有 arguments 对象,因此不能直接访问函数参数;而普通函数可以使用 arguments 对象来访问函数参数。
  4. 箭头函数不能作为构造函数使用,因为它没有自己的 this 对象;而普通函数可以通过 new 关键字来作为构造函数使用,生成一个新的实例对象。

总的来说,箭头函数相对于普通函数来说更加简洁,但是在某些场景下可能会有一些限制,需要根据实际情况进行选择。

73.说说webpack中常见的Loader?解决了什么问题?

(1)style-loader: 将css添加到DOM的内联样式标签style里
(2)css-loader:允许将css文件通过require的方式引入,并返回css代码
(3)less-loader: 处理less
(4)sass-loader: 处理sass
(5)postcss-loader: 用postcss来处理CSS
(6)autoprefixer-loader:处理CSS3属性前缀,已被弃用,建议直接使用 postcss
(7)file-loader: 分发文件到output目录并返回相对路径
(8)url-loader: 和file-loader类似,但是当文件小于设定的limit时可以返回一 DataUrl
(9)html-minify-loader: 压缩HTML
(10)babel-loader :用babel来转换ES6文件到ES5

74.SPA首屏加载速度慢怎么解决

加载慢的原因
1.网络延时问题
2.资源文件是否体积过大
3.资源是否重复发送请求加载
4.加载脚本的时候,渲染内容堵塞
解决优化方案
1.减小入口文件体积
2.静态资源本地缓存
3.第三方插件按需加载或者使用CDN引用
4.图片资源压缩
5.抽离公共组件避免重复打包
6.开启GZip压缩
7.使用SSR

75.你对SPA单页面的理解,它的优缺点分别是什么?如何实现SPA应用呢

SPA应用就是一个web应用,可理解为:是一种只需要将单个页面加载到服务器之中的web应用程序。当浏览器向服务器发出第一个请求时,服务器会返回一个index.html文件,它所需的js,css等会在显示时统一加载,部分页面需要时加载。

优点:1:良好的交互式体验 2:良好的前后端分离模式(MVVM),减轻服务端压力。3:共用同一套后端程序代码,不用修改就可用于web界面,手机和平板等客户端设备

缺点:1.不利于SEO优化。2.不能使用浏览器自带的前进和后退功能3…首屏加载过慢。

实现一个SPA:

  1. 监听地址栏中hash变化驱动界面变化
  2. 用pushsate记录浏览器的历史,驱动界面发送变化

76.Vue中组件和插件有什么区别?

组件:把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个组件

优势:降低整个系统的耦合度,调试方便,提高可维护性

插件:通常用来为 Vue 添加全局功能

  • 添加全局方法或者属性。如: vue-custom-element
  • 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  • 通过全局混入来添加一些组件选项。如vue-router
  • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如vue-router

区别

编写形式:

  • 组件:vue单文件的这种格式,每一个.vue文件我们都可以看成是一个组件

  • 插件:暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象

注册形式:

  • 组件注册主要分为全局注册与局部注册:

    • 全局注册通过Vue.component方法,第一个参数为组件的名称,第二个参数为传入的配置项
    • 局部注册只需在用到的地方通过components属性注册一个组件
  • 插件注册:通过Vue.use()的方式进行注册(安装),第一个参数为插件的名字,第二个参数是可选择的配置项

    • 注册插件的时候,需要在调用 new Vue() 启动应用之前完成

      Vue.use会自动阻止多次注册相同插件,只会注册一次

使用场景:

  • 组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue
  • 插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身
  • 简单来说,插件就是指对Vue的功能的增强或补充

77. 你了解vue的diff算法吗?说说看

diff 算法是一种通过同层的树节点进行比较的高效算法

其有两个特点:

  • 比较只会在同层级进行, 不会跨层级比较
  • 在diff比较的过程中,循环从两边向中间比较

1、vue引入diff算法的由来,是因为vue 2.x中为了降低Watcher力度,每个组件只有一个Watcher与之对应,所以引入diff算法进行精确的找到发生变化的地方。

2、vue中diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称为patch。

3、diff的过程整体遵循深度优先、同层比较的策略;两个节点之间比较会根据它们是否拥有子节点或者文本节点做不同操作;比较两组子节点是算法的重点,首先假设头尾节点可能相同做4次比对尝试,如果没有找到相同节点才按照通用方式遍历查找,查找结束再按情况处理剩下的节点;借助key通常可以非常精确找到相同节点,因此整个patch过程非常高效。

78.简单说一下 Virtual Dom

虚拟 dom 是相对于浏览器所渲染出来的真实 dom 的,

以往,我们改变更新页面,只能通过首先查找dom对象,再进行修改dom的方式来达到目的。 但这种方式相当消耗计算资源, 因为每次查询 dom ,都需要遍历整颗 dom 树。

现在,我们用对象的方式来描述真实的 dom,并且通过对象与真实dom建立了一一对应的关系,那么每次 dom 的更改,我通过找到相应对象,也就找到了相应的dom节点,再对其进行更新。这样的话,就能节省性能,因为js 对象的查询,比对整个dom 树的查询,所消耗的性能要少。

本质

Vnode的本质就是用树型结构的JS对象来描述真实的DOM结构的信息,这个树结构的JS对象包含了整个DOM结构的信息.。

虚拟 DOM 的优缺点:

优点:

  • 降低浏览器性能消耗
  • diff算法,减少回流和重绘
  • 跨平台

缺点:

  • 首次显示要慢些
  • 无法进行极致优化

实现原理

虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要 的 dom 操作,从而提高性能。

具体实现步骤如下:

  1. 用 JavaScript 对象结构表示 DOM 树的结构,比如说:一个元素对象,包含TagName、props 和 Children这些属性。然后根据这个对象构建一个真正的 DOM 节点, 插到文档当中;
  2. 当数据状态变更的时候,重新构造一棵新的对象树。通过diff 算法,比较新旧虚拟 DOM 树的差异。
  3. 根据差异,对真正的 DOM 树进行增、删、改。

Virtual DOM 真的比操作原生 DOM 快吗

这是一个性能 vs. 可维护性的取舍。框架的意义在于为你掩盖底层的 DOM 操作,让你用更声明式的方式来描述你的目的,从而让你的代码更容易维护。

没有任何框架可以比纯手动的优化 DOM 操作更快因为框架的 DOM 操作层需要应对任何上层 API 可能产生的操作,它的实现必须是普适的

在构建一个实际应用的时候,你难道为每一个地方都去做手动优化吗?出于可维护性的考虑,这显然不可能。框架给你的保证是,你在不需要手动优化的情况下,我依然可以给你提供过得去的性能。

79. 说说 React中的setState执行机制

在 React 中,setState 是用于更新组件状态的方法。它是异步执行的,因为 React 希望在进行多次状态更新时,将其批量执行以提高性能。

当我们调用 setState 时,React 会将新的状态合并到当前状态中,然后计划一次更新操作。更新操作将在当前代码执行结束后异步执行。这意味着调用 setState 后,如果我们立即打印状态,可能看到的是当前状态而不是新的状态。

在处理更新时,React 会首先比较新旧状态,检查它们是否相同。如果新旧状态相同,则不会执行任何操作。否则,React 将计划重新渲染组件并将新状态应用于组件。

值得注意的是,在某些情况下,React 可能会在 setState 中同步执行更新,而不是异步执行。这通常发生在使用 refs 或在生命周期方法中调用 setState 时。在这种情况下,我们需要小心处理更新,以避免出现问题。

80.说说对React中类组件和函数组件的理解?有什么区别?

类组件:在 React 16.8版本(引入钩子)之前,使用基于类的组件来创建需要维护内部状态或利用生命周期方法的组件(即componentDidMount和shouldComponentUpdate)。基于类的组件是 ES6 类,它扩展了 React 的 Component 类,并且至少实现了render()方法。
函数组件:是无状态的(同样,小于 React 16.8版本),并返回要呈现的输出。它们渲染 UI 的首选只依赖于属性,因为它们比基于类的组件更简单、更具性能。

  • class组件是有状态的组件,可以定义state状态,函数组件无状态
  • class组件有生命周期的,函数组件无生命周期
  • class组件是有this对象,函数组件没有this对象
  • 组件调用: class组件实例化后调用render方法调用,函数组件直接调用的。
  • class组件内部的话,render方法return返回渲染jsx模板,函数组件直接返回即可
  • ref获取子组件的对象,class组件可以直接获取到的,函数组件无法直接获取到。
  • 绑定bind改变this指向,只适用于class组件

81.说说对React Hooks的理解?解决了什么问题?

Hook是React 16.8.0版本增加的新特性/新语法,可以让你在函数组件中使用 state 以及其他的 React 特性

  • useState()用于为函数组件引入状态。在useState()中,数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState
  • useEffect()接受两个参数,第一个参数是你要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行
  • useRef()可以在函数组件中存储/查找组件内的标签或任意其它数据,保存标签对象,功能与React.createRef()一样
  • useContext()接收context状态树传递过来的数据
  • useReducer()接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数
  • memo和callback ,接收的参数都是一样,第一个参数为回调,第二个参数为要依赖的数据
    共同作用:仅仅依赖数据发生变化, 才会调用,也就是起到缓存的作用。useCallback缓存函数,useMemo 缓存返回值。

82.UseMemo和useCallback如何提升了性能,应用场景有哪些?

useMemo是对函数组件中的属性包装,返回一个具有缓存效果的新的属性,当依赖的属性没变化的时候,这个返回新属性就会从缓存中获取之前的。

useCallback是对函数组件中的方法缓存,返回一个被缓存的方法

usememo使用场景:缓存子组件,仅当有关联的属性发生变化时才会触发子组件的更新。举个简单的例子,父组件中有一个配置对象,配置对象中的属性分别由几个子组件分开展示,配置对象的数据来自服务端,每次去服务器端拉取配置对象在前端都会生成一个行的配置对象,即便其中的属性没有发生变化,子组件都会跟随父组件更新,此时我们可以分别对子组件用 useMemo 处理,将子组件关联的属性作为依赖项,依赖项不变,则子组件不更新,以此作为优化手段。

useCallback使用场景:父组件中需要传递函数到子组件,父组件每次更新都会重新声明内部的函数,导致传递给子组件的函数变化,子组件也会进行没有必要的更新,这种情况就可以利用 useCallback 处理传递给子组件的函数,避免每次父组件更新导致子组件更新的情况,因为只要 useCallback 的依赖项没有发生变化,传递给子组件的函数始终都是缓存的同一个函数。

83.如何封装组件在不同的项目之间使用如何实现

封装组件使其可以在不同的项目之间使用的一种常见的方式是通过将组件打包为可复用的npm包。具体步骤如下:

  • 创建一个独立的npm包,可以使用工具如npm init来初始化包的基本信息,或者使用脚手架工具如create-react-library或vue-cli-plugin-library来创建基础的npm包结构。

  • 将要封装的组件放在npm包的src目录下,并编写组件的代码。

  • 使用工具如rollup或webpack将组件代码打包成umd、cjs、esm等不同格式的包,并输出到npm包的dist目录下。同时在package.json文件中定义main、module、browser等字段,指定输出的不同包格式和入口文件。

  • 在组件代码中引用依赖的第三方库,使用peerDependencies字段将第三方库的版本号声明到npm包中,表示组件需要依赖这些第三方库。

  • 发布npm包到npm仓库,可以使用npm publish命令将包发布到公共仓库,或使用私有仓库来管理npm包。

在不同的项目中使用封装的组件时,可以通过npm install安装该组件包,然后在项目中引入组件。对于React项目,可以使用import语句导入组件,并在JSX中使用;对于Vue项目,可以使用Vue.use()方法全局注册组件,或在单个组件中通过import语句导入并使用。需要注意的是,引用组件时需要根据组件包中定义的不同包格式,选择合适的导入方式。

84.vue、react、angular 区别

基本概念
Angular 是一个应用设计框架与开发平台,用于创建高效、复杂、精致的单页面应用。

React 是一个用于构建用户界面的 JavaScript 库

Vu 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
相同点

  • 都是基于javascript/typescript的前端开发库,为前端开发提供高效、复用性高的开发方式
  • 都有组件和模板的开发思想
  • 各自的组件都有生命周期,不用的组件可以卸载,不占用资源
  • 都支持指令,如样式、事件等的指令

不同点:

​1. 创始和发行不同:

Angular是由googl提供支持的,初始发行于 2016年9月;React由Facebook维护,初始发行于 2013年3月;Vue是由前google人员创建,初始发行于2014年2月
  1. 应用类型不同:

    Angular支持开发native应用程序、SPA单页应用程序、混合应用程序和web应用程序;React支持开发SPA和移动应用程序;Vue支持开发高级SPA,开始支持native应用程序
    
  2. 模型不同

    angular基于MVC(模型-视图-控制器)架构;react和vue是基于Virtual DOM(虚拟的文档对象模型)
    
  3. 数据流流向不同

    Angular使用的是双向数据绑定,React用的是单数据流的,而Vue则支持两者。
    
  4. 对微应用和微服务的支持不同

    Angular使用的是TypeScript,因此它更适合于单页Web应用(single page web application,SPA),而非微服务。相反,React和Vue的灵活性更适合微应用和微服务的开发。
    
  5. 对原生应用的支持不同

    React Native为iOS和Android开发原生应用;Angular的NativeScript已被原生应用所采用,特别是Ionic框架已经被广泛地运用在制作混合应用等方面;Vue的Weex平台正在开发之中,尚无下一步使之成为全面跨平台的计划。
    
  6. 框架和库

    Angular 是一个框架而不是一个库,因为它提供了关于如何构建应用程序的强有力的约束,并且还提供了更多开箱即用的功能。React 和 Vue 是是一种库,可以和各种包搭配。
    
  7. 组件之间传值方式不同

    Angular 中直接的父子组件,父组件可以直接访问子组件的 public 属性和方法,也可以借助于@Input 和 @Output 进行通讯。没有直接关系的,借助于 Service 单例进行通讯;React 组件之间通过通过prop或者state来通信,不同组件之间还有Rex状态管理功能;Vue组件之间通信通过props ,以及Vuex状态管理来传值
    

85. 说说你对Redux的理解?其工作原理?

redux就是针对难以处理的数据管理,提出的一种解决方案。它能够让你的页面的数据管理更轻松。

redux要求我们把数据都放在store公共存储空间。一个组件改变了store里的数据内容,其他组件就能感知到store的变化,再来取数据,从而间接的实现了这些数据的传递的功能。React components需要获取一些数据,然后它就告知store需要获取数据,这就是action creactor ,store接收到之后去reducer查一下,reducer会告诉store应该给这个组件什么数据

86.怎么判断一个变量arr的话是否为数组(此题用 typeof 不行)

  • 使用 instanceof 运算符, 该运算符左边是我们想要判断的变量, 右边则是我们想要判断的对象的类,
  • 利用构造函数来判断他的原型是否为Array, 用法: 变量.constructor === 变量类型
  • 利用的一个专门的方法 isArray(), 用法:Array.isArray(变量),返回true,则说明该变量是数组类型;反之,说明该变量不是数组类型
  • 调用Object.prototype.toString.call(),返回true,则说明该变量是数组类型;反之,说明该变量不是数组类型
  • 通过对象的原型方式来判断
  • 通过 Object.getPrototypeOf()来判断是否为数组类型
  • 是通过 isPrototypeOf() 方法来判断是否为数组类型

87.Vue3.0的设计目标是什么?做了哪些优化

设计目标:

不以解决实际业务痛点的更新都是耍流氓,下面我们来列举一下Vue3之前我们或许会面临的问题

  • 随着功能的增长,复杂组件的代码变得越来越难以维护
  • 缺少一种比较「干净」的在多个组件之间提取和复用逻辑的机制
  • 类型推断不够友好
  • bundle的时间太久了

优化:

  • 更小
  • 更快
  • TypeScript支持
  • API设计一致性
  • 提高自身可维护性
  • 开放更多底层功能

88.说说 React 生命周期有哪些不同阶段?每个阶段对应的方法是

挂载阶段:

Constructor()在react组件挂载之前,会调用他的构造函数

componentWillMount:在调用render方法之前调用,并在初始化挂载及后续更新的时候都会被调用

componentDidMount:在组件挂载的时候立即调用

更新运行阶段:

ComponentWillReceiveProps:在接收父组件改变后的props需要重新的渲染组件的时候用的比较多,外部组件传递频繁的时候会导致效率比较低

ShouldComponentUpdate:用于控制组件重新渲染的生命周期,state发生变化的时候,组件会进入冲洗你的渲染流程当中,在这里return false就可以阻止组件的更新

Render():是class组件中唯一的必须实现的方法

ComponentWillUpdate():这个方法是在等ShouldComponentUpdate返回true的时候,组件会进入重新渲染完成之前的进行这个函数

ComponentDidUpdate():每次state改变并重新渲染页面后都会进入这个生命周期

卸载或者销毁的阶段:

ComponentWillunMount():在此处完成组件的卸载和数据的销毁

89. 如何解决跨域问题

跨域是指在同源策略下,一个网页无法向另一个网页发送请求。同源策略是一种浏览器安全策略,主要限制一个源加载的文档或脚本如何与另一个源进行交互。如果一个源包含的文档或脚本,试图向另一个源的资源发起请求,那么浏览器就会拦截这个请求。

解决跨域问题有多种方式,常见的有以下几种:

  • CORS(跨域资源共享):在服务端设置相应的头部信息,允许跨域访问。需要后端支持。

  • JSONP:利用 script 标签可以跨域请求的特性,将请求封装成 script 请求,服务器返回 JavaScript 脚本,通过回调函数的方式将数据返回到前端。只支持 get 请求。

  • 反向代理:通过 nginx、Apache 等反向代理服务器,将前端请求转发到目标服务器,再将目标服务器返回的数据返回给前端,使得前端代码和目标服务器属于同一域名和端口。需要服务器的配置和管理。

  • WebSocket:建立双向通信通道,通过特定的 API 实现浏览器和服务器之间的实时数据传输。需要服务器的支持。

90.如何优化webpack打包速度?

打包速度优化:

1、使用高版本的webpack和Node.js

2、多进程打包:happyPack或thread-loader

3、多进程并行压缩:parallel-uglify-plugin、uglifyjs-webpack-plugin 开启 parallel 参数、terser-webpack-plugin 开启 parallel 参数

4、预编译资源模块:DLLPlugin

5、缓存(babel-loader、terser-webpack-plugin、cache-loader)

6、exclude、include缩小构建目标,noParse忽略、IgnorePlugin

7、resolve配置减少文件搜索范围(alias、modules、extensions、mainFields)

打包体积优化:

1、Tree-shaking擦除无用代码

2、Scope Hoisting优化代码

3、图片压缩(image-webpack-loader)

4、公共资源提取(CommonsChunkPlugin)

5、动态Polyfill

6、分包设置Externals,使用 html-webpack-externals- plugin,将 react、react-dom 基础包通过 cdn 引入,不打入 bundle 中

7、删除无用CSS代码(purgecss-webpack-plugin)

8、JS、CSS压缩(UglifyJsPlugin(3)、terser-webpack-plugin(4)、optimize-css-assets-webpack-plugin)

91.new操作符具体干了什么?

(1)在内存中创建了一个新的对象(空对象)
(2)这个对象内部的[[prototype]]属性会被赋值为该构造函数的protottype属性
(3)构造函数内部的this,会指向创建出来的新对象
(4)执行函数的内部代码
(5)如果构造函数没有返回非空对象,则返回创建处理的新对象

92.说说webpack中常见的Plugin?解决了什么问题

HtmlWebpackPlugin:将打包后的JS、CSS等文件自动注入到HTML文件中,方便开发者使用。

MiniCssExtractPlugin:将CSS文件从JS文件中分离出来,避免JS文件过大,提高页面加载速度。

CleanWebpackPlugin:每次打包前清空输出目录,避免旧文件对新文件的影响。

DefinePlugin:定义全局变量,方便在代码中使用。

HotModuleReplacementPlugin:热更新插件,可以在不刷新页面的情况下更新代码,提高开发效率。

UglifyJsPlugin:压缩JS代码,减小文件体积,提高页面加载速度。

CopyWebpackPlugin:将静态资源文件复制到输出目录中,方便开发者使用。

93.说说你对递归的理解?封装一个方法用递归实现树形结构封装

递归是一种在函数内部调用自身的方法,通常用来解决需要反复执行同一任务的问题,其思想是将大问题分解成小问题进行解决。

在Vue中,递归可以用于展示树形结构的数据,它通过不断递归调用相同的组件,使得数据能够依次按照树形结构展开。

<template>
  <div>
    <li v-for="item in list" :key="item.id">
      {{ item.label }}
      <tree :list="item.children"></tree>
    </li>
  </div>
</template>

<script>
export default {
  name: "tree",
  props: {
    list: {
      type: Array,
      default: () => []
    }
  },
  components: {
    Tree: () => import('./Tree.vue') // 注册为异步组件,避免无限递归
  }
};
</script>

94. 什么是FOUC? 如何避免?

FOUC是指页面在加载时,由于CSS文件的加载顺序导致页面的样式先后变化,从而出现页面闪烁的现象。FOUC的全称是“Flash of Unstyled Content”。

要避免FOUC,我们可以采取以下几种方式:

  • 将CSS样式表放在HTML文档头部,这样浏览器加载HTML时就可以同时加载CSS文件,避免了样式变化的闪烁。
  • 使用媒体查询,对不同的设备采取不同的CSS样式,以避免因页面元素的尺寸改变导致的样式变化。
  • 使用JavaScript将CSS样式表动态地插入到页面中,可以避免页面的样式变化。
  • 使用CSS样式表中的特定属性,如visibility: hidden或者opacity: 0,避免在页面加载时元素的显示

在HTML标签上加上style="display:none"的方式,避免页面的样式变化。在JS中,我们可以使用window.onload事件,在页面元素加载完毕后再显示页面。

95.说说你对预编译器的理解?

预编译器是一种将代码预处理成标准化代码的工具。它们通过增加特性和语法来扩展普通的CSS、HTML、JS,并将这些扩展内容转换成浏览器可识别的CSS、HTML、JS代码。常见的预编译器包括Sass、Less、Stylus、Pug等。

预编译器的优点包括:

  • 增加特性:预编译器能够增加CSS、HTML、JS的特性,比如在CSS中添加变量、嵌套等语法;在HTML中添加变量、条件语句等语法;在JS中添加类似于Typescript的类型检查、ES6的语法等。
  • 提高可读性:预编译器能够更加语义化和清晰地书写代码,让代码更易读、易维护。
  • 提高开发效率:使用预编译器能够极大地提高开发效率,减少代码量和重复劳动。
  • 支持自定义扩展:预编译器支持自定义扩展,能够满足特定需求或组织特定的业务逻辑。

缺点则包括:

  • 需要学习新的语法和工具:使用预编译器需要熟悉其特定的语法和工具,增加了学习成本。
  • 不易调试:使用预编译器需要将其转换成标准的代码,当出现问题时,调试起来比较困难。
  • 增加编译时间:使用预编译器需要编译成标准代码,增加了编译时间。

总之,预编译器在前端开发中被广泛使用,能够提高开发效率和代码质量,减少重复劳动。但也需要注意其对开发成本和调试难度的影响。

96.shouldcomponentupdate-的作用

ShouldComponetUpdate询问组件是否需要更新的一个生命周期钩子,判断组件是否重新渲染,返回一个布尔。默认的返回true,需要重新render(),若返回值是false,则不触发渲染,利用这个生命周期钩子函数可以强行关闭不需要更新的子组件来提升渲染性能。这个方法用来判断是否需要调用render方法来重新描绘dom。因为dom的描绘会非常消耗性能,如果能在shouldComponentUpdate方法中能够写出更优化的dom diff算法,可以极大的提高性能。

97.概述下-react-中的事件处理逻辑

React中的事务处理逻辑与浏览器中的事件机制很相似,都是把一系列的回调函数封装起来,然后进行统一的调度和执行。

在React中,每一个组件的rerender都可以理解为一个事务,每个事务都包括三个阶段:

开始阶段 (transaction start):在这个阶段,React会记录当前要进行rerender的组件,并维护一个执行列表,用于记录当前事务中的所有回调函数。
执行阶段 (transaction perform):在这个阶段,React会依次执行事务中所有的回调函数,包括组件的生命周期函数、组件的setState函数等。
提交阶段 (transaction complete):在这个阶段,React会根据事务的执行结果进行状态更新和DOM操作等,最终完成真正的渲染。
React通过ReactDOM.unstable_batchedUpdates()函数将这些事务进行了批处理,可以把多个事务合并为一个,从而减少了不必要的性能消耗。

总之,React中的事务处理逻辑是React高效渲染的重要保证,它通过将多个更新操作批量处理来提高性能,并保证了在事务执行期间的更新操作能够稳定地进行。

98.react组件的划分业务组件技术组件

在 React 中,组件的划分一般可以分为业务组件和技术组件。

业务组件(Presentational Components)是指与业务相关的组件,主要负责展示数据和用户交互,通常称为展示组件或 dumb 组件,因为它们没有自己的状态,只接收父组件传递的属性(props),并根据属性渲染 UI。

技术组件(Container Components)是指与技术相关的组件,主要负责处理数据和业务逻辑,通常称为容器组件或 smart 组件,因为它们拥有自己的状态,可以直接操作数据,并将数据以属性(props)的形式传递给业务组件。

在实际开发中,我们通常会将复杂的页面或功能拆分成多个小组件,然后将这些小组件组合在一起形成一个完整的业务组件。而技术组件则负责控制数据流动和处理业务逻辑,将数据传递给业务组件进行展示。

业务组件和技术组件的划分可以帮助我们更好地组织代码,提高代码的可复用性和可维护性。

99.react性能优化是哪个周期函数

React性能优化的周期函数主要是shouldComponentUpdate()。在React应用中,每当props或state更新时,React会自动调用render()函数重新生成组件的虚拟DOM树,并将其与旧的虚拟DOM树进行Diff算法的比较,从而找出需要更新的部分进行局部渲染。

其中,shouldComponentUpdate()函数就是在进行Diff算法比较的时候调用的,我们可以在这个函数中控制是否需要更新组件的state和props,从而避免不必要的更新和渲染,提高应用的性能。

当shouldComponentUpdate()函数返回false时,React就认为组件不需要更新,从而直接使用旧的虚拟DOM树进行渲染,避免了不必要的操作。

需要注意的是,对于Pure Component (纯组件),即纯函数组件和继承自React.PureComponent的类组件,React会自动实现一个浅比较的shouldComponentUpdate()函数来避免不必要的重新渲染。

总之,React性能优化中的shouldComponentUpdate()函数可以帮助我们控制组件是否需要更新和渲染,从而提高应用的性能。但这个函数的实现需要注意保证正确性并避免过度优化导致的维护成本增加。

100. 说说你对Fiber的理解和应用场景

fiber是React中的一种新的协调机制,它的目的是解决在React应用中由于大量计算和渲染导致的卡顿问题。在旧的协调机制中,React是通过递归遍历组件树来计算并更新组件,如果组件树层级过深,递归过程中的计算和渲染会占用大量时间,从而导致页面卡顿。而Fiber则采用了一种基于时间片的调度算法,将大量的计算和渲染任务划分为多个小的任务单元,并且在每个任务单元执行完成后进行一次中断和恢复,以确保页面的响应速度。

Fiber的应用场景包括但不限于:

大型React应用,如社交网络、电商等,这些应用通常包含大量的组件,使用Fiber可以提高应用的性能和用户体验。
高并发场景,如在线游戏等,使用Fiber可以确保应用的实时性和响应速度,避免因大量计算和渲染导致的卡顿问题。
移动端应用,移动端设备的计算和渲染能力有限,使用Fiber可以减少计算和渲染的负担,提高应用的性能和用户体验

101.react性能优化方案

React性能优化有多种方案,以下列举了一些常见的方法:

  • 使用shouldComponentUpdate()或React.PureComponent来控制组件的更新;
  • 使用React的React.memo()函数或第三方库reselect进行数据的缓存和避免重复渲染;
  • 对长列表或树形结构等组件进行虚拟化,例如使用react-virtualized;
  • 对动画组件使用transform代替top、left等属性进行渲染,避免触发浏览器的重排和重绘;
  • 对复杂的组件进行分割和代码的懒加载,例如使用React.lazy和React.Suspense;
  • 对组件的代码进行优化,避免不必要的渲染和操作,例如对事件绑定进行正确的销毁和管理、合理使用生命周期函数等

需要注意的是,优化方案需要根据项目的具体情况进行选择,不能随意追求性能而影响代码的可读性和可维护性。在实现优化方案时,也需要注意对组件的正确性进行保证,避免引入新的问题。

102. 简述flux 思想及Redux的应用

Flux是一种架构思想,用于管理Web应用中的数据流。它强调单向数据流,即数据只能从store(数据层)向视图层(view)流动,视图层不能直接修改数据,而必须通过action来触发数据的改变。这种模式下,数据的流动更加可控和可预测,提高了代码的可维护性和可测试性。

Redux是一个基于Flux思想的状态管理库,它的核心思想是将应用中的所有状态保存在一个store中,视图层从store中读取状态,并通过派发action来触发store中的状态改变。Redux通过提供统一的API和严格的规则来管理应用中的状态,使得状态管理更加可控和可维护。

Redux的应用场景包括:

复杂的数据流管理:当应用中数据流较为复杂,需要管理多个相互依赖的状态时,Redux可以提供统一的数据管理方案,使得状态的变化更加可预测和可控。

跨组件状态共享:当多个组件需要共享同一状态时,Redux可以提供一个全局的状态容器,并通过订阅和派发机制来实现状态的同步。

服务端渲染:当应用需要进行服务端渲染时,由于服务端没有DOM环境,因此需要将数据和组件状态提前序列化并传递给客户端。Redux可以通过提供统一的数据容器和数据序列化方案来简化服务端渲染的实现

103.说说html和css渲染的过程是什么

HTML和CSS渲染的过程一般分为三个阶段:解析、渲染和合成。下面是具体的流程:

  • 解析HTML:浏览器首先会解析HTML,生成一颗DOM树。DOM树是由一些个体(HTML标签、CSS样式)构成的树形结构,表示整个页面的结构和层级关系。

  • 解析CSS:浏览器接着解析CSS文件,生成一份CSSOM树。CSSOM树也是由一些个体(CSS样式)构成的树形结构,表示整个页面的样式信息。

  • 合成:在完成DOM树和CSSOM树的解析后,浏览器就可以开始将它们合成为一颗渲染树(Render Tree),这个过程就是合成。渲染树只包含渲染网页所必须的节点,例如可见的节点,所有的CSS信息和计算后的样式属性,不可见的节点和一些不需要渲染的节点就不在渲染树中。

  • 布局:渲染树生成后,浏览器会根据每个节点的内容、样式等信息计算其在页面中的位置和大小,这个阶段称为布局(Layout)。

  • 绘制:最后是绘制(Painting)阶段,浏览器遍历渲染树,并依据树中节点的几何信息将所有的节点绘制出来,呈现在屏幕上。

需要注意的是,HTML和CSS渲染的过程是一个复杂的过程,可以受到很多因素的影响,并且在实际渲染中会涉及到很多细节和优化,了解渲染的基本流程可以帮助我们更好的理解页面渲染的过程,从而更好地进行前端的开发和调试。

104.说一下DOM0、DOM2、DOM3事件处理的区别是什么

  • DOM0事件处理:是最早出现的一种事件处理方式,通过在DOM节点上直接指定事件处理函数来实现。
  • DOM2事件处理:DOM2级事件定义了两种方法,addEventListener和removeEventListener,它们可以动态地添加和移除事件处理函数。DOM2事件处理可以添加多个事件处理函数,它们按照添加的顺序依次执行
  • DOM3事件处理:DOM3级事件增加了更多的事件类型,例如鼠标滚轮事件、键盘按键事件、文本输入事件等。除此之外,DOM3事件处理还增加了更多的方法,例如preventDefault()、stopPropagation()、stopImmediatePropagation()等,这些方法可以更加精确地控制事件的传播和处理。

总体来说,DOM2事件处理相比DOM0事件处理有更多的优势,而DOM3事件处理进一步扩展了事件的类型和方法。但是,由于DOM0事件处理在一些场景下的兼容性更好,所以在实际开发中也需要根据具体情况来选择不同的事件处理方式。

105.如何判断页面滚动到底部,如何判断页面中元素是否进入可视化区域?

106. 浏览器的内核和区别?

107.说一下浏览器Event Loop 和NodeJs中Event Loop的区别?

108.说一下vue-router的底层实现原理?

Vue-router是Vue.js官方提供的路由管理库,可以在Vue.js应用程序中实现客户端路由。

Vue-router的实现原理可以简单概括为以下几个步骤:

  • 定义路由规则:在Vue.js应用程序中定义路由规则,即指定哪些URL路径应该由哪些组件渲染。

  • 创建路由实例:使用VueRouter类创建一个路由实例,将路由规则作为参数传递给该实例。

  • 将路由实例挂载到Vue实例上:在Vue.js应用程序中将路由实例挂载到Vue实例上,使得所有的组件都可以访问路由实例。

  • 监听URL变化:当URL发生变化时,路由实例会根据定义的路由规则匹配相应的组件,并将组件渲染到应用程序的页面上。

  • 实现导航:Vue-router提供了一些API,可以通过编程方式实现导航,例如:push()、replace()、go()、back()等方法。

在实现路由的过程中,Vue-router利用了Vue.js的组件系统,将路由组件定义为Vue组件,实现了路由和组件的无缝衔接。同时,Vue-router还利用了浏览器的History API实现了前端路由的实现。

总的来说,Vue-router的实现原理是通过监听URL的变化,根据定义的路由规则匹配相应的组件,并将组件渲染到应用程序的页面上,实现了前端路由的实现。

109.说一下Vuex的实现原理,commit和dispatch方法如何实现的

Vuex是一个专为Vue.js设计的状态管理库,它借鉴了Flux、Redux等框架的设计思想,提供了一种集中式管理应用状态的方案。Vuex的实现原理是基于Vue.js的响应式系统和发布/订阅模式实现的。

Vuex中包含了五个模块:state、mutations、actions、getters和modules。其中,state是存储应用状态的地方;mutations是修改应用状态的地方;actions是处理异步操作的地方;getters是计算状态的地方;modules是将状态进行模块化管理的地方。

Vuex中提供了两个方法:commit和dispatch。其中,commit用于提交mutation,而mutation是唯一修改状态的方式;dispatch用于触发action,而action则可以进行异步操作,最终通过提交mutation来修改状态。

commit方法的实现原理比较简单,它只是简单地调用mutation的方法来修改状态。

dispatch方法的实现原理则比较复杂,它需要先处理异步操作,然后再通过commit方法提交mutation来修改状态。在处理异步操作时,dispatch方法会根据action的类型分别执行不同的操作,可以是异步请求、定时器等等。当异步操作完成后,它会再次调用commit方法来提交mutation,从而修改状态。

总之,Vuex通过响应式系统和发布/订阅模式,实现了集中式管理应用状态的方案,提供了commit和dispatch方法来实现状态的修改和异步操作,从而简化了应用状态管理的过程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值