2022届秋招保利威前端面试

2022届秋招保利威前端面试

原文网址:https://www.nowcoder.com/discuss/353158719997419520?sourceSSR=search

对象的浅拷贝和深拷贝如何实现?

浅拷贝:

浅拷贝只复制对象的第一层属性,不会递归复制嵌套对象。

使用Object.assign()

Object.assign() 静态方法将一个或者多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象。

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target);
// Expected output: true

使用展开运算符

let obj1 = {
    name: "jack",
    age: 18
  }
  let obj2 = {}
  obj2 = { ...obj1 }
  console.log(obj2)
  输出
  {
    "name": "jack",
    "age": 18
}

深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

使用第三方库_.cloneDeep()

const _ = require('lodash');
const obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

使用JSON.stringify()

let newobj = JSON.parse(JSON.stringify(obj))//深拷贝

JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串

JSON.parse() 方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象

但是这种方式存在弊端,会忽略undefinedsymbol函数

1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;

2.如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;

3.如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;

4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

5.JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;

6.如果对象中存在循环引用的情况也无法正确实现深拷贝;

手写深拷贝(通过递归实现)

function checkType(target){
	return Object.prototype.toString.call(target).slice(8,-1)
}
function deepClone(data){
	let type = checkType(data)
	let obj
	if(type === 'Array'){
		obj = []
		for(let i = 0; i < data.length; i++){
			obj.push(deepClone(data[i]))
		}
	}else if(type === 'Object'){
		obj = {}
		for(const key in data){
			if(data.hasOwnProperty(key)){
				obj[key] = deepClone(data[key])
			}
		}
	}else{
		return data
	}
	return obj
}

事件委托是什么?有什么例子?为什么要绑定在父元素而不是子元素?

事件委托(Event delegation)是一种事件处理模式,它将事件处理程序绑定到一个父元素上,以代替直接在子元素上进行事件绑定。当事件触发时,事件会冒泡到父元素,然后由父元素的事件处理程序来处理。

举个例子,假设有一个HTML列表,其中包含多个列表项(li元素)。如果要为每个列表项添加点击事件处理程序,传统的做法是为每个列表项分别绑定事件处理程序。而采用事件委托的方式,可以将事件处理程序绑定到整个列表的父元素上,然后通过事件冒泡机制来处理每个列表项的点击事件。

  • Item 1
  • Item 2
  • Item 3
  • Item 4

为什么要将事件绑定在父元素而不是子元素呢?有以下几个原因:

  1. 减少事件绑定的数量:通过事件委托,只需要为父元素绑定一个事件处理程序,而不是为每个子元素分别绑定。这在处理大量元素时可以提高性能和代码的可维护性。
  2. 动态添加或删除元素:如果通过JavaScript动态地添加或删除子元素,事件委托可以自动地处理这些新添加或删除的元素的事件,无需手动重新绑定事件处理程序。
  3. 简化代码结构:通过将事件处理程序集中在父元素上,可以简化代码结构,减少重复的代码,并使代码更易读和维护

axios的返回值是promise,请说说你对promise的理解?

Promise(承诺)是JavaScript中用于处理异步操作的对象。它代表了一个尚未完成但最终会完成的操作,并可以获取其结果或错误。

Promise有三种状态:

  1. Pending(进行中):初始状态,表示操作尚未完成。
  2. Fulfilled(已完成):表示操作成功完成。
  3. Rejected(已拒绝):表示操作失败。

当创建一个Promise对象时,可以传入一个执行器函数(executor function),该函数接受两个参数:resolve和reject。通过调用resolve函数,可以将Promise从Pending状态转变为Fulfilled状态,并传递一个值作为操作的结果。通过调用reject函数,可以将Promise从Pending状态转变为Rejected状态,并传递一个错误对象作为操作的原因。

Promise对象具有then方法,它接受两个回调函数作为参数:onFulfilled和onRejected。当Promise状态变为Fulfilled时,会调用onFulfilled回调函数,并传递操作结果作为参数;当Promise状态变为Rejected时,会调用onRejected回调函数,并传递错误对象作为参数。

Promise还提供了其他方法,例如catch方法用于捕获错误、finally方法用于指定无论Promise状态如何都要执行的回调函数等。

Promise的主要优势在于它简化了处理异步操作的流程和提供了更好的代码结构。它可以避免回调地狱(callback hell)的问题,使异步操作更易于理解和组织。通过使用Promise,可以将异步代码写成连续的链式调用,使其更具可读性和可维护性。

对于axios来说,它返回的是一个Promise对象,可以通过调用then方法来处理异步请求的结果,或者通过catch方法来捕获可能发生的错误。这样可以更方便地进行异步请求的处理和错误处理。

vue生命周期的理解

按照套路背就好了

v-for的key的作用是什么?

在Vue.js 2中,key属性用于辨识和跟踪在使用v-for指令时渲染的DOM元素的身份。它在Vue的虚拟DOM算法中起着重要的作用。

当使用v-for指令循环渲染一个数据列表时,Vue会生成一组DOM元素来表示每个列表项。为了优化性能和提高渲染效率,Vue会尽可能地重用已经存在的DOM元素,而不是重新创建新的元素。

这就引出了一个问题:如何判断两个元素是否是相同的,并且可以重用?这就是key属性的作用。Vue使用key属性来标识每个生成的DOM元素的唯一性。它们不是组件的属性,而是Vue特定的属性。

当数据发生变化,Vue会比较新的数据和旧的数据,并根据key属性来判断哪些元素需要被更新、重用或删除。如果两个元素具有相同的key,Vue会假定它们是相同的元素,从而重用之前的DOM元素,避免不必要的重新渲染。

key属性的原理可以总结如下:

1.key属性必须是唯一的,通常使用具有唯一标识的数据来生成。
2.在使用v-for指令渲染列表时,为每个列表项添加一个key属性。
3.当数据更新时,Vue会比较新旧数据,并根据key属性来确定哪些元素需要进行重新渲染、重用或删除。
4.如果两个元素具有相同的key,Vue会假定它们是相同的元素,并重用之前的DOM元素。

通过合理使用key属性,可以最大限度地提高Vue应用的性能和渲染效率,特别是在涉及列表渲染的情况下。

虚拟DOM中key的作用

key是虚拟DOM对象的标识,当数据发生变化的时候,vue会根据新数据生成新的虚拟DOM,随后进行新虚拟DOM和旧的虚拟DOM比较,比较规则如下:

比较规则:

1.旧虚拟DOM中找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没有发生改变,则直接使用之前的真实DOM

若虚拟DOM中的内容发生改变,则生成新的真实DOM,替换掉页面中真实的DOM

2.旧虚拟DOM中未找到与新虚拟DOM相同的key:

创建新的真实DOM,随后渲染到页面上

使用index作为key可能会发生的问题:

1.若对数据进行逆序添加、逆序删除等破坏顺序的操作:

会产生没有必要的真实DOM更新,界面效果没问题,但是效率低下

2.如果结构中还包含输入类的DOM:

会产生错误的DOM更新,界面有问题

说说vuex的属性?

  1. State(状态): Vuex的核心是一个包含所有组件共享状态的单一数据源,称为state。State是响应式的,当它发生变化时,所有依赖于它的组件都会自动更新。
  2. Getters(获取器): Getters用于从state中派生出一些衍生数据,类似于Vue组件中的计算属性。它们可以对state进行过滤、计算和组合,然后在组件中使用。
  3. Mutations(变更): Mutations是一种修改state的方式。它们是同步的操作,用于处理同步任务。每个mutation都有一个字符串类型的事件类型和一个回调函数,当触发一个mutation时,回调函数会被调用来修改state。
  4. Actions(动作): Actions用于处理异步任务和复杂的业务逻辑。它们可以包含多个mutation的提交,可以通过调用mutations来间接修改state。Actions可以是异步的,可以执行一些异步操作(如API请求),然后提交一个或多个mutation。
  5. Modules(模块): Vuex允许将store分割为模块,每个模块拥有自己的state、getters、mutations和actions。这使得大型应用程序的状态管理更加灵活和可维护。

vue-router的history和hash模式的区别?什么时候用history?什么时候用hash

Vue Router提供了两种路由模式:history模式和hash模式。它们在URL的表现形式和浏览器兼容性上有所不同。

  1. Hash模式:在hash模式下,URL中会以"#“符号来表示路由的路径。例如,http://example.com/#/about。这种模式的好处是它在所有现代浏览器中都能正常工作,因为改变hash部分不会导致浏览器向服务器发送请求。但是,它的缺点是URL中带有冗余的”#"符号,不够美观,可能不太友好。
  2. History模式:在history模式下,URL没有冗余的"#"符号,而是直接使用常规的URL路径来表示路由的路径。例如,http://example.com/about。这种模式看起来更加干净和友好。它通过使用HTML5的History API来管理URL,可以动态地修改URL而不刷新页面。然而,history模式在一些较旧的浏览器上可能不被支持,因此需要服务器的支持来处理路由请求。

什么时候使用History模式?

  • 当你想要更美观、更符合常规URL的路由路径时,可以使用history模式。
  • 当你的应用程序的部署环境可以处理路由请求并返回正确的页面时,可以使用history模式。
  • 当你的应用程序使用Vue.js和服务器端渲染(SSR)时,推荐使用history模式,因为SSR可以处理路由请求。

什么时候使用Hash模式?

  • 当你的应用程序需要在所有现代浏览器中运行,包括较旧的浏览器时,可以使用hash模式。
  • 当你的应用程序部署在没有服务器端支持的环境中(例如静态文件服务器),可以使用hash模式。

请说说你对缓存的理解?还有没有对其他缓存有了解?(除了强缓存、协商缓存)

  1. 本地缓存(Local Cache): 本地缓存是将数据存储在客户端(通常是内存或磁盘)上的一种缓存方式。它可以减少对服务器的请求次数,提高响应速度。常见的本地缓存技术有:内存缓存(如Redis)、文件缓存和数据库缓存。
  2. 分布式缓存(Distributed Cache): 分布式缓存是将数据存储在分布式环境中的多个节点上,以提供高可用性和可伸缩性。常见的分布式缓存系统有:Memcached和Redis。
  3. CDN缓存(Content Delivery Network): CDN缓存是通过将内容分发到位于全球各地的边缘节点上,使用户能够更快地访问数据。CDN缓存可以存储静态文件(如图片、CSS和JavaScript文件)以及动态内容的缓存副本,减轻源服务器的负载并提高用户访问速度。
  4. 数据库查询缓存: 数据库查询缓存是将数据库查询的结果缓存起来,以避免重复的数据库查询操作。当相同的查询被频繁执行时,可以从缓存中获取结果,减少对数据库的访问压力。
  5. 对象缓存: 对象缓存是将对象存储在缓存中,以避免重新计算或重新获取对象的开销。对象缓存通常用于存储经过计算或从其他数据源获取的复杂对象,以提高应用程序的性能和响应速度。

强制缓存

不会向服务器发送请求,直接从缓存中读取资源,从chrome控制台中的network选项中可以看到该请求返回的状态码是200

协商缓存

在使用本地缓存之前,需要向服务器发送请求,服务器会根据这个请求的request header中的一些参数来判断是否命中协商缓存,如果名字,则返回304的状态码并带上新的response header通知浏览器从缓存中读取资源,协商缓存可以解决强制缓存的情况下资源不更新的问题

强制缓存中header的参数(响应头)

Expires:response header里的过期时间

Cache-Control:当值设为max-age=数字时,则代表这个请求返回资源的缓存时间

Cache-Control除了该字段外,还有下面几个比较常用的设置值:

no-cache:不使用本地缓存。需要使用协商缓存,先与服务器确认返回的响应是否被修改,如果之前的响应中存在ETag,那么请求的时候会与服务器验证,如果资源未被修改,则可以避免重新下载

no-store:禁止使用浏览器缓存

public:可以被所有用户缓存,包括终端用户和CDN等中间代理服务器

private:只能被终端用户的浏览器缓存,不允许CDN等中间缓存服务器缓存

协商缓存

Cache-Control:no-cache

Last-Modify/If-Modify/Since:浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-Modify是一个时间标识该资源的最后修改时间,当浏览器再次请求资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。 因为Last-Modify的单位是秒,所以1秒钟之内被修改多次是不知道的,所以就有了下面的ETag

Etag/If-none-Match:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识。web服务器收到的请求会根据收到的哈希值进行比较判断资源是否被修改

什么是跨域?如何实现跨域?cors跨域的原理?

跨域(Cross-Origin)是指在前端网页中,当一个请求的源(Origin)与当前页面的源不同,即两个网页的域名、协议或端口不一致时,就会发生跨域问题。

由于安全原因,现代浏览器限制了跨域请求的访问。这是因为如果没有跨域限制,恶意网站就可以通过在用户浏览器中执行脚本来获取其他网站的数据,从而导致安全问题。

要实现跨域请求,有几种常见的方法:

  1. JSONP(JSON with Padding):利用

你可能感兴趣的:(模拟面试,前端,面试,javascript)