# 面试题(十)

  • call, apply, bind 的区别?怎么实现
  • 介绍一下vue的生命周期
  • 16进制颜色转换为rgb
  • keep-alive了解吗
  • 聊聊LRU算法
  • Vue中组件生命周期调用顺序
  • 你都做过哪些Vue的性能优化
  • npm install 原理
  • Map,weakMap,Set,weakSet
  • 什么是尾递归和尾调用
  • link 与 @import 的区别
  • 数组 map()forEach() 方法的区别?
  • 什么是静态网站

# call, apply, bind 的区别?怎么实现

都是用来改变函数的 this 对象的指向的。

第一个参数都是 this 要指向的对象。

都可以利用后续参数传参。 区别:

call 接受函数传参方式为:fn.call(this, 1, 2, 3)

apply 接受函数传参方式为:fn.apply(this,[1, 2, 3])

bind 的返回值为一个新的函数,需要再次调用: fn.bind(this)(1, 2, 3)

# vue的生命周期

# beforeCreate( 创建前 )

使用这个钩子,组件的选项对象并没有创建,el和data都还没初始化,所以data、methods和computed等都用不了。一般用来在组件挂在之前渲染一些东西。

# created ( 创建后 )

这时候上面的data、methods、computed都已经创建完成了,数据观测,属性和方法的运算,watch/event事件回调都完成了,但这时候挂载阶段mount还没开始,是el并没有完成。这是最常用的生命周期钩子,可以调用methods中的方法,改变data中的数据,并且修改可以通过vue的响应式绑定体现在页面上,,获取computed中的计算属性等等,通常我们可以在这里对实例进行预处理,也在这里发ajax请求,这个周期中是没有什么方法来对实例化过程进行拦截的,因此假如有某些数据必须获取才允许进入页面的话,并不适合在这个方法发请求,建议在组件路由钩子beforeRouteEnter(路由守卫)中完成

# beforeMount(挂载之前)

挂载之前被调用,render(渲染)函数首次被调用(虚拟DOM),这里已经完成了模板编译,data里面的数据和模板会生产HTML,这里el也完成了,但并没有挂载到html页面上。

# mounted(挂载)

挂载完成了,这时候HTML模板会被渲染到HTML中,还可以做一些ajax操作。但mounted只能执行一次。

# beforeUpdate(更新之前)

更新指数据更新,发生在虚拟DOM重新渲染和补丁之前,在这个钩子中可以更改状态而不发生重绘。

# updated(更新后)

在由于数据更改导致地虚拟DOM重新渲染和打补丁只会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器端渲染期间不被调用

# beforeDestroy(销毁前)

在实例销毁前调用,但实例还可以用。

这里还可以使用this,一般用来做重置操作,比如清除定时器和DOM监听事件。

# destroyed(销毁后)

在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用

# 16进制颜色转换为rgb

function hex2rgb(hex) {
	const str = hex.slice(1),
		res = []
	if (str.length === 3) {
		for (const w of str) {
			res.push(parseInt(w + w, 16))
		}
	} else {
		for (let i = 0; i < 6; i += 2) {
			res.push(parseInt(str[i] + str[i + 1], 16))
		}
	}
	return res
}

# keep-alive了解吗

keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

# 一个场景

用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。 总的来说,keep-alive用于保存组件的渲染状态

keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

常用的两个属性include/exclude,允许组件有条件的进行缓存。

两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。

keep-alive的中还运用了LRU(Least Recently Used)算法。

使用 vue-des-tools 可以查看当前组件是否缓存

<keep-alive> 是一个抽象组件,

  • 首次渲染的时候设置缓存
  • 缓存渲染的时候不会执行组件的 created、mounted 等钩子函数, 而是对缓存的组件执行patch 过程,最后直接更新到目标元素。

使用 LRU 缓存策略对组件进行缓存

  • 命中缓存,则直接返回缓存,同时更新缓存key的位置
  • 不命中缓存则设置进缓存,同时检查缓存的实例数量是否超过 max

# 聊聊LRU算法

操作系统内存管理:分页,分段,段页结合

LRU(最近最久未使用)属于页面置换算法中的一种,其他还有 FIFO(先进先出算法),OPT(最佳置换算法)等等

操作系统页面置换算法 (opens new window)

leetcode146:LRU缓存机制 (opens new window)

题解 (opens new window)

# Vue中组件生命周期调用顺序

组件的调用顺序都是先父后子,渲染完成的顺序是先子后父

组件的销毁操作是先父后子,销毁完成的顺序是先子后父

# 加载渲染过程

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

# 子组件更新过程

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

# 父组件更新过程

父 beforeUpdate -> 父 updated

# 销毁过程

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

# 你都做过哪些Vue的性能优化

# npm install 原理

npm install 原理分析 (opens new window)

# Map,weakMap,Set,weakSet

JavaScript中的Map、WeakMap、Set和WeakSet介绍 (opens new window)

# 什么是尾递归和尾调用

阶乘函数

int fact(int n) {
    if (n < 0)
        return 0;
    else if(n == 0 || n == 1)
        return 1;
    else
        return n * fact(n - 1);
}

尾递归实现

int facttail(int n, int res)
{
    if (n < 0)
        return 0;
    else if(n == 0)
        return 1;
    else if(n == 1)
        return res;
    else
        return facttail(n - 1, n * res);
}

再举一个例子:计算 1 到 n 的整数的和

const sum = (n) => {
  if (n <= 1) return n;
  return n + sum(n-1) // 当前调用栈保留,还需计算 n + ...
}

const sum = (n, prevSum = 0) => {
  if (n <= 1) return n + prevSum;
  return sum(n-1, n + prevSum)
}

根本思想:避免了入栈出栈造成的时间空间损耗

// 尾调用
function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();

// 等同于
function f() {
  return g(3);
}
f();

// 等同于
g(3);

上面代码中,如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除 f() 的调用记录,只保留 g(3) 的调用记录。

这就叫做"尾调用优化"(Tail call optimization),即只保留内层函数的调用记录。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"尾调用优化"的意义。

尾调用优化 (opens new window)

  • link是HTML提供的标签,不仅可以加载CSS 文件,还可以定义RSS、rel 连接属性等。 @import是CSS 提供的语法规则,只有导入CSS的作用。
  • 加载页面时,link 标签引入的 CSS 被同时加载。 @import 引入的 CSS 将在页面加载完毕后被加载。

# 数组 map()forEach() 方法的区别?

这两个方法都是进行遍历数组的方法。map() 方法通过调回回调函数映射每一个元素到新元素上,并且返回的是一个新数组。另一方面,forEach() 为每个元素调用回调函数,但是它不返回新数组。forEach() 函数通常用于在迭代中产生副作用,而 map() 函数是一种常见的函数式编程技术

  • 如果你需要遍历数组,会造成元素变化,而且不需要返回值来生成一个新数组,你可以使用 forEach()
  • 对于保持数据的不变,map() 是正确的选择,原始数组的每一个值都会映射到一个新数组中

# 静态网站

# 什么是静态网站生成器

  • 静态网站生成器是使用一系列配置,模板以及数据,生成静态HTML文件及相关资源的工具
  • 这个功能也叫预渲染
  • 生成的网站不需要服务器,只需要放到支持静态资源的 Web Server 或 CDN 上即可运行

# 常见的静态网站生成器

  • Jekyll(Ruby)
  • Hexo(Node)
  • Hugo(Golang)
  • Gatsby(Node/React)
  • Gridsome(Node/Vue)
  • 另外,Next.js,Nuxt.js 也能生成静态网站,但是它们更多被认为是服务端渲染框架

# 应用场景

  • 不适合有大量路由页面的应用
  • 不适合有大量动态内容的应用
  • 适用于纯内容展示网站:博客,文档,宣传站等
最后更新时间: 3/15/2023, 7:26:00 PM