前端面试题

  • 1、vue2和vue3的主要区别
  • 3、Apply/call/bind的原理是什么?
  • 4、说说你对原型和原型链的理解?
  • 5、说说你对ES6中Generator的理解
  • 6、说说你对Event Loop的理解
  • 7、说说Promise和async/await 的区别?
  • 8、说说浏览器事件循环和nodeJs的事件循环的区别?
  • 9、说说你对浏览器缓存机制的理解
  • 10、说说你对浏览器内核的理解
  • 11、说说你对Vue的响应式原理的理解
  • 12、Methods watch computed区别是什么
  • 13、说说你对Virtual DOM的理解?
  • 14、说说你对nextTick的理解和作用
  • 15、说说你对webpack的理解
  • 16、谈谈GET和POST的区别
  • 17、说说HTTP和HTTPS的区别,HTTPS加密原理是?
  • 18、TCP为什么要三次握手?
  • 19、说说Proxy代理的原理?
  • 20、说说内存泄漏的理解?内存泄漏的情况有哪些?
  • 21、说说你对BOM的理解,常见的BOM对象你了解哪些?
  • 22、说说浏览器的渐进增强和优雅降级的区别?
  • 23、浏览器的内核都有哪些,什么区别?
  • 24、网站性能优化的方案都有哪些?
  • 25、Link和@import之间有什么区别?
  • 26、说说你对BFC的理解,触发条件有哪些?
  • 27、null,undefined 的区别
  • 28、说说css中元素脱离文档流的方式有哪些?定位的方式有哪些以及区别?
  • 29、同步和异步的区别
  • 30、伪类和伪元素的区别有哪些? Css3新增了哪些选择器
  • 31、说说箭头函数和普通函数的区别?
  • 32、SPA首屏加载速度慢怎么解决
  • 33、说说重排和重绘的区别?触发条件有哪些?
  • 34、Javascript如何实现继承?
  • 35、说说什么是严格模式,限制都有哪些?
  • 36、如何快速的让一个打乱一个数组的顺序,比如 var arr = [1,2,3,4,5,6,7,8,9,10];
  • 37、Vue的自定义指令钩子函数有哪些?你用自定义指令做过什么?
  • 38、从A页面跳转到B页面,缓存A组件,从A组件跳转到C组件,取消缓存,如何实现?
  • 39、Vue2和Vue3中响应式原理及区别?
  • 40、Vue是如何实现实现权限管理的,按钮级别权限如何实现?
  • 41、说说webpack中常见的Loader?解决了什么问题?
  • 42、你对SPA单页面的理解,它的优缺点分别是什么?如何实现SPA应用呢
  • 43、Vue中组件和插件有什么区别?
  • 44、你了解vue的diff算法吗?说说看?
  • 45、Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 有什么不同?
  • 47、说说 React中的setState执行机制?
  • 48、说说对React中类组件和函数组件的理解?有什么区别?
  • 49、说说对React Hooks的理解?解决了什么问题?
  • 50、UseMemo和useCallback如何提升了性能,应用场景有哪些?
  • 51、Vue-router的实现原理是什么?
  • 52、如何封装组件在不同的项目之间使用如何实现?
  • 53、vue、react、angular 区别?
  • 54、说说你对Redux的理解?其工作原理?
  • 55、说说你对递归的理解?封装一个方法用递归实现树形结构封装
  • 56、什么是FOUC? 如何避免?
  • 57、说说你对预编译器的理解?
  • 58、shouldComponentUpdate 的作用
  • 59、概述下 React 中的事务处理逻辑
  • 60、react组件的划分业务组件技术组件?
  • 61、react性能优化是哪个周期函数
  • 62、说说你对Fiber的理解和应用场景
  • 63、react性能优化方案
  • 64、简述flux 思想及Redux的应用
  • 65、说说html和css渲染的过程是什么
  • 66、说一下DOM0、DOM2、DOM3事件处理的区别是什么?
  • 67、如何判断页面滚动到底部,如何判断页面中元素是否进入可视化区域?
  • 68、说一下Vuex的实现原理,commit和dispatch方法如何实现的
  • 69、请简单叙述Vue2和Vue3的区别和变化至少说6点
  • 70、说说对盒子模型的理解?
  • 71、Css的选择器有哪些?优先级?哪些可以继承
  • 72、元素水平垂直居中的方法有哪些?如果元素不定宽高呢?
  • 73、怎么理解回流跟重绘?什么场景下会触发
  • 74、什么是响应式设计?响应式设计的基本原理是什么?如何做?
  • 75、如果要做优化,CSS提高性能的方法有哪些?
  • 76、对前端工程师这个职位是怎么样理解的?它的前景会怎么样
  • 77、说说JavaScript中的数据类型?存储上的差别?
  • 78、请简单叙述js数据类型判断的方法有哪些?
  • 79、说说你对闭包的理解?闭包使用场景
  • 80、bind、call、apply 区别?如何实现一个bind
  • 81、Javascript本地存储的方式有哪些?区别及应用场景
  • 82、请叙述Vue2和Vue3的diff算法的区别?
  • 83、请简单叙述你对作用域链得理解?
  • 84、Vue3中的生命周期函数的变化以及含义
  • 85、Vue3中自定义指令生命周期的变化及含义
  • 86、Vue3中的组合式Api有哪些? 和Vue2的Options Api又什么不同?
  • 87、 什么是跨域?如何解决跨域问题?
  • 88、 什么是浮动?如何清除浮动?
  • 89、 请简述HTML5的新特性。
  • 90、 请简述CSS3的新特性。
  • 91、 请描述CSS中的选择器及其优先级
  • 92、 请描述盒子模型的四个属性:margin、padding、border和content。
  • 93、如何处理移动端的适配问题?
  • 94、 请描述常见的HTTP请求方法。
  • 95、 什么是闭包?请举例说明。
  • 96、 什么是原型链?如何实现继承?
  • 97、 请描述CSS中的position属性及其取值。
  • 98、请描述CSS中的display属性及其取值。
  • 99、请描述CSS中的float属性及其取值。
  • 100、什么是BFC?如何触发BFC?
  • 101、请描述JS中的数据类型及其判断方法。
  • 102、请描述JS中的作用域及其作用域链。
  • 103、什么是异步编程?请举例说明。
  • 104、什么是事件委托?有何优缺点?
  • 105、请描述ES6的箭头函数及其使用方法。
  • 106、请描述ES6的模板字符串及其使用方法。
  • 107、请描述ES6的let和const关键字及其作用。
  • 108、请描述ES6的解构赋值及其使用方法。
  • 109、什么是webpack?如何使用webpack打包项目?
  • 110、Vue中组件和插件有什么区别?
  • 111、什么是防抖和节流,有什么区别?如何实现?
  • 112、什么是事件代理
  • 113、ES5、ES6和ES2015有什么区别?
  • 114、babel是什么,有什么作用?
  • 115、举一些ES6对String字符串类型做的常用升级优化?
  • 116、举一些ES6对Array数组类型做的常用升级优化
  • 117、什么是Vue SSR
  • 118、请列举出3个Vue中常用的生命周期钩子函数?
  • 119、Vue的路由实现:hash模式 和 history模式原理
  • 120、对MVVM的理解
  • 121、Vue组件间的数据传递方式有哪些
  • 122、v-if 和 v-show 区别
  • 123、`$route和$router`的区别
  • 124、如何让CSS只在当前组件中起作用?
  • 125、`<keep-alive></keep-alive>`的作用是什么
  • 126、在Vue中使用插槽的步骤
  • 127、Proxy 相比于 defineProperty 的优势
  • 128、vuex是什么?怎么使用?哪种功能场景使用它?
  • 129、在vue使用插件的步骤
  • 130、vue路由的钩子函数有哪些
  • 131、vue2的生命周期

1、vue2和vue3的主要区别

1、性能优化:Vue3对虚拟DOM进行了优化,例如使用了更高效的算法,缩减了代码量。此外,Vue3还利用Proxy代理优化了响应式系统,提高了性能。

2、新特性:Vue3引入了Composition API,是一种函数式API。Composition API使得组合逻辑更加容易,能够更好地重用组件逻辑。

3、Tree-shaking:Vue3支持更好的Tree-shaking(摇树优化)能力,使得项目打包后更加精简,加载速度更快。

4、Typescript支持:Vue3对Typescript支持更完善,使用Typescript编写Vue3应用可以获得更好的类型安全和开发体验。

5、小巧的包:Vue3的核心库包大小比Vue2更小,在使用上更加灵活。

#/2、vue3组件通信流程
Vue3中组件通信的流程可以用以下方式表述:

1、父组件向子组件传递数据

  • 父组件通过props属性将需要传递的数据传递给子组件,在子组件中定义props属性接收父组件传递的数据
  • 子组件通过props属性访问父组件传递过来的数据

2、子组件向父组件传递数据

  • 子组件通过 e m i t 方法触发父组件的事件,子组件在 emit方法触发父组件的事件,子组件在 emit方法触发父组件的事件,子组件在emit方法中传递需要传递的数据
  • 父组件中监听子组件的事件,在监听方法中获取子组件传递过来的数据

3、setup中的返回值

  • 在setup函数中定义需要传递的数据或方法返回一个对象或数组
  • 在子组件中使用props属性获取父组件传递过来的数据,子组件通过setup函数提供的数据或方法来使用

4、provide / inject

  • provide在父组件中提供需要传递的数据
  • inject在子组件中获取提供的数据
    可以在组件树中遥远的组件之间进行传递

在Vue3中,父子组件之间的通信需要通过props和$emit方法、setup函数以及provide / inject来进行。这些方式的选择需根据实际情况和项目需求和组织结构而定。需要注意的一点是,过于频繁的组件通信也可能导致应用的耦合度过高,因此,在使用时需要权衡其利弊。

3、Apply/call/bind的原理是什么?

·apply()·, ·call()·, ·bind()· 是 JavaScript 中函数对象的方法,它们的作用是改变函数的执行上下文,即函数内部的 this 指向。

在 JavaScript 中,函数是一类特殊的对象。它们具有 call, apply, bind 等内置方法。这些方法利用了 JavaScript 中函数是对象的性质,在函数运行时临时绑定了一个新的执行上下文,从而改变了函数内部 this 关键字的指向。

  • call() 方法和 apply() 方法都可以改变函数的执行上下文,并且接受的参数也不同。apply() 方法接受的是一个数组参数,而 call() 方法则接受一个或多个单独的参数。这两个方法的本质区别在于参数的传递方式不同,但作用一致。
  • bind() 方法则是将原函数和指定的对象绑定,返回一个新的函数,新函数的执行上下文为绑定对象。bind() 方法只返回对函数的绑定,并不会立即执行函数。

这三个方法的核心机制是通过改变函数的作用域链来改变 this 的指向,进而控制函数的执行上下文。在使用 call(), apply(), bind() 来改变函数执行上下文时,我们需要显式地指定需要绑定的对象,从而避免了因为 this 指向问题而造成的函数执行错误。

4、说说你对原型和原型链的理解?

在JavaScript中,每个对象都有一个关联的原型对象,也称为原型。原型对象是一个普通对象,它具有一组属性和方法,它可以被用来继承这些属性和方法。每当你创建一个新的对象时,它都会自动关联到它的构造函数的原型对象上。

原型链是一种机制,它使得对象之间可以通过它们各自的原型对象相互关联起来。一个对象的原型对象又可以有自己的原型对象,这样就形成了一个原型链。当你试图访问一个对象上的属性或方法时,JavaScript会首先在对象自身上查找,如果没有找到,它就会去该对象的原型对象上查找,如果还没有找到,它就会继续沿着原型链向上查找,直到找到该属性或方法或者到达原型链的顶部,即Object.prototype。如果最终还是没有找到该属性或方法,JavaScript会返回undefined。

这种原型继承的机制在JavaScript中非常强大,因为它使得我们可以轻松地在对象之间共享代码。例如,如果你创建了一个构造函数,它有一些方法和属性,你可以将这些方法和属性添加到它的原型对象上,这样每个从该构造函数创建的对象都可以访问这些方法和属性,这样可以大大节省内存空间。此外,原型链还允许我们实现更高级的继承和多态性,这些是面向对象编程中非常有用的概念。

5、说说你对ES6中Generator的理解

ES6引入了一个新的概念——生成器(Generator)。生成器是一种可以暂停执行的函数,可以用来惰性地生成一系列值。相比普通函数,生成器有以下几个特点:

  • 生成器函数使用function*关键字定义,内部使用yield关键字可以将函数的执行暂停,将控制权交回给调用者。

  • 生成器函数的返回值是一个生成器对象,这个对象同时也是一个可迭代对象,可以使用for…of语句进行迭代。

  • 在每次调用生成器对象的next()方法时,生成器会从上一次暂停的位置开始执行,直到遇到下一个yield表达式或函数结束。

  • 可以使用yield表达式向生成器对象返回一个值,在下一次调用next()方法时可以继续从上一次暂停的位置开始执行,并在yield表达式处暂停。

  • 生成器函数内部可以使用yield*表达式调用另一个生成器函数或可迭代对象的迭代器。

  • 生成器函数内部可以使用return语句返回最终的值,并终止生成器的执行。

通过使用生成器,可以方便地实现异步操作、惰性计算、迭代器等功能,同时避免了回调地狱和复杂的异步操作处理。

6、说说你对Event Loop的理解

当JavaScript代码执行时,它将被放置在执行栈中,按照先进先出的顺序执行。如果当前执行的任务是一个异步任务(例如,定时器、事件监听器、网络请求等),则它将被添加到任务队列(Event Queue)中,等待执行。

当执行栈中的所有任务完成时,事件循环开始工作。它从任务队列中取出一个任务,将其放置在执行栈中执行。执行栈再次为空时,事件循环再次从任务队列中取出一个任务,并将其放置在执行栈中执行。这个过程循环重复,直到任务队列为空。

JavaScript的事件循环采用单线程的方式执行,即每个时刻只有一个任务在执行。由于JavaScript是单线程的,因此在处理长时间运行的任务时,它会阻塞事件循环,导致其他任务不能及时得到执行。因此,JavaScript提供了一些异步编程模式,例如Promise和回调函数,以允许长时间运行的任务在后台执行,不会阻塞事件循环。

总之,事件循环是JavaScript异步编程的基础,它通过任务队列和执行栈来协调任务的执行顺序,保证了JavaScript代码的执行顺序和异步事件的处理。

7、说说Promise和async/await 的区别?

Promise 和 async/await 都是处理异步操作的方式,但它们在语法和使用上有一些区别。

Promise 是一个用于处理异步操作的对象,它代表了一个尚未完成的操作,并提供了一种可以在操作完成时执行回调函数的方式。Promise 提供了 then() 方法,可以在异步操作完成后执行成功和失败的回调函数。

async/await 是在 ES6 中引入的一种处理异步操作的语法糖,它提供了一种更简洁的方式来编写异步代码。使用 async 关键字标记一个函数为异步函数,异步函数中可以使用 await 关键字等待 Promise 对象完成,并返回 Promise 的结果。

下面是 Promise 和 async/await 的一些区别:

  • 语法:Promise 通过链式调用 then() 方法来处理异步操作的结果,而 async/await 利用 async 和 await 关键字来处理异步操作的结果,使得代码更加简洁易懂。

  • 错误处理:在 Promise 中,错误处理通常使用 catch() 方法来捕获 Promise 返回的错误,而在 async/await 中,可以使用 try/catch 语句来捕获异步操作中的错误。

  • 控制流:在 Promise 中,如果有多个异步操作需要依次执行,可以使用链式调用 then() 方法来处理。而在 async/await 中,可以使用 async/await 结合 for…of 循环来处理异步操作的顺序执行。

  • 可读性:由于 async/await 使用了同步代码的风格,所以它通常比 Promise 更加易读和易于理解。但是,当出现多个异步操作需要依次执行时,使用 Promise 可能会更加简洁明了。

总之,Promise 和 async/await 都是处理异步操作的方式,具体使用哪种方式取决于开发者的个人偏好和具体应用场景。

8、说说浏览器事件循环和nodeJs的事件循环的区别?

虽然浏览器和Node.js都使用事件循环来处理异步任务,但它们的事件循环实现方式有所不同。

在浏览器中,事件循环包括主线程、任务队列和微任务队列。当浏览器遇到异步任务时,它将其添加到任务队列中,等待下一次事件循环迭代时执行。当主线程完成当前执行栈中的任务时,它会检查微任务队列是否有任务需要执行,如果有,则按顺序执行微任务队列中的任务。然后,它会从任务队列中取出一个任务,并将其添加到执行栈中执行。这个过程循环重复,直到任务队列和微任务队列都为空。

在Node.js中,事件循环包括主线程、任务队列、微任务队列和观察者(Watchers)。观察者用于监听操作系统的事件,例如文件I/O、网络I/O等。当Node.js遇到异步任务时,它将其添加到任务队列中,等待下一次事件循环迭代时执行。当主线程完成当前执行栈中的任务时,它会检查微任务队列是否有任务需要执行,如果有,则按顺序执行微任务队列中的任务。然后,它会执行观察者中的回调函数,处理相应的事件。这个过程循环重复,直到任务队列和微任务队列都为空,并且没有活动的观察者为止。

因此,浏览器和Node.js的事件循环机制在微任务队列和观察者方面存在一些区别。在浏览器中,微任务队列只包括Promise和MutationObserver回调,而在Node.js中,微任务队列还包括process.nextTick回调。另外,Node.js的事件循环还包括观察者,用于处理底层的操作系统事件。

9、说说你对浏览器缓存机制的理解

浏览器缓存机制是指浏览器在向服务器请求资源时,会先在本地缓存中查找该资源,如果缓存中存在该资源且没有过期,则直接使用缓存中的资源,否则向服务器请求资源。

浏览器缓存机制可以分为两种类型:强制缓存和协商缓存。

  • 强制缓存:强制缓存是指在浏览器向服务器请求资源时,先检查本地缓存中是否存在该资源,如果存在且没有过期,则直接使用缓存中的资源。可以使用 HTTP 头信息中的 Expires 和 Cache-Control 字段来控制缓存的过期时间。缺点是如果资源在缓存期间发生了变化,浏览器无法检测到,依然会使用缓存中的旧资源。

  • 协商缓存:协商缓存是指在浏览器向服务器请求资源时,先向服务器发送一个请求,询问该资源是否有更新。服务器收到请求后,会比较该资源的最后修改时间或者 ETag 值,如果资源有更新,则返回新的资源,否则返回一个状态码 304 Not Modified,并告诉浏览器直接使用缓存中的资源。可以使用 HTTP 头信息中的 Last-Modified 和 ETag 字段来实现协商缓存。

需要注意的是,浏览器缓存机制仅适用于静态资源,对于动态资源或者需要实时更新的内容,缓存机制并不适用。此外,开发者也可以通过设置 HTTP 头信息来控制浏览器缓存,以达到更好的缓存效果。

10、说说你对浏览器内核的理解

浏览器内核是指浏览器用来渲染网页的核心程序。它主要负责将网页的HTML、CSS和JavaScript等前端代码转换成可视化的网页。

常见的浏览器内核包括:

  • Trident内核:是Microsoft开发的浏览器内核,被用于Internet Explorer浏览器。

  • Gecko内核:是Mozilla开发的浏览器内核,被用于Firefox浏览器。

  • WebKit内核:是苹果公司开发的浏览器内核,被用于Safari浏览器和Chrome浏览器的早期版本。

  • Blink内核:是由Google基于WebKit内核开发的浏览器内核,被用于Chrome浏览器和Opera浏览器。

浏览器内核的性能和特性对浏览器的速度、兼容性、安全性等方面都有影响。不同的内核在处理网页的方式、渲染效果、支持的标# 11、说说你对Vue的响应式原理的理解

11、说说你对Vue的响应式原理的理解

Vue的响应式原理是指当Vue监测到数据变化时,它会自动更新与该数据相关联的视图,从而实现数据驱动视图的目的。

具体来说,当我们在Vue中定义一个数据对象时,Vue会将该对象转换成响应式对象。当我们改变响应式对象的属性时,Vue会自动更新与该属性相关联的视图。

实现这个功能的核心是Vue的侦听器和观察者机制。Vue使用侦听器来监测数据的变化,并将变化通知给相关的观察者。观察者会接收到通知后,再执行相应的更新操作。

这种响应式原理的实现,使得我们在使用Vue开发应用时可以更加专注于数据的处理,而不用关心视图的更新。同时,也让我们能够更方便地进行组件化开发,提高了代码的可复用性和可维护性。

12、Methods watch computed区别是什么

在Vue.js中,“methods”,"watch"和"computed"都是用来处理Vue实例中数据和状态的方式,但它们各自有不同的用途和适用场景。

  • Methods(方法): methods是Vue实例中的函数,通常用于响应用户事件或其他触发器。methods可以修改Vue实例的状态,从而影响UI的呈现。例如,一个方法可以在用户输入后切换组件的可见性或更新一个计数器。

  • Watch(观察): Watch是Vue.js的一个功能,它允许您对特定的数据属性进行反应式监视,并在该属性发生更改时执行一些操作。当您在一个属性上定义一个watch时,Vue.js会自动在该属性发生更改时调用一个回调函数,传入该属性的新旧值作为参数。Watches通常用于比简单的computed属性或methods更复杂的逻辑。

  • Computed(计算属性): Computed属性是基于已有的属性(响应式)计算得出的属性,它们可以根据一个或多个已有的属性进行计算,并在依赖的属性发生变化时自动重新计算。这些计算属性可以被看做是对状态的一种派生或衍生,并且它们通常用于根据已有的状态计算出一些衍生的状态或属性,例如计算一个数值或格式化一个字符串。

因此,方法(methods)用于响应用户事件或其他触发器,Watch(观察)用于响应响应式属性的变化,Computed(计算属性)用于基于已有的响应式属性计算得出新的属性。在使用Vue.js时,您可以根据需要选择使用这些功能的组合,以满足您的特定需求。

13、说说你对Virtual DOM的理解?

传统的DOM操作在更新页面时需要重新计算和渲染整个页面,这样会导致页面更新的性能较低,而且会产生大量的性能瓶颈。而Virtual DOM可以通过比较新旧两个虚拟DOM之间的差异,然后只对需要更新的部分进行操作,从而减少了页面的渲染次数和计算量,提高了页面的渲染性能。

Virtual DOM的实现原理可以简单描述为:

  • 每次数据变化后,生成一个新的虚拟DOM树。

  • 将新的虚拟DOM树和旧的虚拟DOM树进行比较,找出两个树之间的差异。

  • 根据差异,只对需要更新的部分进行DOM操作,从而更新页面。

需要注意的是,由于Virtual DOM是通过JavaScript对象来描述页面结构的,因此它的操作速度非常快。同时,由于Virtual DOM只更新需要更新的部分,因此它可以减少不必要的页面渲染和计算,提高了页面的性能和响应速度。

14、说说你对nextTick的理解和作用

在Vue中,nextTick是一个异步执行的方法,它用于在当前DOM更新周期结束之后执行一些操作。

具体来说,当我们在Vue中修改数据时,Vue会立即更新虚拟DOM,并计划在下一个时间片执行DOM更新操作。如果我们需要在DOM更新完成后执行一些操作,比如获取更新后的DOM元素或者调用一些依赖于DOM的方法,那么就可以使用nextTick方法。

nextTick方法的作用是将回调函数推迟到下一个DOM更新周期之后执行。这样可以保证回调函数在DOM更新完成之后执行,从而避免了因为DOM更新尚未完成而导致的操作错误。同时,由于nextTick是异步执行的,所以它也不会阻塞UI线程,保证了页面的流畅性和响应速度。

在使用nextTick方法时,可以通过传入一个回调函数作为参数来执行需要延迟执行的操作。回调函数中可以访问更新后的DOM元素和数据,从而进行一些操作,比如计算DOM元素的尺寸、位置等信息,或者触发一些事件。

总之,nextTick是一个非常实用的工具方法,在Vue的开发中非常常见,可以帮助我们更加灵活地处理DOM更新和操作。

15、说说你对webpack的理解

Webpack是一个现代化的前端打包工具,它可以将多个源文件打包成一个或多个文件,以便于在浏览器中进行加载和执行。Webpack可以处理JavaScript、CSS、HTML和其他各种资源,并提供了丰富的插件和工具来支持各种前端开发场景。

Webpack的核心概念是“模块”,它支持各种模块化规范,包括CommonJS、AMD、ES6模块等。通过模块化的方式,Webpack可以将各种源文件组织成模块,并进行依赖管理和打包。Webpack的主要功能包括:

  • 模块化支持:Webpack支持各种模块化规范,并提供了丰富的加载器和插件来处理各种不同类型的模块。

  • 打包和压缩:Webpack可以将多个源文件打包成一个或多个文件,并且可以对打包后的文件进行压缩和优化,以便于在生产环境中使用。

  • 开发服务器:Webpack提供了一个开发服务器,可以在本地启动一个Web服务器,并支持热更新和自动刷新等功能,方便开发调试。

  • 代码分离:Webpack支持将代码分离成多个文件,以便于在需要的时候进行按需加载,从而提高页面加载速度。

  • 插件系统:Webpack提供了一个强大的插件系统,可以通过各种插件来扩展Webpack的功能,比如添加静态资源、优化代码等。

总之,Webpack是一个非常强大和灵活的前端打包工具,可以大大提高前端开发效率和性能。它在现代化前端开发中已经成为必不可少的工具之一。

16、谈谈GET和POST的区别

GET和POST是HTTP协议中最常见的两种请求方式,它们在传输数据的方式、安全性、适用场景等方面有所不同。

  • 数据传输方式:GET请求将请求参数附加在URL的末尾,以?号分隔,参数之间用&符号连接,比如http://localhost:8080/index?param1=value1&param2=value2。而POST请求则将请求参数放在请求体中进行传输,不会暴露在URL中。

  • 安全性:GET请求的参数暴露在URL中,容易被其他人看到或者截获,因此不适合传输敏感信息。而POST请求的请求体内容不会暴露在URL中,相对来说更加安全。

  • 适用场景:GET请求通常用于请求数据,比如查询数据、获取资源等,因为它的请求速度快、简单易用,但不适合传输大量数据和敏感信息。而POST请求通常用于提交数据,比如登录、注册、表单提交等,因为它可以传输大量数据,并且更加安全。

  • 缓存:GET请求可以被缓存,从而提高性能,而POST请求无法被缓存,每次提交都会产生新的请求。

总之,GET和POST请求各有优缺点,应根据实际需求进行选择。如果是获取数据或者查询资源,可以使用GET请求,如果是提交数据或者敏感信息,应该使用POST请求。同时,为了保证数据的安全性,不应该将敏感信息放在URL中,而应该使用POST请求。

17、说说HTTP和HTTPS的区别,HTTPS加密原理是?

HTTP和HTTPS都是网络传输协议,主要用于浏览器和服务器之间的数据传输,但它们在数据传输的安全性、加密方式、端口等方面有所不同

  • 数据传输的安全性:HTTP是明文传输,数据不加密,容易被黑客窃听、篡改或者伪造,存在安全隐患。而HTTPS使用了SSL/TLS加密协议对数据进行加密和认证,数据传输更加安全可靠。

  • 加密方式:HTTPS使用SSL/TLS协议对数据进行加密和认证,而HTTP不加密,所以在使用HTTP协议传输数据时,数据很容易被中间人拦截、修改或者伪造。

  • 端口:HTTP使用的默认端口是80,而HTTPS使用的默认端口是443,这是因为HTTPS需要使用SSL/TLS协议进行加密和认证,需要使用一个单独的端口来避免和HTTP协议混淆。

HTTPS加密原理:HTTPS使用了SSL/TLS协议对数据进行加密和认证,主要包括以下几个步骤:

  • 握手阶段:客户端向服务器发送一个加密通信请求,服务器回应一个数字证书。客户端通过数字证书验证服务器的身份,然后生成一个共享的密钥,用于后续的加密通信。

  • 加密阶段:客户端和服务器使用共享密钥进行加密通信,客户端将请求数据加密后发送给服务器,服务器解密后进行处理,然后将响应数据加密后发送给客户端,客户端解密后进行处理。

  • 断开连接:通信完成后,客户端和服务器断开连接。

总之,HTTPS通过加密和认证技术保证数据传输的安全性,是一种更加安全可靠的网络传输协议,比HTTP更适合传输敏感信息和保护用户隐私。

18、TCP为什么要三次握手?

TCP协议采用三次握手(three-way handshake)的方式建立连接,这是为了确保连接的可靠性和安全性。

三次握手的过程如下:

  • 客户端向服务器发送一个SYN(同步)报文,请求建立连接。该报文包括一个随机的序列号x。

  • 服务器收到客户端的SYN报文后,向客户端发送一个SYN+ACK(同步+确认)报文,表示可以建立连接。该报文包括一个随机的序列号y,以及一个确认号x+1。

  • 客户端收到服务器的SYN+ACK报文后,向服务器发送一个ACK(确认)报文,表示连接已经建立。该报文包括一个确认号y+1。

三次握手的目的是为了确保连接的可靠性和安全性:

  • 确保双方都能收到对方的数据包。在第一次握手时,客户端向服务器发送SYN报文,如果服务器没有收到该报文,会认为客户端没有请求建立连接,不会做出响应;在第二次握手时,服务器向客户端发送SYN+ACK报文,如果客户端没有收到该报文,会认为服务器没有响应,不会发送ACK报文,连接不会建立。

  • 防止连接被第三方劫持。在第三次握手时,客户端向服务器发送ACK报文,确认连接已经建立。如果连接被第三方劫持,客户端发送的ACK报文会被第三方拦截,服务器不会收到该报文,连接不会建立。

总之,TCP采用三次握手的方式建立连接,是为了确保连接的可靠性和安全性,防止数据包丢失或者被第三方劫持。

19、说说Proxy代理的原理?

在JavaScript中,Proxy代理可以用来创建一个代理对象,该对象可以代替另一个对象进行一些操作。代理对象可以拦截对另一个对象的访问,对访问进行一些控制和修改,从而实现一些高级的功能。

Proxy代理的原理是利用了JavaScript中的“元编程”能力,即能够对代码进行动态修改和增强的能力。通过创建一个代理对象,我们可以拦截并修改对目标对象的访问,包括读取、赋值、删除等操作。代理对象可以在这些操作发生之前或之后进行一些自定义的处理,从而实现对目标对象的控制和修改。

在使用Proxy代理时,我们需要定义一个“处理器”(handler)对象,该对象包含一些拦截方法,用于拦截对代理对象的操作。处理器对象可以拦截的方法包括get、set、has、deleteProperty、apply等等。通过定义这些方法,我们可以对代理对象的访问进行拦截和修改,从而实现一些高级的功能,比如数据绑定、属性拦截等等。

需要注意的是,Proxy代理只能对ES6标准中定义的对象进行代理,对于一些内置对象如Array、Date等,可以通过使用Reflect对象中的方法来进行操作。同时,由于Proxy代理的性能比直接访问对象要慢一些,因此在一些需要高性能的场景中,需要谨慎使用。

20、说说内存泄漏的理解?内存泄漏的情况有哪些?

内存泄漏指的是程序中申请的内存空间没有被正确释放,从而导致系统的内存资源被浪费或者耗尽的现象。当一个对象没有被程序再次使用时,占用的内存空间应该被立即释放,但是如果程序中存在一些不当的内存使用方式,就会导致内存泄漏。

内存泄漏的情况包括:

  • 循环引用:在程序中存在两个或多个对象之间的相互引用关系,而这些对象中至少有一个不再被程序使用,但是由于相互引用关系,导致这些对象无法被垃圾回收机制回收,从而造成内存泄漏。

  • 内存泄漏的DOM元素:在JavaScript中,DOM元素是非常常见的内存泄漏来源,因为DOM元素的创建和销毁是由浏览器控制的,如果程序中存在对DOM元素的引用,但是没有及时释放,就会导致内存泄漏。

  • 定时器:如果程序中存在一些没有被正确清理的定时器,就会导致内存泄漏。例如,如果一个定时器在页面销毁之前没有被清除,就会一直占用内存空间,从而导致内存泄漏。

  • 闭包:闭包是一种非常强大的编程技巧,但是如果不小心使用会导致内存泄漏。当一个函数返回一个内部函数时,内部函数会保留对外部函数的引用,如果这个内部函数被存储或者传递给其他对象,就会导致外部函数无法被垃圾回收机制回收,从而造成内存泄漏。

  • 资源未释放:在程序中使用一些系统资源,如文件、网络连接、数据库连接等,如果这些资源在使用完毕后没有被正确释放,就会导致内存泄漏。

为避免内存泄漏,我们需要遵循良好的编程习惯,及时释放不再使用的对象和资源,避免循环引用、不合理的定时器使用、合理使用闭包等方式。另外,使用一些工具如内存检测工具、代码分析工具等也可以帮助我们及时发现内存泄漏问题。

21、说说你对BOM的理解,常见的BOM对象你了解哪些?

BOM(Browser Object Model)指的是浏览器对象模型,它提供了浏览器窗口之间交互的接口,使得JavaScript可以操作浏览器窗口以及其中的文档和元素。BOM并不是W3C的标准,而是由浏览器厂商自行定义和实现的。

常见的BOM对象包括:

  • window对象:代表整个浏览器窗口,在JavaScript中,所有的全局变量和函数都是window对象的属性和方法。可以通过window对象获取和设置窗口的大小、位置、URL地址等信息。

  • location对象:代表当前窗口的URL地址,可以通过它获取和设置当前窗口的URL地址,并且可以对URL地址进行解析和操作。

  • history对象:代表当前窗口的浏览历史记录,可以通过它访问浏览器的历史记录,进行前进、后退等操作。

  • navigator对象:代表浏览器本身,可以通过它获取浏览器的一些信息,如浏览器的名称、版本、用户代理字符串等。

  • screen对象:代表用户的屏幕,可以通过它获取屏幕的一些信息,如分辨率、颜色深度等。

  • document对象:代表当前窗口中的文档,可以通过它获取和操作文档中的元素、样式、事件等。

在BOM中,window对象是最基本的对象,其他对象都是它的属性或方法。BOM提供了一些重要的功能,如窗口大小的调整、页面的跳转、浏览器的历史记录、弹出对话框等,可以帮助我们更好地控制浏览器的行为。

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

浏览器的渐进增强和优雅降级是两种不同的设计思想,它们都是为了在不同的浏览器环境中提供最佳的用户体验。

渐进增强(Progressive Enhancement)是指以功能为基础的设计方法,即先设计基本功能,再根据用户设备和浏览器的能力逐步增强功能。这种方法从功能的最基本需求出发,确保在所有设备和浏览器环境下都能够正常运行,并且在高端设备和浏览器中添加额外的功能,提升用户的体验。

例如,在设计一个Web页面时,先确保页面的核心功能能够在所有浏览器中正常运行,如HTML的结构和内容,CSS的基本样式等,然后再根据浏览器的支持情况和用户设备的性能逐步增加一些高级的功能,如动画效果、视频播放等。

相反,优雅降级(Graceful Degradation)是指先设计完整的功能,并在更高级别的浏览器环境中实现这些功能,然后在不支持这些功能的较低级别的浏览器环境中以某种方式进行降级处理。这种方法从高级浏览器环境出发,设计完整的功能,再考虑在低端设备和浏览器中适当的降级处理,以确保功能的基本可用性。

例如,在设计一个Web页面时,先考虑在最新的浏览器中实现完整的功能,如动画效果、视频播放等,然后再为低端设备和浏览器提供某种基本的备用方案,如静态图像、文本链接等。

总的来说,渐进增强和优雅降级都是为了提供最佳的用户体验,只是在设计思路上有所不同。渐进增强从基本功能出发,逐步增加高级功能,而优雅降级则是从完整功能出发,逐步降级处理。

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

浏览器内核是指浏览器用来解析和渲染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页面,提高页面的性能和用户体验。

24、网站性能优化的方案都有哪些?

网站性能优化是提高网站响应速度和用户体验的关键,它可以从多个方面入手,包括:

  • 前端优化:前端优化是网站性能优化的重要手段,可以从压缩CSS和JavaScript文件、优化图片大小和格式、减少HTTP请求、使用CDN加速等方面入手,从而提高网站的响应速度。

  • 后端优化:后端优化可以通过使用缓存技术、优化数据库查询、减少服务器负载等手段来提高网站的响应速度。

  • 服务器优化:服务器优化包括使用更快速的硬件、优化服务器配置、使用缓存等手段,可以提高服务器的响应速度,进而提高网站的性能。

  • 数据库优化:数据库优化可以通过建立索引、减少查询次数、优化SQL语句等手段来提高数据库查询的速度,从而提高网站的响应速度。

  • 使用CDN:CDN(内容分发网络)可以加速网站的访问速度,将网站的静态资源如图片、CSS、JavaScript等文件缓存到全球各地的CDN节点上,使得用户可以从离自己最近的节点获取资源,从而提高网站的响应速度。

  • 压缩文件:通过压缩CSS、JavaScript、HTML等文件,可以减小文件的大小,从而减少HTTP请求的次数,提高网站的响应速度。

  • 预加载和懒加载:通过预加载可以提高网站的响应速度,而懒加载可以延迟加载图片和其他资源,提高页面的响应速度和用户体验。

  • 使用异步加载:异步加载可以提高网站的响应速度,通过异步加载JavaScript和CSS文件可以使得网站能够更快地响应用户的请求。

综上所述,网站性能优化的方案是多样化的,可以从前端、后端、服务器、数据库、CDN等多个方面入手,需要根据实际情况选择相应的优化方案。

25、Link和@import之间有什么区别?

<link>@import 都可以用来导入外部资源,但它们有以下区别:

加载方式:<link> 是 HTML 标签,而 @import 是 CSS 的一种方式,因此 <link> 可以放在 HTML 文档的 <head> 中,或者放在文档中任何位置,而 @import 只能出现在 CSS 文件中。

加载时间:<link> 标签会在页面加载时同时加载,并行加载外部资源,而 @import 会等到页面全部加载完毕之后再加载。

兼容性:<link> 标签的兼容性好于 @import,在早期版本的 IE 浏览器中不支持 @import

功能扩展:<link> 标签可以通过 rel 属性指定不同类型的外部资源,比如 rel="stylesheet" 可以加载样式表,rel=“icon” 可以加载网站图标等,而 @import 只能加载 CSS 样式表。

总之,<link> 适合导入各种类型的资源,包括样式表、网站图标、脚本等,而 @import 适合在 CSS 样式表中导入其他样式表。

26、说说你对BFC的理解,触发条件有哪些?

BFC(Block Formatting Context)指的是一个独立的块级渲染区域,其中的元素按照一定的规则进行布局和渲染,不受外部影响。BFC 具有以下特性:

内部的块级元素垂直排列;

  • 块级元素在垂直方向的距离由它们的 margin 决定;
  • BFC 区域不会与浮动元素重叠;
  • BFC 区域的左侧与包含块的左侧相接触,右侧同理;
  • BFC 会阻止垂直方向上的 margin 重叠。

触发 BFC 有以下几种方式:

  • 根元素;
  • 浮动元素(float 不为 none);
  • 绝对定位元素(position 为 absolute 或 fixed);
  • display 为 inline-block、table-cell、table-caption、flex、inline-flex;
  • overflow 不为 visible。

当一个元素触发了 BFC 后,它就成为了一个独立的渲染区域,可以避免和外部元素发生布局和渲染上的冲突,可以用于解决一些布局问题,比如清除浮动、防止 margin 重叠等。

27、null,undefined 的区别

在 JavaScript 中,null 和 undefined 都表示没有值,但它们有以下区别:

  • undefined 表示一个声明了但未被赋值的变量,或者对象没有该属性的值;
  • null 表示一个被赋值为 null 的变量或对象属性。
    简单来说,undefined 表示缺少值,而 null 表示有值但是值为 null。

另外,null 和 undefined 在 JavaScript 中有不同的数据类型,null 是一个表示空值的对象,而 undefined 是一个表示未定义值的原始数据类型。

在使用时,应该尽量避免将变量赋值为 undefined,而使用默认值或者 null 来表示缺少值。同时,在判断变量是否有值时,应该使用严格相等运算符(===)来检查是否为 null 或 undefined,因为它们在非严格相等运算符(==)中可能会发生类型转换。

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

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

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

定位的方式有以下几种:

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

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

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

29、同步和异步的区别

同步和异步是用于描述程序或者系统中的操作方式的。

同步操作是指当一个操作开始执行后,必须等待它执行完成后才能执行下一个操作。也就是说,同步操作是按照顺序依次执行的,每个操作都要等待上一个操作完成后才能执行。同步操作的优点是操作的执行顺序可控,但是如果某个操作执行时间过长,会导致整个程序停顿,用户体验差。

异步操作是指当一个操作开始执行后,不需要等待它执行完成,可以继续执行后续的操作。也就是说,异步操作不是按照顺序依次执行的,某些操作可以在其它操作完成之前就开始执行。异步操作的优点是不会阻塞程序的执行,提高了程序的执行效率,但是操作的执行顺序是不可控的。

在 JavaScript 中,常见的异步操作包括事件回调函数、定时器、Promise 和异步函数等。同步操作包括普通函数调用、for 循环等。可以通过使用异步操作来提高程序的执行效率,避免程序的停顿,提高用户体验。

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

伪类和伪元素都是 CSS 中用于选择特定元素的方式,它们的区别如下:

  • 伪类(pseudo-class)是用来描述元素的特殊状态,比如:hover、:active等,通常是以单个冒号(:)表示。
  • 伪元素(pseudo-element)是用来描述元素的特殊部分,比如::before、::after等,通常是以双冒号(::)表示。

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元素前插入一个“前缀”文本。

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

箭头函数和普通函数在语法和功能上有一些不同之处:

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

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

32、SPA首屏加载速度慢怎么解决

如果 SPA(Single Page Application)首屏加载速度慢,可以考虑以下一些解决方案:

  • 代码压缩和打包:将代码进行压缩和打包,减少网络传输的时间,提升首屏加载速度。
  • 路由懒加载:采用路由懒加载技术,将不同路由下的组件分别打包成不同的代码块,按需加载,减少首屏加载的数据量,提升加载速度。
  • 图片优化:对于图片资源,可以采用图片懒加载、图片压缩、使用 WebP 格式等方式进行优化,减少网络传输的数据量。
  • 静态资源缓存:使用浏览器缓存等方式对静态资源进行缓存,减少网络请求次数,提升加载速度。
  • CDN 加速:使用 CDN(Content Delivery Network)进行加速,将静态资源分布在不同的 CDN 节点上,减少网络传输距离,提升加载速度。
  • 预渲染技术:使用预渲染技术,在服务器端预先生成页面的 HTML 和 CSS,提高首屏渲染速度。
    综合考虑实际情况,可以采用一些或多个方案,来优化 SPA 首屏加载速度。

33、说说重排和重绘的区别?触发条件有哪些?

重排(Layout)和重绘(Repaint)都是浏览器渲染页面时的关键步骤,它们之间的区别如下:

  • 重排:指对 DOM 结构进行修改后,浏览器需要重新计算元素的布局和位置,以及页面的几何属性,重新构建渲染树,并进行重新布局。重排是相对耗费时间和性能的操作。
  • 重绘:指对 DOM 结构进行修改后,浏览器需要重新绘制元素的外观和样式,但不需要改变其位置和大小,因为在重排时已经计算好了。重绘是比重排更轻量的操作。

在页面渲染过程中,当元素的布局、样式等属性发生变化时,就会触发重排和重绘。常见的触发条件有:

  • 页面初次渲染时;
  • 浏览器窗口大小发生变化;
  • 元素的位置、大小或布局发生变化;
  • 元素的内容发生变化;
  • 元素的样式发生变化;
  • 用户交互事件,如鼠标滚动、点击等。

为了减少页面的重排和重绘,可以采取以下优化策略:

  • 减少 DOM 操作,尽量减少对 DOM 的频繁修改;
  • 避免频繁读取样式值,尽可能合并操作;
  • 使用批量修改样式的方式;
  • 尽量避免使用 table 布局;
  • 避免使用复杂的 CSS 选择器;
  • 使用 CSS3 硬件加速等方式。

通过优化上述策略,可以有效减少页面的重排和重绘,提升页面的性能和响应速度。

34、Javascript如何实现继承?

在JavaScript中,可以通过以下几种方式来实现继承:

  • 原型链继承:将子类的原型对象指向父类的实例。这种方式可以实现简单的继承关系,但是如果父类的属性或方法是引用类型,那么子类实例共享这个引用类型,会导致子类实例之间相互影响。

  • 借用构造函数继承:通过在子类的构造函数中调用父类的构造函数来实现属性的继承。这种方式可以避免子类实例之间共享引用类型的问题,但是父类原型上定义的方法无法被继承。

  • 组合继承:结合原型链和借用构造函数的方式实现继承。子类的原型对象指向父类的实例,而子类的构造函数通过借用父类的构造函数来实现属性的继承。这种方式既可以继承父类的属性,也可以继承父类原型上的方法。

  • 原型式继承:通过使用一个空对象作为中介,将一个对象作为另一个对象的原型来实现继承。这种方式可以实现简单的对象之间的继承关系,但是会存在对象共享的问题。

  • 寄生式继承:在原型式继承的基础上,通过在新对象上增加方法来扩展对象。这种方式可以在不影响原对象的情况下扩展对象,但是也会存在对象共享的问题。

  • 寄生组合式继承:通过借用构造函数来继承属性,通过原型链的方式来继承方法。这种方式可以避免父类构造函数被调用多次的问题,同时也可以继承父类原型上的方法。

35、说说什么是严格模式,限制都有哪些?

严格模式(Strict Mode)是 ECMAScript 5 引入的一种运行模式,它主要对 JavaScript 的一些不安全的或者不合理的语法进行了限制,使代码更加规范、严谨,避免出现一些难以发现的错误。

严格模式的限制包括:

  • 变量必须声明后再使用,否则会抛出错误。
  • 函数的参数不能有同名属性,否则会抛出错误。
  • 不能使用 with 语句。
  • 在严格模式下,对一个对象进行只读属性的赋值会抛出错误。
  • 对象不能有重名的属性,否则会抛出错误。
  • 函数不能有重名的参数,否则会抛出错误。
  • eval 函数的作用域不再是调用它的函数的局部作用域。
  • 在严格模式下,delete 关键字删除变量时,需要用到变量名,否则会抛出错误。

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

打乱一个数组的顺序,可以使用 Fisher-Yates 洗牌算法,它的基本思路是从数组末尾开始,每次随机生成一个下标,将当前元素与该下标的元素交换位置,然后继续从数组末尾开始,直到数组首位元素都被交换过。这样就可以将数组打乱顺序。

以下是使用 Fisher-Yates 洗牌算法打乱数组顺序的代码实现:

var arr = [1,2,3,4,5,6,7,8,9,10];function shuffleArray(arr) {for (var i = arr.length - 1; i > 0; i--) {var j = Math.floor(Math.random() * (i + 1));var temp = arr[i];arr[i] = arr[j];arr[j] = temp;}return arr;
}console.log(shuffleArray(arr)); // 输出打乱顺序后的数组

37、Vue的自定义指令钩子函数有哪些?你用自定义指令做过什么?

Vue的自定义指令提供了一些钩子函数,可以在指令的不同生命周期中执行一些自定义的操作,常用的钩子函数有以下几个:

bind:指令第一次绑定到元素时调用,只调用一次,可以在这个钩子函数中进行初始化操作。
inserted:元素插入到 DOM 中时调用,但是不保证父节点已经插入到 DOM 中。
update:元素的值更新时调用,但是可能在子元素更新之前调用。
componentUpdated:元素和子元素的值都更新后调用。
unbind:指令与元素解绑时调用,只调用一次。

自定义指令可以实现一些特定的需求,比如实现一个点击外部区域关闭弹窗的功能:

Vue.directive('click-outside', {bind: function(el, binding, vnode) {el.clickOutsideEvent = function(event) {// 判断是否点击了 el 元素以外的区域if (!(el == event.target || el.contains(event.target))) {// 执行指令绑定的方法vnode.context[binding.expression](event);}};document.body.addEventListener('click', el.clickOutsideEvent);},unbind: function(el) {document.body.removeEventListener('click', el.clickOutsideEvent);},
});

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

在Vue中,可以通过路由的meta字段来标记需要缓存的组件,在路由配置中设置keepAlive: true。比如:

const router = new VueRouter({routes: [{path: '/A',component: A,meta: {keepAlive: true}},{path: '/B',component: B},{path: '/C',component: C}]
})

在需要取消缓存的组件中,可以在activated生命周期钩子中调用$destroy方法来销毁该组件实例。比如:

export default {activated() {this.$destroy();}
}

39、Vue2和Vue3中响应式原理及区别?

Vue2和Vue3中的响应式原理都是通过数据劫持实现的,但是具体实现方式有所不同。

Vue2使用了Object.defineProperty()方法来劫持数据,即将对象的属性转化为getter和setter,通过getter进行依赖收集,当setter被触发时,通知相关的依赖进行更新。这种方式有一些限制,比如无法监听到数组下标的变化以及新增属性的变化。

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

此外,Vue3中的响应式系统还引入了一些新特性,比如可对多个响应式对象进行操作的组合式API、全局API和应用级别的静态属性、更好的Typescript支持等等。

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

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

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

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

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

41、说说webpack中常见的Loader?解决了什么问题?

Webpack中的Loader是用来处理特定类型的文件,将它们转换为Webpack可以处理的模块。常见的Loader有以下几种:

  • babel-loader:将ES6/ES7代码转换成ES5语法,解决了浏览器兼容性问题。
  • style-loader/css-loader:将CSS文件注入到HTML文件中或将CSS文件转换成JS模块,解决了样式打包问题。
  • file-loader/url-loader:将图片、字体等静态资源转换成模块,解决了静态资源打包问题。
  • vue-loader:处理Vue文件,将其转换为JS模块。
  • json-loader:将JSON文件转换为JS模块。

除此之外,还有很多其他的Loader,例如less-loader、sass-loader、postcss-loader等等,都是为了解决Webpack打包过程中的特定问题。

Loader的作用是解决Webpack中不同类型的文件在打包过程中的处理问题,从而使得Webpack能够处理更多类型的文件,让打包更加便捷和高效。

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

SPA(Single Page Application)即单页面应用,它是一种 Web 应用的架构模式。它通过使用 JavaScript 动态地切换 HTML 内容,从而实现在不刷新整个页面的情况下更新页面的功能。SPA应用通常是基于前端框架(如Vue、React、Angular)实现的,通过路由控制不同的页面展示。

优点:

  • 用户体验好:不用频繁地刷新整个页面,加载速度快,有更好的交互体验;
  • 代码结构清晰:页面结构相对简单,易于维护;
  • 可维护性高:前后端分离,各自负责各自的领域,便于协作开发。

缺点:

  • SEO 问题:由于只有一个 HTML 页面,搜索引擎难以抓取到 SPA 应用中的内容,不利于 SEO 优化;
  • 首屏加载时间长:SPA 应用需要将所有资源加载完毕后才能展示出页面,导致首屏加载时间长;
  • 浏览器兼容性问题:需要兼容多个浏览器,增加了开发难度和工作量。

实现SPA应用通常使用前端框架、路由库、状态管理库等技术来实现。比如使用 Vue 可以使用 Vue Router 来实现路由控制,使用 Vuex 来管理状态。SPA 应用也需要考虑如何优化首屏加载时间,可以采用懒加载等方式来减少首屏需要加载的资源量。同时,需要注意 SEO 优化,可以采用服务端渲染或者预渲染等方式来解决。

43、Vue中组件和插件有什么区别?

Vue中的组件和插件都可以扩展Vue的功能,但它们的使用场景和实现方式不同。

组件是Vue中的一种基本概念,可以将一个页面拆分成多个独立的可重用组件,每个组件可以有自己的数据和方法,通过组合不同的组件来构建复杂的页面。组件的使用非常灵活,可以全局注册,也可以局部注册,可以接收props传递数据,也可以通过事件和vuex实现组件间的通信。

插件则是对Vue进行全局性的功能扩展,可以在Vue实例上添加新的方法、指令、过滤器、混入等,来扩展Vue的能力。插件通常是一些功能性的库,如axios、vue-router、vuex等,需要通过Vue.use()来安装并注册使用。

区别总结如下:

  • 组件是Vue的基本概念,可以拆分页面并重用;插件是对Vue进行全局性功能扩展的库。
  • 组件可以接收props传递数据,也可以通过事件和vuex实现通信;插件可以在Vue实例上添加新的方法、指令、过滤器、混入等。
  • 组件的使用非常灵活,可以全局或局部注册;插件一般需要通过Vue.use()安装并注册。
  • 组件的实现方式是Vue组件选项,插件的实现方式是包含install方法的对象或函数。
    总之,组件和插件都是Vue非常重要的扩展方式,我们可以根据具体的场景和需求来选择使用。

44、你了解vue的diff算法吗?说说看?

Vue的虚拟DOM中实现了一种高效的算法——Diff算法,用于比较新旧虚拟节点之间的差异,只对有变化的节点进行实际的DOM操作,从而避免了不必要的DOM操作,提高了应用的性能。

Vue中的Diff算法实现的大致流程如下:

  • 将旧节点与新节点进行比较,如果它们的标签不同,那么直接删除旧节点,创建并插入新节点;
  • 如果它们的标签相同,那么比较它们的属性差异,并更新节点的属性;
  • 如果它们的子节点不同,那么将子节点逐一进行比较,递归执行Diff算法。

Vue的Diff算法具有以下优点:

  • 减少了不必要的DOM操作,提高了应用的性能;
  • 可以最小化修改DOM的次数,从而减少浏览器的重排和重绘,提高了用户体验;
  • 对比算法的效率较高,能够快速地处理大量的节点。

但是,Vue的Diff算法也存在一些缺点:

  • 对于嵌套层级较深的节点,Diff算法的性能可能会受到影响;
  • 如果在数组中进行插入或删除等操作,Diff算法可能会出现误判的情况,从而导致界面不更新。

总体来说,Vue的Diff算法是一种高效的算法,能够大大提高应用的性能和用户体验,但在使用时需要注意一些问题,以避免出现不必要的问题。

45、Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 有什么不同?

Vue3.0 中的 Composition API 和 Vue2.x 中的 Options API 是两种不同的组件编写方式。下面是它们的一些不同之处:

  • 组合 API 可以将功能逻辑封装到单个函数中,这使得代码更容易重用和组合。相比之下,Options API 是基于定义组件选项对象的方式,其中每个选项对应一个功能。

  • Composition API 更加灵活,可以让开发者更加自由地组织代码。相比之下,Options API 需要严格按照 Vue 的组件选项规范来定义组件。

  • Composition API 更加强大,可以使用 React Hooks 的方式来管理组件状态、生命周期和逻辑。相比之下,Options API 只能在生命周期钩子中处理状态和逻辑。

  • Composition API 支持更好的 TypeScript 支持,因为可以使用泛型来标记状态和逻辑。相比之下,Options API 的类型定义通常需要手动编写。

需要注意的是,Options API 仍然是 Vue3.0 中的一个完全支持的特性,因此如果你习惯了 Options API,你完全可以继续使用它。但是,组合 API 是一个更加现代化和强大的方式来编写 Vue 组件,并且在大型应用中可能会更加适合。# 46、说一下Vue2数据响应式的原理和Vue3数据响应式原理的不同?

47、说说 React中的setState执行机制?

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

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

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

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

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

React中的组件分为两种:类组件和函数组件。

类组件是以ES6的class语法为基础,使用extends关键字继承React.Component类来定义的组件。类组件中必须包含一个render()方法,用于返回组件的结构,可以通过this.props来获取父组件传入的属性值,通过this.state来管理组件的状态。

函数组件是以函数的形式定义的组件,是纯函数,接收一个props参数,并返回一个React元素,没有自己的状态和生命周期函数,所以也被称为无状态组件。函数组件的优点是简洁、易于测试、性能更好,所以在React Hooks出现后,函数组件也得到了更多的使用。

类组件和函数组件的区别在于定义方式、组件的状态管理方式、生命周期函数等方面。类组件需要继承React.Component类,而函数组件直接是一个函数。类组件中的状态是通过this.state来管理的,而函数组件中的状态可以通过useState等Hooks来管理。生命周期函数在类组件中有,而在函数组件中有useEffect等Hooks来代替。

在React 16.8之前,函数组件缺少状态和生命周期等特性,只能作为展示性组件。但是React Hooks的出现解决了这个问题,使得函数组件能够管理自己的状态、处理副作用等操作,从而使得函数组件的应用范围更加广泛,性能也更加优秀。

49、说说对React Hooks的理解?解决了什么问题?

React Hooks 是 React 16.8 引入的一项新功能,它可以让函数组件也具有类组件的状态管理和生命周期函数等能力,从而简化 React 的编码方式。

在 React 中,组件的状态是需要通过 class 组件来管理的,而函数组件只能通过 props 来接收父组件传递的值,并且没有生命周期函数等特性。而 React Hooks 则打破了这种限制,可以让函数组件也能够具有管理状态和生命周期函数的能力。

React Hooks 解决了一些问题,比如:

  • 在 class 组件中,管理状态需要使用 this.state 和 this.setState,而使用 Hooks 可以通过 useState 简化状态管理的方式,更加直观易懂。
  • 在 class 组件中,生命周期函数的使用比较繁琐,而使用 Hooks 可以通过 useEffect 简化生命周期函数的使用。
  • 在 class 组件中,代码量较多,使用 Hooks 可以使代码更加简洁,更加易于维护。

React Hooks 的常用函数包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useImperativeHandle、useLayoutEffect 等。通过使用这些函数,可以在函数组件中管理状态、获取上下文、优化性能等。

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

useMemouseCallback 都是 React 中用于性能优化的 Hooks。

useMemo 可以缓存计算结果,避免每次重新计算,从而提升组件的渲染性能。它接收两个参数,第一个参数为计算函数,第二个参数为依赖数组,只有依赖数组中的值发生变化时,计算函数才会重新执行。应用场景包括:

  • 计算量较大的数据处理
  • 避免重复渲染子组件

举个例子,在一个表格组件中,如果每次渲染时都需要重新计算表格行数,会导致性能问题。可以使用 useMemo 来缓存计算结果:

const rowNumber = useMemo(() => {// 计算表格行数return data.length;
}, [data]);

useCallback 可以缓存函数,避免每次重新创建函数实例,从而提升组件的渲染性能。它接收两个参数,第一个参数为函数,第二个参数为依赖数组,只有依赖数组中的值发生变化时,函数才会重新创建。应用场景包括:

  • 传递给子组件的回调函数
  • 事件处理函数

举个例子,在一个列表组件中,如果每次渲染时都需要重新创建点击事件处理函数,会导致性能问题。可以使用 useCallback 来缓存函数:

const handleClick = useCallback((item) => {// 处理点击事件
}, []);

需要注意的是,使用 useMemouseCallback 并不是一定能提升性能,需要结合实际场景进行优化。同时,过度使用 useMemouseCallback 也可能会导致代码可读性下降,需要在性能和可读性之间进行权衡。

51、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的变化,根据定义的路由规则匹配相应的组件,并将组件渲染到应用程序的页面上,实现了前端路由的实现。

52、如何封装组件在不同的项目之间使用如何实现?

封装组件使其可以在不同的项目之间使用的一种常见的方式是通过将组件打包为可复用的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语句导入并使用。需要注意的是,引用组件时需要根据组件包中定义的不同包格式,选择合适的导入方式。

53、vue、react、angular 区别?

Vue、React和Angular都是当前流行的前端框架,它们有一些不同的特点和用法。

Vue是一个轻量级的框架,具有较为简单易懂的API和良好的文档,适合用于构建中小型应用。Vue使用了双向数据绑定和虚拟DOM等技术,以及一些方便的工具,如Vuex、Vue-router和Vue-cli等,使得开发者可以快速构建高效且易于维护的应用。

React是由Facebook开发的一个灵活且高效的框架,它采用了虚拟DOM、单向数据流和组件化等概念。React具有很好的可重用性和可组合性,以及很好的性能,但相比Vue有较为复杂的API和一些陡峭的学习曲线。

Angular是由Google开发的一个全面的框架,它采用了强类型、依赖注入和模块化等概念。Angular提供了很多强大的工具和功能,如路由、表单验证、HTTP服务和可复用的组件等,但相比Vue和React有较大的体积和较为复杂的API。

总的来说,Vue、React和Angular都有其适用场景和特点,开发者可以根据项目需求和个人偏好来选择合适的框架。

54、说说你对Redux的理解?其工作原理?

Redux是一个状态管理库,用于在JavaScript应用程序中管理应用程序的状态。它是一个单向数据流的模式,它将应用程序状态存储在单个store中,而不是分散在多个组件中。Redux的三个核心原则是单一的数据源、状态不可变和纯函数。

  • Redux的工作原理可以概括为以下几个步骤:

  • Action:使用Action来描述发生的事件。它是一个JavaScript对象,它必须包含一个type属性,表示事件类型,并且可以包含其他任意数据。

  • Reducer:Reducer负责根据Action更新状态。它是一个纯函数,接受当前状态和Action作为输入,返回新的状态。

  • Store:Store是一个包含整个应用程序状态的对象。它是由Redux的createStore函数创建的,包含三个方法:getState,dispatch和subscribe。

  • View:View使用store.getState()来获取应用程序状态,并根据状态来渲染UI。

通过这样的方式,Redux可以实现状态的集中管理,让应用程序的状态变得可预测和可控。

相比于其他状态管理库,Redux的优势在于它的设计思想非常简单,易于理解和学习,并且可以与各种UI库和框架结合使用。同时,Redux的严格规定也让它能够在大型复杂应用程序中得到更好的应用。

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

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

在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>

在这里,我们通过使用Vue的组件机制,定义了一个Tree组件,它接收一个list参数作为树形结构的数据。在组件的模板中,我们通过v-for指令遍历list数组,并递归调用自身(注:要把子组件注册为异步组件,避免无限递归)。这样,就可以实现树形结构的展示了。

通过以上示例,我们可以发现,递归非常适合处理树形结构这类重复性工作,它可以大大减少代码的复杂度和冗余度,提高代码的可维护性和可读性。

56、什么是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事件,在页面元素加载完毕后再显示页面。

57、说说你对预编译器的理解?

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

预编译器的优点包括:

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

缺点则包括:

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

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

58、shouldComponentUpdate 的作用

shouldComponentUpdate 是 React 生命周期中的一个方法,用于判断组件是否需要更新,可以在组件渲染前被调用,根据返回值来决定是否执行更新操作。该方法可以用来优化 React 应用的性能,避免不必要的渲染。

默认情况下,当父组件的状态或属性发生变化时,所有的子组件都会重新渲染,但是在某些情况下,某些子组件其实并不需要重新渲染,这时可以通过在子组件中实现 shouldComponentUpdate 方法来控制是否需要更新。

shouldComponentUpdate 接收两个参数:nextPropsnextState,分别表示下一个状态和属性。该方法返回一个布尔值,如果返回 true,则表示需要更新组件,反之则表示不需要更新组件。可以通过比较前后两个状态和属性的值,来判断是否需要更新组件。

当组件状态或属性改变时,如果使用了 shouldComponentUpdate 方法,React 会先调用该方法,然后再根据方法的返回值来决定是否执行更新操作。如果返回 true,则继续执行更新操作,如果返回 false,则停止更新操作,直接使用之前的状态和属性进行渲染,从而避免了不必要的渲染,提高了应用的性能。

59、概述下 React 中的事务处理逻辑

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

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

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

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

60、react组件的划分业务组件技术组件?

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

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

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

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

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

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

62、说说你对Fiber的理解和应用场景

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

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

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

63、react性能优化方案

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

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

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

64、简述flux 思想及Redux的应用

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

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

Redux的应用场景包括:

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

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

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

65、说说html和css渲染的过程是什么

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

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

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

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

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

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

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

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

DOM0、DOM2和DOM3都是JavaScript中用于处理事件的三种不同的API版本,它们之间有以下区别:

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

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

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

1、判断页面滚动到底部

在浏览器中判断页面是否滚动到底部,一般有以下两种方法:

(1)通过监听浏览器的scroll事件。当滚动条的位置与文档的高度之差等于可视区域的高度时,就可以认为页面已经滚动到了底部。

window.addEventListener('scroll', function() {const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 当前滚动条的位置const scrollHeight = document.documentElement.scrollHeight; // 文档高度const clientHeight = document.documentElement.clientHeight; // 可视区域的高度if (scrollTop + clientHeight >= scrollHeight) { // 如果滚动到底部 // do something}
});

(2)通过 Intersection Observer API。这是一种新的浏览器API,可以观察一个元素是否进入/退出浏览器的视窗。

const observer = new IntersectionObserver(function(entries) {if (entries[0].intersectionRatio <= 0) return; // 元素未进入视窗if (entries[0].intersectionRatio === 1) {// 元素完全进入视窗} else {// 元素部分进入视窗}
});observer.observe(targetElement); // 监听目标元素

2、判断页面中元素是否进入可视化区域

同样,我们可以借助上面的 Intersection Observer API 来实现元素是否进入可视化区域的判断。只需要创建一个IntersectionObserver对象,并绑定回调函数即可。

const observer = new IntersectionObserver(function(entries) {if (entries[0].intersectionRatio <= 0) return; // 元素未进入视窗if (entries[0].intersectionRatio === 1) {// 元素完全进入视窗} else {// 元素部分进入视窗}
});observer.observe(targetElement); // 监听目标元素

在回调函数中,第一个参数 entries 是被观测的目标元素,它是一个数组,每个元素都包含目标元素的一些信息:

isIntersecting:目标元素是否进入/退出视窗
intersectionRatio:目标元素进入视窗的比例(完全进入 = 1,完全退出 = 0)
target:目标元素本身
需要注意的是,Intersection Observer API 的兼容性存在一定的局限性,在使用前需要按照兼容性表格检查目标浏览器是否支持该API。

68、说一下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方法来实现状态的修改和异步操作,从而简化了应用状态管理的过程。

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

Vue2和Vue3之间有许多变化和区别,以下是其中的六点:

  • 性能提升:Vue3在内部使用了Proxy来代替Vue2中的Object.defineProperty,可以更高效地跟踪数据变化,从而提高性能。

  • 组合式 API:Vue3引入了组合式API,可以更好地组织组件的逻辑,使代码更具可读性和可维护性。

  • Composition API:Vue3的组合式API将组件的逻辑代码按照功能划分成多个小函数,而非Vue2中的选项式API,使得代码更加模块化。

  • V-model指令:Vue3中的v-model指令可以直接用于自定义组件,而Vue2则需要在组件中手动处理v-model。

  • Teleport组件:Vue3中引入了Teleport组件,可以轻松实现Portal的功能,将子组件渲染到父组件之外的DOM节点中。

更好的TypeScript支持:Vue3对TypeScript的支持更加完善,通过TypeScript可以更好地实现类型检查和自动补全。

70、说说对盒子模型的理解?

盒子模型是指我们网页中每个 HTML 元素都被看作是一个矩形的盒子,它由四条边界(外边距、边框、内边距和内容)组成,它们之间的关系可以用下面的公式来表示:

内容区宽度 = 元素宽度 - 左内边距 - 右内边距 - 左边框宽度 - 右边框宽度

内容区高度 = 元素高度 - 上内边距 - 下内边距 - 上边框宽度 - 下边框宽度

在这些边界中:

  • 内边距(padding):包裹在内容周围,用来增加元素内容与其边框的间距。
    边框(border):包裹在内边距周围,用来定义元素的边框。
  • 外边距(margin):包裹在边框周围,用来增加元素与其他元素之间的距离。

盒子模型对于网页布局来说非常重要,因为当我们设置元素的宽度、高度、内边距、边框、外边距等属性时,浏览器会根据盒子模型进行解析和渲染,如果不理解盒子模型的机制,就很容易出现一些布局上的问题。

理解盒子模型可以帮助我们更好的控制网页布局和样式,例如能够更好地调整文本与其周围元素的间距、更好地处理元素之间的空隙、更好地管理网页内的空间和排版等。

71、Css的选择器有哪些?优先级?哪些可以继承

CSS选择器有以下几种:

  • 标签选择器:选择指定 HTML 标签的元素,如 div、p、a 等。
  • 类选择器:选择指定类名的元素,以 . 开头,如 .box。
  • ID选择器:选择指定ID的元素,以 # 开头,如 #header。
  • 属性选择器:选择包含指定属性的元素,如 [title] 选择所有有 title 属性的元素。
  • 伪类选择器:选择元素的特殊状态,如 :hover 表示当鼠标悬停在元素上时的状态。
  • 伪元素选择器:选择元素的特殊部分,如 ::before 表示元素前面的内容。

CSS选择器的优先级如下:

  • !important声明的样式优先级最高;
  • 行内样式(内联样式);
  • ID选择器;
  • 类选择器、属性选择器、伪类选择器;
  • 标签选择器、伪元素选择器。

CSS中可继承的属性有以下几种:

  • font系列属性(font-family、font-size、font-weight、font-style、font-variant等)
  • text系列属性(text-indent、text-align、line-height、word-spacing、letter-spacing等)
  • color、visibility、cursor
  • border-collapse、white-space、background、list-style等。

72、元素水平垂直居中的方法有哪些?如果元素不定宽高呢?

在CSS中实现元素的水平垂直居中方式常常使用以下几种方法。

使用flex布局:将元素的父容器设置成display: flex,并设置子元素的align-items: center和justify-content: center,这样子元素就可以实现水平垂直居中。

使用绝对定位:将元素的父容器设置成相对定位position: relative,将元素设置成绝对定位position: absolute,并使用left: 50%和top: 50%将元素的中心点移到父容器的中央,最后再使用transform: translate(-50%, -50%)将元素向左、向上移动自身宽高的一半。

使用网格布局:将元素的父容器设置成display: grid,并使用align-items: center和justify-content: center使其水平垂直居中。

当元素不定宽高时,可以使用所有方法中的绝对定位方式,使用上述方法在将元素的中心点移到父容器的中央后,再使用transform: translate(-50%, -50%)将元素向左、向上移动自身宽高的一半。

例如,如果我们的HTML代码如下所示:

<div class="wrapper"><div class="box"><p>这是一段文本。</p></div>
</div>

可以采用绝对定位实现元素的水平垂直居中,可以将CSS样式设置为:

.wrapper {position: relative;width: 100%;height: 500px;background-color: #ccc;
}.box {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
}

这个样式可以让.box元素垂直居中于.wrapper容器中,即使它不定宽高。

73、怎么理解回流跟重绘?什么场景下会触发

回流(reflow)和重绘(repaint)是网页渲染时经常涉及到的两个概念,它们之间的关系是重绘是回流的一个子集。具体解释如下:

  • 回流:指元素的布局或几何属性发生变化时,浏览器重新计算元素的几何属性和页面布局,这个过程称为回流。回流会使其他的元素的布局也受到影响,可能会引起其他元素的重新布局和回流,导致性能问题。
  • 重绘:指元素的绘制属性发生变化时,浏览器会重新绘制元素的外观,但不会重新布局,这个过程称为重绘。例如,修改元素的颜色、背景颜色、边框颜色等属性都只会引起重绘。
    回流和重绘的出现,会对页面的性能产生负面影响。因此,需要尽量减少页面的回流和重绘,从而提高页面的性能。

以下是常见引起回流和重绘的场景:

  • 添加、删除、修改 DOM 元素。
  • 改变窗口大小,或者滚动页面。
  • 修改元素的样式,如改变元素的颜色、大小、位置等。
  • 读取某些属性,如 offsetWidth、offsetHeight、clientWidth、clientHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight 等。

有些属性值的变化,只会引起重绘而不会引起回流,例如改变元素的颜色、背景色等,而有些属性值的变化会同时引起回流和重绘,例如改变元素的宽度、高度等。

为了减少回流和重绘的次数,可以采取以下策略:

  • 尽量避免频繁读取计算样式属性和布局属性,避免多次触发回流和重绘。
  • 尽量批量修改 DOM 元素,减少对 DOM 的频繁操作。
  • 使用文档碎片(DocumentFragment)来操作 DOM 元素,减少 DOM 的访问次数。
  • 对于频繁重绘的元素,可以使用绝对定位来让它脱离文档流,从而避免其他元素的回流。
  • 避免在元素频繁改变大小、位置等属性时,使用 table 布局,因为 table 布局的元素变化时,需要触发整个表格的重新布局。
  • 对于需要读取元素尺寸和位置等信息的场景,可以使用 getBoundingClientRect() 方法,它可以返回一个矩形对象,包含元素的位置和尺寸信息,而且不会触发回流和重绘。

74、什么是响应式设计?响应式设计的基本原理是什么?如何做?

响应式设计是指能够根据不同设备的屏幕尺寸和分辨率自动调整页面布局和内容的设计方法。它的基本原理是使用弹性布局、媒体查询、图片自适应等技术实现页面的自适应性,从而使得页面在不同设备上都能够呈现出最佳的用户体验。

具体来说,响应式设计需要考虑以下几个方面:

  • 1.弹性布局:使用相对单位(如百分比、em、rem等)来设置元素的尺寸和位置,使得页面能够根据不同设备的尺寸自适应调整。

  • 2.媒体查询:根据不同设备的屏幕尺寸和分辨率,使用CSS3的媒体查询技术来加载不同的CSS样式文件,从而实现页面布局的自适应性。

  • 3.图片自适应:使用响应式图片技术(如srcset、picture等)来根据不同设备的屏幕尺寸加载适合的图片,从而提高页面加载速度和用户体验。

  • 4.内容筛选:根据不同设备的屏幕尺寸和分辨率,显示或隐藏某些内容,从而提高页面的可读性和可用性。

通过以上技术的组合应用,可以实现页面的自适应性,并在不同设备上呈现出最佳的用户体验。

75、如果要做优化,CSS提高性能的方法有哪些?

以下是几种提高CSS性能的方法:

  • 合并和压缩样式表:合并多个CSS样式表为一个,这样可以减少HTTP请求,从而提高页面的加载速度。同时,压缩CSS文件可以删除样式表中的注释和空格,以减少文件大小。

  • 避免使用通配符和浅层次选择器:通配符和浅层次选择器会影响渲染速度,避免使用它们可以提高页面的性能。

  • 减少使用选择器:在CSS中,选择器的使用越多,渲染速度就越慢。因此,尽量减少选择器的数量和使用范围。

  • 避免使用过于复杂的选择器:过于复杂的选择器也会降低渲染速度,例如在选择器中使用多个后代选择器或层次选择器。

  • 避免使用不必要的样式:尽量避免为元素指定不必要的样式,例如将font-family属性指定为系统默认字体Arial,而不是使用默认值inherit。

  • 使用CSS预处理器:CSS预处理器可以提高CSS的可维护性和可扩展性,同时还可以使用变量、函数、混合等高级特性,以提高CSS的性能和开发效率。

  • 使用GPU加速:使用CSS3中的GPU加速特性,例如transform和opacity属性,可以提高元素的渲染速度和性能。但是,过度使用GPU加速也会降低性能,因此要谨慎使用。

综上所述,我们可以通过合并、压缩和优化CSS样式表、避免使用通配符和选择器、精简样式、使用预处理器和GPU加速等方法,来提高CSS性能。

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

作为一名前端工程师,主要负责开发和维护Web应用程序的前端部分,包括网站的布局、样式、交互逻辑和数据展示等。前端工程师需要熟练掌握HTML、CSS、JavaScript等技术,能够实现页面的响应式设计和良好的用户交互体验,并且需要与后端开发人员进行协作,实现前后端的数据交互。

随着Web技术的不断发展,前端工程师的前景非常广阔。现在越来越多的企业和组织意识到Web应用程序的重要性,因此需要越来越多的前端工程师来开发和维护这些应用程序。同时,随着移动设备和平板电脑的普及,对于响应式设计和移动端开发的需求也越来越大,这为前端工程师提供了更多的机会和挑战。

77、说说JavaScript中的数据类型?存储上的差别?

JavaScript中有七种基本数据类型和一种复杂数据类型,分别为:

  • number(数字):用于表示数值,包括整数、浮点数和NaN(表示非数字)。

  • string(字符串):用于表示文本数据,使用一对单引号(')或双引号(")将文本括起来。

  • boolean(布尔值):用于表示真或假,只有两个值,即true和false。

  • null(空值):用于表示一个空值或不存在的对象。

  • undefined(未定义):用于表示变量未初始化或不存在。

  • symbol(符号):用于表示对象的唯一标识符(ES6引入)。

  • BigInt(大整数):用于表示任意长度的整数,以n作为后缀创建(ES10引入)。

除基本数据类型外,JavaScript还有一种复杂数据类型,即Object(对象),用于存储键值对。对象是一组无序的属性的集合,每个属性都有一个字符串类型的名称(键)和对应的值,可以是基本数据类型和其他对象。

在JavaScript中,基本数据类型的值存储在栈内存中,而对象类型的值存储在堆内存中,变量保存的是该对象在堆内存中的地址引用。
举个例子:

let a = 10; // 存储在栈内存中
let b = 'hello'; // 存储在栈内存中
let c = true; // 存储在栈内存中let obj = { name: 'Tom', age: 18 }; // 存储在堆内存中
let arr = [1, 2, 3]; // 存储在堆内存中

基本数据类型的值在赋值时是直接传递,而对象类型的值在赋值时是传递引用。也就是说,当我们将一个对象赋值给一个变量时,实际上该变量保存的是该对象在内存中的地址,而不是对象本身。因此,当我们修改对象时,其它引用该对象的变量也会受到影响。

值类型的数据在栈内存中比较简单,读取速度快,但容量小,无法存储大量数据。而使用对象存储数据,可以保存大量数据,但在读取时需要从堆内存中寻址,速度较慢。

至此,JavaScript中的数据类型和存储上的差别就介绍完毕了。

78、请简单叙述js数据类型判断的方法有哪些?

JavaScript数据类型判断的方法有以下几种:

  • typeof 操作符:用于判断一个变量的数据类型,返回一个字符串表示该变量的数据类型,包括 “undefined”、“boolean”、“number”、“string”、“bigint”、“symbol” 和 “object”。

  • instanceof 操作符:用于判断一个对象是否属于某个构造函数的实例,返回一个布尔值。

  • Object.prototype.toString() 方法:返回对象的数据类型,包括 “[object Object]”、“[object Array]”、“[object Function]” 等,需要注意的是该方法返回的都是字符串,需要进行截取。

  • constructor 属性:每个实例对象都有 constructor 属性,该属性指向创建该实例对象的构造函数。

  • Array.isArray() 方法:用于判断一个变量是否为数组类型,返回一个布尔值。

综上,不同的判断方法适用于不同的场景,需要根据具体情况选择。

79、说说你对闭包的理解?闭包使用场景

闭包是指在一个函数内部定义的函数,这个函数可以访问外层函数作用域中的变量和参数,即使外层函数已经执行完毕,也可以继续访问这些变量和参数。闭包可以保存函数所在的作用域,使其在函数执行完之后仍然可以被访问。

闭包有以下几个特点:

  • 函数内部定义函数:闭包就是一个函数,它在另一个函数内部定义。

  • 可以访问外部函数作用域中的变量:由于作用域链的特性,闭包可以访问外部函数作用域中的变量和参数。

  • 变量和作用域不会被回收:当函数执行完毕后,其内部定义的函数仍然可以访问其作用域中的变量和参数,因此这些变量和作用域不会被回收。

闭包的使用场景有很多,以下是一些常见的场景:

1、实现函数柯里化:函数柯里化是指将多个参数的函数转换成单个参数的函数的过程。通过闭包可以实现函数柯里化,例如下面这个例子:

function add(x) {return function(y) {return x + y;};
}let add5 = add(5);
console.log(add5(3)); // 8
console.log(add5(7)); // 12

2、封装私有变量:通过闭包可以封装私有变量,保护数据不被外界访问。例如下面这个例子:

function Counter() {let count = 0;return function() {return ++count;};
}let increment = Counter();
console.log(increment()); // 1
console.log(increment()); // 2

3、解决循环中的异步问题:在循环中使用异步函数时,由于变量作用域的问题,往往得不到期望的结果。通过使用闭包可以解决循环中的异步问题。例如下面这个例子:

for (let i = 0; i < 5; i++) {setTimeout(function() {console.log(i);}, 1000);
}

4、上述代码中,由于回调函数是异步执行的,输出结果可能不是期望的,这时候可以使用闭包来保证每个回调函数中的变量i都是独立的。例如:

for (let i = 0; i < 5; i++) {(function(j) {setTimeout(function() {console.log(j);}, 1000);})(i);
}

闭包可以用于许多场景,但需要谨慎使用,因为它会占用内存并且可能会导致变量泄漏等问题。

80、bind、call、apply 区别?如何实现一个bind

bind、call、apply 都是 JavaScript 中用于改变函数执行上下文的方法,它们的主要区别在于参数传递方式和函数调用的时机:

  • call 和 apply:改变函数执行时的上下文,并立即执行该函数。它们的第一个参数都是指定的函数执行上下文,区别在于传递给函数的参数的方式不同。call 会将参数逐个传递,而 apply 则会将参数放在数组中传递。
  • bind:返回一个新函数,并将原函数的执行上下文改变为绑定的对象。不同于 call 和 apply,bind 不会立即执行原函数,而是返回一个新的函数,需要手动调用这个新的函数才能执行。

实现一个 bind 方法,可以通过以下步骤:

  • 在函数原型上扩展一个新的方法 bind,该方法接受一个上下文对象作为第一个参数,返回一个新的函数。

  • 在新函数内部使用 apply 方法,将函数执行的上下文设置为上下文对象,同时将调用 bind 方法传入的参数列表也传递给原函数。

代码示例如下:

Function.prototype.bind = function (context) {var self = this;var args = Array.prototype.slice.call(arguments, 1);return function () {var bindArgs = Array.prototype.slice.call(arguments);return self.apply(context, args.concat(bindArgs));};
};

这样实现的 bind 方法可以将原函数绑定到指定的上下文对象上,并返回一个新的函数,调用这个新函数时,新函数内部的 this 指向绑定的上下文对象。

81、Javascript本地存储的方式有哪些?区别及应用场景

JavaScript本地存储技术有以下几种方式:

  • Cookie:通过在客户端存储数据来跟踪和识别用户,以便使网站的服务更加个性化。Cookie可以通过设置过期时间来控制其生命周期。

  • sessionStorage:在用户关闭浏览器之前存储数据,存储的数据仅在当前会话中可用,关闭标签页或者浏览器窗口后数据将失效。

  • localStorage:与sessionStorage类似,但存储的数据没有过期时间,持久保存在客户端,直到被手动删除。

  • IndexedDB:在客户端浏览器中使用的数据库系统,可以存储大量的结构化数据,支持事务操作和索引查询,但使用起来相对复杂。

这四种存储方式的区别在于:Cookie的大小限制为4KB,而sessionStorage和localStorage的大小限制为5MB以上,IndexedDB的大小限制相对较大;Cookie存储数据会发送到服务器端,需要带宽和时间成本,而其他三种存储方式存储在客户端浏览器中,访问速度快;sessionStorage只在当前会话中保存,而localStorage可以被跨会话访问,IndexedDB则是一个独立的数据库系统,使用起来相对复杂。不同的存储方式适用于不同的应用场景。

  • Cookie 适用于存储少量简单信息,并且需要发送到服务器端使用
  • sessionStorage 适用于需要在同一标签页或窗口中保留状态数据,比如表单或用户登录状态等
  • localStorage 适用于需要在不同标签页或浏览器会话都可以访问的数据,比如网站的配置信息或用户设置
  • IndexedDB 适用于需要离线可操作的、复杂的数据结构,比如离线时的内容上传及编辑、富媒体(音频、视频)等的存储和管理等。

总之,选择本地存储方式需要根据具体业务和应用场景来考虑。

82、请叙述Vue2和Vue3的diff算法的区别?

Vue 2.x 的 Virtual DOM 中采用的是基于"全量比对"的 diff 算法。即每次更新都对着 Virtual DOM 进行一次递归式的对比,比较一下旧的 Virtual DOM 和新的 Virtual DOM 之间的差别。然后再将差别更新到真实 DOM 中。

这种算法有一个缺陷是,每次更新之后,会产生一份全新的 Virtual DOM 树,这就会导致大量的重绘和回流,从而影响性能。

Vue 3.x 引入了新的 diff 算法,采用了类似于 React 中Fiber架构的算法,即根据组件本身的特点以及组件之间的关系建立一棵"虚拟链表",这样在更新时只需要更新与之相关的部分,不会再遍历整棵树,减少了不必要的性能浪费。

Vue 3.x 的 diff 算法还在更新了多个组件时使用了异步更新,将多个更新任务一次性提交到队列中,只需要一次性的更新 DOM,减少了界面的重绘次数。

此外,Vue 3.x 引入了新的编译器,支持静态提升和静态节点提取,以及更好的 TypeScript 支持,这些改进都使得 Vue 3.x 的性能和开发效率得到了很大的提升。

83、请简单叙述你对作用域链得理解?

JavaScript 的作用域规则指的是确定变量和函数在什么位置可以访问的规则,其中作用域链是一个非常重要的概念。

作用域链是用来描述一个函数执行时变量的查找路径,其由当前环境记录的一连串对象组成,它的最前端是当前执行的函数的活动对象,最后一个对象是全局执行环境的变量对象。当访问一个变量时,JavaScript 引擎会先从当前函数自己的活动对象中查找,如果找不到就向它的外层作用域链中的上一个对象(外部函数的活动对象)继续查找,直到找到或者抵达全局执行环境的变量对象位置为止。

作用域链决定了当前执行环境对包含变量和函数的访问权限,它是在函数创建的时候就已经形成的。JavaScript中的每个函数都会形成一个新的作用域,在函数内部定义的变量和函数只能在该函数内部访问,而在函数外部定义的变量和函数在整个文件范围内都是可见的。一个函数可以访问在它被创建时处于它父级作用域的变量,这种机制就被称为"闭包"。

理解作用域链的规则有助于我们编写更加精简高效的代码,避免出现变量和函数重名、避免滥用全局变量等问题。同时,在前端开发中,对作用域链的理解也帮助我们更好的理解JavaScript框架和库的底层实现。

84、Vue3中的生命周期函数的变化以及含义

Vue 3.x 中的生命周期函数与 Vue 2.x 有所不同,主要有以下变化:

  • beforeCreate 和 created 合并为一个新的生命周期函数 - setup。setup 函数是组件内仅次于 props 解析的第二个调用的函数,该函数接收 props 对象及相关的上下文对象 (包括 attrs, slots, emit 等) 作为参数,并且它是一个普通函数而非响应式的函数。通过 setup 函数,我们可以完成类似于 beforeCreate 和 created 生命周期的操作,例如初始 data 和组件方法等。

  • deactivated 和 activated 已经被废弃,而 Suspense 和 Error Boundaries 组件则提供了一种新的处理异步操作和错误的方案,使得我们可以更加灵活地控制组件的渲染和行为。

  • beforeMount 和 mounted 生命周期函数的含义与Vue 2.x 中保持一致。它们在组件挂载前后会分别触发,可以在 beforeMount 钩子内进行一些组件挂载前的准备工作,比如获取初始数据和计算属性等;在 mounted 钩子内可以进行与 DOM 操作相关的逻辑,例如渲染 canvas 或添加事件监听器等工作。

  • beforeUpdate 和 updated 生命周期也保持了与 Vue 2.x 相同的含义,分别表示数据更新前和数据更新后的时刻。在这两个生命周期函数内可以实现与数据更新相关的操作,比如手动调用异步操作。

  • beforeUnmount 和 unmounted 表示组件卸载前和卸载后的时刻。在 beforeUnmount 钩子内可以进行与组件自身相关的清理工作,比如禁用定时器、取消事件监听器等,而在 unmounted 钩子内可以执行与组件自身无关但需要关闭的工作,例如释放占用的内存和其他资源等。

在Vue 3.x 中,生命周期函数的变化主要是为了更好地支持组合和异步操作,使得开发者可以更加灵活地在不同的时刻引入和执行代码。

85、Vue3中自定义指令生命周期的变化及含义

Vue3中自定义指令的生命周期相比于Vue2有所变化,主要包括以下几个:

  • bind 生命周期被重命名为 beforeMount
    在 Vue3 中,bind 生命周期被重命名为 beforeMount,表示指令和组件实例的挂载准备工作已经完成,但是尚未挂载到页面上。

  • update 生命周期被重命名为 mounted
    在 Vue3 中,update 生命周期被重命名为 mounted,表示指令和组件已经挂载到页面上,此时可以访问 DOM 节点。

  • componentUpdated 生命周期被重命名为 updated
    在 Vue3 中,componentUpdated 生命周期被重命名为 updated,表示组件已经更新完毕,可以访问 DOM 节点。

  • unbind 生命周期被重命名为 beforeUnmount
    在 Vue3 中,unbind 生命周期被重命名为 beforeUnmount,表示指令和组件即将被卸载。

这些生命周期的变化主要是为了和组件生命周期保持一致,方便开发者理解和使用自定义指令。

在使用自定义指令时,我们可以根据具体的场景选择不同的生命周期钩子函数来处理指令的功能。比如,在 mounted 钩子函数中可以访问 DOM 节点,可以用来操作 DOM,而在 updated 钩子函数中可以对组件进行更新操作等。

需要注意的是,Vue3 中的自定义指令也可以通过使用 watchEffect 和 watch 等函数来实现响应式数据的更新,这也是 Vue3 中响应式系统的一大特点。

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

Vue 3.x 中的组合式 API 对比 Vue 2.x 中的 Options API,在语法和使用方式上都有很大的不同。Vue 3.x 中的组合 API 主要包括以下几个部分:

  • reactive 和 ref:通过 reactive 或者 ref 函数对数据进行响应式处理。其中 reactive 主要用于处理复杂对象,而 ref 则用于处理基本数据类型。
  • computed 和 watchEffect:通过 computed 函数对数据进行计算,从而生成新的响应式数据,而 watchEffect 则用于监听数据的变化,并且在数据变化时执行一些操作,比如长链接 WebSocket 通信等。
  • provide 和 inject:通过 provide 和 inject 函数实现跨越组件树的组件通信。父组件通过 provide 函数提供数据,子组件则通过 inject 函数获取数据。
  • 生命周期钩子函数:Vue 3.x 中的组合 API 仍然包含了 beforeMount、mounted、beforeUpdate、updated、beforeUnmount 和 unmounted 等生命周期钩子函数。

相比之下,Vue 2.x 中的 Options API 则通过大量的选项对象实现组件的配置和管理。而 Vue 3.x 中的组合 API 则更加关注组件中动态数据的处理和组件之间的通信,同时其 API 使用起来更加直观和简洁,可以帮助开发者更加容易地编写高效的代码。其最大的优势,恰恰在于使得不再需要关注 runtime-core 的 api 来构建渲染逻辑。

87、 什么是跨域?如何解决跨域问题?

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

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

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

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

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

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

88、 什么是浮动?如何清除浮动?

浮动(float)是 CSS 中的一种布局方式,其作用是将元素从正常的文档流中移除,并使其向左或向右浮动。通常用来实现文字环绕效果,以及实现多列布局等效果。

浮动元素在文档流中不占据空间,而是从文档流中脱离出来,这也就造成了在某些情况下可能会影响其他元素的布局,比如撑不开父元素、位置异常等问题。为了解决这些问题,我们需要清除浮动。

清除浮动可以使用以下几种方法:

1、Clearfix:在父元素中使用 clearfix 类或者伪元素进行清除浮动。这种方法可以解决标准文档流中很多让人困扰的布局问题。

.clearfix::after {content: "";display: block;clear: both;
}

2、BFC (块级格式化上下文):当父元素被设置为 BFC 后,就可以自动清除子元素的浮动。这种方法需要额外注意一些细节问题,但是不会像 Clearfix 一样会产生额外内容。

.parent {overflow: auto;  /* 或者使用其他触发 BFC 的方法 */
}

3、Grid 布局和 Flex 布局:使用 Grid 布局或 Flex 布局可以不需要考虑 clearfix 和 BFC 的技巧,而是使得正确的布局变得更加容易。

清除浮动的方法都是通过一些额外的元素或属性,来使得当前元素变成一个干净的盒子,可以避免它对后续元素的影响。

89、 请简述HTML5的新特性。

HTML5是HTML的第五个版本,相比于之前的版本,它引入了许多新的特性。以下是HTML5的一些主要特性:

  • 新的语义化元素:HTML5提供了一些新的语义化元素,如

    ,

    ,

前端面试题【131道】相关推荐

  1. 2020前端面试题72道总结

    1.说说你对盒子模型的理解? 当对一个文档进行布局的时候,浏览器的渲染引擎会根据标准之一的css基础框盒模型,将所有元素表示为一个个矩形的盒子 一个盒子由四部分组成: content 内容区域 pad ...

  2. java 前端页面传过来的值怎么防止篡改_答对这40道经典web前端面试题,想不拿到offer都难!...

    想成功就业web前端工程师,想要能高薪就业,那么除了好的web前端技能以外,还得有好的面试技巧,如果提前就了解更多企业的面试要求及面试题目,那么可以让我们的面试成功的几率大大的提高. 今天小编就整理了 ...

  3. 【前端面试题】—53道常见NodeJS基础面试题(附答案)

    说到前端就不得不提到后端,我们给用户展示页面所需的数据正是从后端获取的,所以了解后端的运行原理和技术的实现很有必要. Node. js是一个不错的选择,它是基于JavaScript语法的一套服务器端( ...

  4. 【前端面试题】—21道有关移动端的面试题(附答案)

    前端发展到今天,移动端的流量已经超越了PC端.比如对绝大部分人来说,每天使用手机上网的时间要远高于使用笔记本电脑.计算机的上网时间.因此移动端变得越来越重要.每个人的手机屏幕大小不同.系统不同,因此移 ...

  5. 【前端面试题】21道有关移动端的面试题(附答案)

    [前端面试题]21道有关移动端的面试题(附答案) 前端发展到今天,移动端的流量已经超越了PC端.比如对绝大部分人来说,每天使用手机上网的时间要远高于使用笔记本电脑.计算机的上网时间.因此移动端变得越来 ...

  6. 20道vue前端面试题总结

    vue前端面试题 双向绑定是什么意思? 说一下v-model的原理 MVC与MVVM的区别 methods方法与computed计算属性区别 再说一下Computed和Watch vue的生命周期有哪 ...

  7. 一份来自于全球的前端面试题清单,看看老外喜欢考哪些题(部分有答案)

    方括号中的蓝色标题是题目的出处,有些题目在原址内包含答案.搜集的大部分外国前端面试题没有做翻译,单词并不难,大家应该看得懂.题目旁边的方括号内, 简单记录了与此题相关的知识点.总共大概一千多道,包含国 ...

  8. 前端面试题集锦——JavaScript

    前端面试题集锦--JavaScript 1.请你谈谈 Cookie 的优缺点 cookie是存储于访问者计算机中的变量 cookie是浏览器提供的一种机制 可以由JavaScript对其进行控制(设置 ...

  9. 金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上

    引言 元旦匆匆而过,2020年的春节又接踵而来,大家除了忙的提着裤子加班.年底冲冲冲外,还有着对于明年的迷茫和期待!2019年有多少苦涩心酸,2020年就有更多幸福美好,加油,奥利给!怀着一颗积极向上 ...

最新文章

  1. 1145 Hashing - Average Search Time
  2. 麦肯锡报告:传统车企正面临出行的数字化颠覆
  3. shell脚本详解(二)——条件测试、if语句和case分支语句
  4. linux100day(day3)--常用文本处理命令和vim文本编辑器
  5. 16. OD-破解序列号验证机算法
  6. 京东健康暗盘涨幅超27% 成交额超1.6亿港元
  7. Linux 在不重启的情况下识别新挂载的磁盘
  8. android studio中添加新的model时候
  9. Eclipse 更新Android SDK后,新建项目出现appcompat_v7project的相关问题
  10. 挑战程序设计竞赛: Fence Repair
  11. 大数据项目实战二之电信大数据项目
  12. fiddler对模拟器抓包
  13. 小程序源码:微信智慧外链接致富版微信小程序源码下载,支持多端转换-多玩法安装简单
  14. 浏览器兼容性问题(IE9+;PC)
  15. KnockOut+TypeScript+上传图片(oos功能)以及导入Excel文件(oos功能)并回显插入
  16. 关于海外博士和启明计划
  17. 深耕模具细分领域20载 德惠创新研发领跑行业
  18. 【千锋】网络安全学习笔记(三)
  19. 直播界要哭了!罗永浩进军电商直播:最可怕的对手,永远来自未知领域!
  20. 1290 越狱(逆向思维-快速幂)

热门文章

  1. android中奖名单轮播,iOS模拟中奖名单循环滚动效果
  2. 5g宣传方案_活动创意策划方案要向“5G时代”看齐
  3. 使用 font-spider 对 webfont 网页字体进行压缩
  4. 点击html内任意图片放大,再点击关闭放大图片
  5. 5G网下通过网络编码增强转发策略的NDN物联网内容分发模型
  6. 心流:提升幸福的奥秘
  7. U-BOOT中文文档 概述与配置选项
  8. 8种减肥法,让你的APP瘦身30%
  9. TiggerRamDisk的超详细使用教程(亲测成功)
  10. weka的java环境配置_weka学习(安装和部署)