前言
今年的前端行情着实不太好。在面试太少的情况下,把握住每次面试机会,记录一下每次的面试题经历
卷 + 少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事件执行顺序要优先于组件的
- 同个mixin被多个组件调用
*从外到内,再从内到外,mixins先于组件*
-
从源码上看
- 优先递归处理 mixins
- 先遍历合并parent中key再调用mergeField合并,保存
- 再遍历child,合并parent中没有的key,再调用mergeField合并,保存
- 通过mergeOption合并
问题:typeof原理是什么
答案:
原理: 通过检查操作数的内部的[[class]]属性来确定其数据类型
问题:string作为基本类型,怎么会拥有 length、substring等属性、方法呢?
答案:
原因:基本类型在调用方法是,JS引擎会先对原始类型数据进行包装 -- 基本包装类型。
-
什么是基本包装类型(JS包装类)
-
创建基本类型的一个实例;
-
在实例上调用指定的方法;
-
销毁这个实例;
var str = '我是string基本类型的值' var new_str = new String("我是string基本类型的值"); // 包装处理 var my_str = new_str.substring(5,8); new_str = null; // 方法调用之后销毁实例
问题:浅拷贝,深拷贝分别解释并说出其多种实现方式
答案:
-
理解深浅拷贝
- 数据分为:基本数据类型(直接存储在栈内存中)、引用数据类型(存储的对象指针放在栈中,真正数据在堆内存中)
-
理解栈和堆
- 通过栈里定义一个地址值,通过地址值去找堆里面定义的某一个值
- 区别:堆在栈里存了一个地址值;栈存储的永远是一个基础数据类型的数据
-
理解深浅拷贝
-
浅:创建一个对象
- 如果是基本类型,拷贝的就是基本类型的值
- 如果是引用类型,拷贝的就是内存地址,指向同一个堆内存,改变拷贝的值会影响原来的对象
-
深:创建一个新对象
- 如果是基本类型,拷贝的就是基本类型的值
- 如果是引用类型,从堆内存里开辟出一个新的区域存放该引用类型指向的堆内存的值,修改新对象的值不会影响原对象
-
-
浅拷贝实现
- 展开运算符:...
- Object.assign() , ps: 当obj只有一层的时候是深拷贝
- Array.prototype.concat(): 用原数组去合并一个空数组,返回合并后的数组。【不修改原数组】
- slice() 不修改原数组
-
深拷贝实现
-
SON.parse(JSON.stringify(): 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象
- 不能处理函数和正则 得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)
-
手写deepclone
- 原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
-
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
后记
最近投的简历都已读不回啦。 一直在听录音,一直在整理