2023前端面试记录-1

334 阅读5分钟

前言

今年的前端行情着实不太好。在面试太少的情况下,把握住每次面试机会,记录一下每次的面试题经历

卷 + 少hc + 要求高 = [0] Offer

面试题如下

多个公司的面试题融合,不分公司!!!

问题:vue同步父子组件和异步父子组件的生命周期顺序

答案:

  • 同步

父组件的beforeCreate、created、beforeMount --> 所有子组件的beforeCreate、created、beforeMount --> 所有子组件的mounted --> 父组件的mounted

  • 异步

父组件的beforeCreate、created、beforeMount、mounted --> 子组件的beforeCreate、created、beforeMount、mounted

问题:forEach为什么是并发执行

答案:

foreach内部实现使用的是while循环,当判断当前的索引小于length,会一直执行下去不会等待异步执行完成

forEach 不会按顺序执行 而是并发执行异步任务

for of 和 普通的for循环却能顺序执行异步任务

问题:关于this,介绍一下

答案:

JS函数中this的指向是在运行的时候决定的,

全文总结:谁调用this就指向谁!

this有几种调用方式:

  • 函数调用: fn()this为 window/Global
  • 对象调用: obj.say()this为obj
  • 箭头函数: ()=>{}this指向箭头函数外层的this
  • new: const fn = new Fn()this为 fn
  • call: fn.call({}, 1,2) this为*{}*
  • apply: fn.call({}, [1,2]) this为*{}*
  • bind: fn.bind(1).bind(2) this为1【多次bind时只认第一次的值】

注:bind < new; bind > apply

问题:call怎么实现的?口述自己实现一个call的步骤

答案:

  • call的作用是可以修改函数调用时this的指向,其余参数会作为原函数的参数
  • call的用法是fn.call(obj, params1, params2),此时this指向obj
Function.prototype.my_call = function(context, ...args) {
     if (!context || context === null) {
        context = window
      }
      // 构造唯一的  key【为了防止覆盖掉context原有的同名属性】
      const sy = Symbol()
      // 组装成‘obj.fn()’的形式,来改变this
      context[sy] = this
      // 传入参数args
      const result = context[sy](...args)
      // 删除临时加的key【防止污染】
      delete context[sy]
      // 返回结果
      return result
}

问题: v-model 和sync的区别

答案:

  • 相同点:

    都是语法糖,都可以实现父子组建中的数据的双向通信

  • 区别点:

    • 格式不同
    • 一个组件身上只能有一个v-model 但是.sync修饰符能有
  • 实现:

 v-model --> \<com1 :value="num" @input="(val)=>this.num=val"></com1>
.sync-->\<com1 :a="num" @update:a="val=>num=val" :b="num2" @update:b="val=>num2=val" />

问题:vue中mixins和组件中的优先级

答案:

如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子

相当于组件的拓展,和组件内其他方法变量一样使用

import mixin from './mixin.js'
export default {
	name: 'list',
	mixins: [‘minxin’]
}
  • 特点
    • 同个mixin被多个组件调用
      • 每个组件引入后,各个组件间变量是独立的,不会项目污染
    • 相同方法,属性
      • mixin和组件中存在相同方法时,组件方法优先级大于mixin
    • 执行顺序
      • mixin事件执行顺序要优先于组件的

*从外到内,再从内到外,mixins先于组件*

  • 从源码上看

    • 优先递归处理 mixins
    • 先遍历合并parent中key再调用mergeField合并,保存
    • 再遍历child,合并parent中没有的key,再调用mergeField合并,保存
    • 通过mergeOption合并

问题:typeof原理是什么

答案:

原理: 通过检查操作数的内部的[[class]]属性来确定其数据类型

问题:string作为基本类型,怎么会拥有 length、substring等属性、方法呢?

答案:

原因:基本类型在调用方法是,JS引擎会先对原始类型数据进行包装 -- 基本包装类型。

  • 什么是基本包装类型(JS包装类)
  1. 创建基本类型的一个实例;

  2. 在实例上调用指定的方法;

  3. 销毁这个实例;

    var str = '我是string基本类型的值'
    var new_str = new String("我是string基本类型的值");  // 包装处理
    var my_str = new_str.substring(5,8);
    new_str = null;   // 方法调用之后销毁实例
    

问题:浅拷贝,深拷贝分别解释并说出其多种实现方式

答案:

  • 理解深浅拷贝

    • 数据分为:基本数据类型(直接存储在栈内存中)、引用数据类型(存储的对象指针放在栈中,真正数据在堆内存中)
  • 理解栈和堆

    • 通过栈里定义一个地址值,通过地址值去找堆里面定义的某一个值
    • 区别:堆在栈里存了一个地址值;栈存储的永远是一个基础数据类型的数据
  • 理解深浅拷贝

    • 浅:创建一个对象

      • 如果是基本类型,拷贝的就是基本类型的值
      • 如果是引用类型,拷贝的就是内存地址,指向同一个堆内存,改变拷贝的值会影响原来的对象
    • 深:创建一个新对象

      • 如果是基本类型,拷贝的就是基本类型的值
      • 如果是引用类型,从堆内存里开辟出一个新的区域存放该引用类型指向的堆内存的值,修改新对象的值不会影响原对象
  • 浅拷贝实现

    1. 展开运算符:...
    2. Object.assign() , ps: 当obj只有一层的时候是深拷贝
    3. Array.prototype.concat(): 用原数组去合并一个空数组,返回合并后的数组。【不修改原数组】
    4. slice() 不修改原数组
  • 深拷贝实现

  1. SON.parse(JSON.stringify(): 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象

    • 不能处理函数和正则 得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)
  2. 手写deepclone

    • 原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
  3. jQuery.extend()

        const obj1 = {
          a: 1,
          b: { f: { g: 1 } },
          c: [1, 2, 3]
        };
        const obj2 = jQuery.extend(true, {}, obj1);
        console.log(obj1.b.f === obj2.b.f); // false
    

后记

最近投的简历都已读不回啦。 一直在听录音,一直在整理