爪哇面试集----1

458 阅读7分钟

1 说一下工作中解决过的比较困难的问题,说一下自己项目中比较有亮点的地方

注意点:

1 面试官要看一下你解决问题的能力

2 工作中做好笔记 遇到问题怎么解决,将问题集中积累,面试中的时候可以做到很好的回答

2 你了解浏览器的事件循环吗

2.1 为什么浏览器中有事件循环的机制?

大体答案: 比如js是单线程,如果两个线程操作dom,一个线程删除dom节点,另外一个是操作dom节点,那么就会出现冲突。浏览器就会无法正确渲染出我们想要的结果。

是如果做到非阻塞的?? 执行代码的时候会有些异步的机制怎么处理??

通过event loop 来实现了非阻塞的事件

2.2 了解事件循环中有两种任务吗

宏任务:整体的代码(main),setTimeout,setInterval, I/O操作

微任务:new Promise().then,MutainObserver(前端的回溯)

2.3 为什么要引入微任务的概念,只要宏任务可以么?

宏任务 保持的是先进先出的原则执行。但是如果说有个高优先级的任务,依照宏任务的原则肯定是后执行的,所以这个时候就出现了微任务。

在整体的宏任务中执行完,会将遇到到微任务添加到队列中去,如果微任务中有其他的微任务,会依次执行完,然后再次执行下一个宏任务。

2.4 了解nodejs的事件循环吗?和浏览器中的事件循环有什么区别?

宏任务的执行顺序:

1 timers定时器: 执行已经安排的setTimeout和setInterval的回调函数

// 回调函数开始
()=> {}, 
// 回调结束
1000)

2 pending callback 待定回调:延迟到下一个循环迭代的I/O回调函数

3 idle, prepare:仅系统内部使用。

4 poll: 检索新的I/O事件,执行与I/O相关的回调。

5 check:执行setImmediate()的回调函数

6 close callbacks: socket.on('close', () => {}) socket回调函数的关闭

微任务和宏任务在node中的执行顺序:是区别与node版本的,不同版本执行顺序也会不一样

node v10 版本为界限:

node v10以前:

1 执行完一个阶段中所以任务

2 执行nextTick队列中的内容

3 执行完微任务队列的内容

node v10以后,执行的宏任务和微任务的执行顺序和浏览器统一

事件循环的笔试题:

图片.png

图片.png

图片.png 思考:

图片.png

3 事件的捕获和冒泡机制你了解多少??

3.1 基本概念??

1 捕获是从window一直到目标元素,是自顶向下 2 冒泡是从目标元素到window,是自底向上

3.2 window.addEventListener('click'), 监听的是什么时候的事件???

1 首先要理解的是,监听的不外两种一个是捕获一个是冒泡,但是window.addEventListener这个除了事件名,回调函数,还有第三个参数(true/false),来决定是捕获还是冒泡,默认不传的时候 是false,false代表冒泡但是

3.3 平时有哪些场景会用到这个机制???

原始的写法:

图片.png

缺点是: 会在每个元素上绑定一个事件

优化:事件委托,只在父元素上绑定事件

图片.png

首先 liList并不是一个真正数组,而是一个node list dom节点的数组,而想要去调用array上的indexOf的方法,那只能去通过call改变this,来达到调用数组原型链上的各种方法

3.4 一个历史页面(很多人开发),上面有若干按钮的点击逻辑,每个按钮都有自己的click事件

新需求:给每个访问的用户添加一个属性,banned=true,此用户点击页面上的任何按钮或者元素都不可以响应原来的函数,而是直接alert提示,你被封禁了。

解决方法:直接在window或者body上直接捕获,进行拦截

window.addEventListener('click', (e) => {
  if(banned === true){
    e.stopProgagtion()
  }
}, true)

3.4.1 事件捕获和冒泡的顺序

图片.png 图片.png

4 工作中用过防抖和节流么?

4.1 基本概念?

防抖:当你持续触发事件的时候,一定时间段内没有再触发事件,事件处理函数才会执行一次。是一直往后顺延的,比如一个点击的事件,只要在不点击的时间,比如1s 没有点击,才会触发。

节流:当你持续触发事件的时候,保证一定时间段内,只调用一次处理函数。固定时间段,固定时间间隔是触发事件。

4.2 分别适合在什么时候???

节流:resize(屏幕大小改变) scroll(滚动)这两个是一定要执行,频率会非常的高,所有给个延迟执行的时间

防抖: input (有可能输入的时候有联动,如果输一个就调用一次接口,那么会非常的耗性能)

4.3 手写节流和防抖函数

防抖:

function debounce(fn, wait = 1000) {
  let timer = null;

  return function debounced(...args) {
    // 重置计时器
    if (timer) clearTimeout(timer);

    // 新计时器
    timer = setTimeout(() => {
      fn.apply(this, ...args);
      timer = null;
    }, wait);
  };
}

有时候我们会要求函数在第一次触发立即执行,我们来为它添加个参数。

function debounce(fn, wait = 1000, immediate = false) {
  let timer = null;

  return function debounced(...args) {
    // 重置计时器
    if (timer) clearTimeout(timer);

    // 首次立即执行
    if (immediate && !timer) {
      fn.apply(this, ...args);

      timer = setTimeout(() => {
        timer = null;
      }, wait);

      return;
    }

    // 新计时器
    timer = setTimeout(() => {
      fn.apply(this, ...args);
      timer = null;
    }, wait);
  };
}

为其添加取消的功能

function debounce(fn, wait = 1000, immediate = false) {
  let timer = null;

  function debounced(...args) {
    // 重置计时器
    if (timer) clearTimeout(timer);

    // 首次立即执行
    if (immediate && !timer) {
      fn.apply(this, ...args);

      timer = setTimeout(() => {
        timer = null;
      }, wait);

      return;
    }

    // 新计时器
    timer = setTimeout(() => {
      fn.apply(this, ...args);
      timer = null;
    }, wait);
  }

  debounced.cancel = () => {
    clearTimeout(timer);
    timer = null;
  };

  return debounced;

节流:

// 时间戳写法 第一次是立即执行
function throttle(fn, interval){
  let last = 0;
  return function(){
    let now = Date.now()
    if(now-last >= interval){
      last = now;
      fn.apply(this.arguments)
    }
  }
}

function handle(){
  console.log(Math.random())
}

const throttleHandle = throttle(handle, 1000)

throttleHandle()

// 定时器的写法 第一次不立即执行的方法

function throttle(fn, interval){
 let timer = null
 return function(){
   let context = this;
   let ars = arguments;
   if(!timer){
     timer = setTimeout(function(){
       fn.apply(context, ars)
       timer = null;
     }, interval)
   }
 }
}

function handle(){
  console.log(Math.random())
}

const throttleHandle = throttle(handle, 1000)

throttleHandle()

缺点: 最后一次触发 也要去等 能不能是最后一次触发不需要等,直接立即执行

## 节流优化

function throttle(fn, delay){
  // 设置定时器开关
  let timer = null;
  // 开始时间
  let startTime = Date.now()

  return function(){
    // 当前时间
    let current = Date.now()
    // 剩余时间,从上一次执行到现在 还有多久需要执行下一次
    let remainning = delay - (current - startTime);
    // 保持this
    let context = this;
    // 保持匿名参数
    let args = arguments;
    // 每次都把定时器关闭
    clearTimeout(timer)
    // 如果已经没有剩余时间了 就立即执行下一次事件
    if(remainning <= 0){
      fn.apply(context, args)
      startTime = Date.now()
    }else{
      // 如果还有剩余时间  生成timer 在延迟剩余时间后去执行事件
      // setTimeout 本身就不是特别精确的延迟 中间在执行微任务的时候 有可能会拖延一些时间
      timer = setTimeout(fn, remainning)
    }
  }
}
function handle(){
  console.log(Math.random())
}
const throttleHandle = throttle(handle, 1000)

throttleHandle()

防抖:

图片.png

节流:

图片.png

5 你了解promise吗?平时用的多吗?

5.1 Promise.all() 你知道有什么特性么?

特性: promise.all() 中的参数是一个数组,里面元素可以是promis也可以是一个常量,比如数字 1 执行情况是,所有的promise执行完成之后,才会输出执行的数据,如果其中一个promise报错,那么就会返回catch,那么其他的promise还会执行么?会的,promise在实例化的已经执行了,我们平常的是.then() 只是需要去拿到他的结果。其实已经执行完。

手写promise.all()

图片.png

function PromiseAll (promiseArray){
  return new Promise((resolve, reject) => {
    // promiseArray 传进来的是一个数组 首要是判断传进来的值对不对
    if(!Array.isArray(promiseArray)){
      return reject(new Error('传入的参数必须是数组!'))
    }
    // 用于存输出的值
    const res = [];
    const promiseNums = promiseArray.length;
    // 判断执行的次数是否和传进来的数组是否一直
    let counter = 0;

    // 循环传进来的值
    for(let i=0; i < promiseNums; i++){
      // 这一步很重要,首先传来的数组中不仅仅报错promise,还有可能是其他的类型的值
      // Promise.resolve()这个特性是 会将所有传来的值都转成promise,这样就省略了判断是不是promise的这个类型
      Promise.resolve(promiseNums[i]).then(value => {
        counter++;
        res[i] = value;
        if(counter === promiseNums){
          resolve(res)
        }
      }).catch(e => reject(e))
    }
  })
}

promise 在实例的时候就应该执行了,那么可以做一个promise的缓存,这样在其他同样调用接口的时候就可以不需要再次去调用接口了---

装饰器

图片.png

6算法

图片.png

图片.png

图片.png

暴力解法: 时间复杂度 o的二次方 空间复杂度o(1)

图片.png 时间复杂度 o(n) 空间复杂度 o(n)

图片.png

双指针法:

图片.png

图片.png

7 面试结束了,你有什么要问我们的么?

1 追求的是什么? 钱: 一定要了解业务,更接近页面,要了解业务,去了解公司是怎么运作的,每一个产品需求的背景。前端深度没有后台深,但是前端的广度是很广的

技术:确定一个方向深挖(vue,react,angluarjs)不算。图形学、编辑器、营销页面。看公司需求,适当的了解公认的技术。