前端面试经验(二):拿下心仪职位

230 阅读6分钟

前言

给小伙伴分享一些我面试出现的题目,给还在备战面试的小伙伴一点点经验,也希望大佬多给我提提建议。让我们在这春暖花开、百花齐放的三四月拿下心仪的工作。

如果你对此感兴趣,可以看我上一篇文章 前端面试经验

请你说一下vue中computed和watch他们分别具有什么功能,有什么区别?

computed

计算属性是基于它们的依赖进行计算的属性,并且具有缓存机制。这意味着计算属性只有在其依赖的数据发生变化时才会重新计算,否则会返回之前缓存的值。

它支持缓存,只有依赖的数据发生了变化,才会重新计算

不支持异步,当Computed中有异步操作时,无法监听数据的变化

computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。

watch

监视属性用于监听指定数据的变化,并在数据变化时执行指定的回调函数。与计算属性不同,监视属性不具有缓存机制,每次数据变化都会触发回调函数。

它不支持缓存,数据变化时,它就会触发相应的操作

支持异步

监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值

总结

computed 计算属性是基于其它属性值的计算得出的属性,具有缓存性,只有依赖的属性值发生改变时才会重新计算。

watch 侦听器更像是一个观察者,用于监视特定数据的变化,无缓存性,每当被监听的数据变化时都会执行相应的回调函数。

代码题一

var a = 30
function foo(){
        alert(a)
        var a = 10
        alert(a)
        a = 20
        function a() {}
        alert(a)
}
foo()
function a(){}
10
20

这段代码考察的知识点包括:

变量声明提升:JavaScript 在执行代码前会将变量声明提升至作用域的顶部,但不会提升变量的赋值操作。

函数声明与变量声明的优先级:在同一个作用域内,函数声明的优先级高于变量声明,但如果变量已经被赋值,则函数声明不会覆盖该变量。

作用域链:函数内部能够访问外部作用域的变量,但如果函数内部有同名变量,则会优先访问函数内部的变量。

首先,在foo()函数内部,存在一个变量声明var a和一个函数声明function a() {}。因为函数声明会优先于变量声明,所以在执行alert(a)时,a 实际上是一个函数,即 function a() {},因此会输出 function a(){}。

然后,在 var a = 10 被执行之后,a 被重新赋值为 10。

在 a = 20 被执行之后,a 变量的值被更新为 20。

最后,在函数声明 function a() {} 被执行之后,由于此时 a 已经被赋值为 20,所以函数声明不会对 a 变量产生影响。

代码题二

let setSize = new Set()
setSize.add([1])
setSize.add([2])
console.log(setSize.size)

image.png

这段代码考察的知识点包括:

Set 集合的特性:Set 是一种集合类型,它存储独特的值,不允许重复。

JavaScript 中对象比较的特性:JavaScript 中的对象(包括数组)是按引用进行比较的,而不是按值进行比较的,因此两个相同内容的数组在内存中的地址不同,会被认为是不同的对象。

Set 集合的大小属性:通过 .size 属性可以获取 Set 集合中的元素数量。

这段代码创建了一个Set集合,并向集合中添加了两个不同的数组[1][2]

setSize.add([1]) 添加了一个包含元素 1 的数组 [1] 到 Set 集合中。 setSize.add([2]) 添加了一个包含元素 2 的数组 [2] 到 Set 集合中。

由于这两个数组是不同的对象,它们虽然内容相同,但在内存中的地址是不同的,因此它们被认为是两个不同的值,都会被成功添加到 Set 集合中。

最后输出 Set 集合的大小。由于 Set 集合只包含了两个不同的数组,因此它的大小为2

编程题一

红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次;如何让三个灯不断交替重复亮灯?
  function red() {
    console.log("red");
  }
  function green() {
    console.log("green");
  }
  function yellow() {
    console.log("yellow");
  }
  const light = function (timer, cb) {
    return new Promise(resolve => {
      cb()
      setTimeout(() => {
        resolve()
      }, timer)
    })
  }
  const step = function () {
    Promise.resolve().then(() => {
      return light(3000, red)
    }).then(() => {
      return light(2000, green)
    }).then(() => {
      return light(1000, yellow)
    }).then(() => {
      return step()
    })
  }
  step();

定义一个light()函数,它接受两个参数:timercb。这个函数返回一个 Promise。在函数内部,它首先执行传入的回调函数 cb(),然后通过 setTimeout 在timer毫秒后解决(resolve)这个 Promise。这就模拟了交通信号灯的变化和时间间隔。

在 Promise 链中,通过then()方法依次调用light()函数来控制灯的变化和时间间隔。首先是红灯,等待 3000 毫秒(3秒),然后是绿灯,等待 2000 毫秒(2秒),最后是黄灯,等待 1000 毫秒(1秒)。这些时间间隔分别对应红灯、绿灯和黄灯的显示时间。

编程题二

实现a,b两个对象值互换
let a = {a:1, value:1}
let b = {b:2, value:2}
let a = {a:1, value:1};
let b = {b:2, value:2};

let temp = Object.assign({}, a);
a = Object.assign({}, b);
b = Object.assign({}, temp);

console.log(a);
console.log(b);

通过创建一个临时变量temp,将对象a的值存储在其中。然后,将对象b的值赋给对象a,再将临时变量中存储的对象a的原始值赋给对象b。最后,输出了交换后的值。

编程题三

给定一个未经排序的整数数组,找到最长连续递增序列的长度。
例如,在数组 [1,3,5,4,7] 中,最长连续递增序列是 [1,3,5],其长度为 3
function foo(nums) {
    if (nums.length === 0) return 0;
    
    let maxLength = 1; // 最长连续递增序列的长度
    let currentLength = 1; // 当前连续递增序列的长度
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] > nums[i - 1]) {
            currentLength++;
            maxLength = Math.max(maxLength, currentLength); /
        } else {
            currentLength = 1;
        }
    }
    return maxLength;
}

首先检查输入的数组是否为空,如果为空则直接返回 0,因为空数组没有连续递增序列。

在循环中,首先检查当前元素是否大于前一个元素。如果是,则说明当前元素在递增序列中,此时增加当前连续递增序列的长度currentLength++,并且更新最长连续递增序列的长度 maxLength,取当前长度和历史最长长度的最大值。如果不是,则当前递增序列中断,将 currentLength重新设置为 1。

最后,函数返回 maxLength,即最长连续递增序列的长度