面试总结
一. 4399一面凉经
自我介绍?
为什么学前端?
平时是怎么学习相关知识的?
Object和map的区别?
1. key的类型不同 : Object的key必须是String或者Symbol等简单数据类型,而map的key允许各种形式,包括对象本身也可以作为键key
2. 构造方式不同 : Object可以直接初始化 {} 进行创建或者通过new进行创建 ;map只能通过new创建,且传入的初始化参数必须为 [ [映射key, 值 ], [key, 值 ] ]的形式
3. 继承的区别 : Object会从Object.prototype中继承部分属性和方法,使用过程中可能会进行覆盖操作,也可以使用Object.create(null)创建没有原型的对象 ;map则不会继承key,因此也不会有覆盖的风险
4. map是可通过for of 进行迭代的,且可以通过map.size()获取长度 ;但是Object不支持直接使用 for of 进行迭代,如果需要可以自己设置可迭代接口,且长度需要通过间接手段获取
5. map的迭代顺序遵循FIFO原则 ;Object的迭代顺序一般也是FIFO,但是也有例外-----例如:如果属性是整数(浮点数都不行):{ ”2” : val } 这种,会根据属性转换后的数值进行小到大枚举 ,然后再按书写对象顺序枚举剩下的属性
6. Object支持JSON化,但是map不支持JSON化
7. 补充 :map和Object的转化,通过Object.entries()获得符合new Map() 初始化类型的可迭代对象转化为map ; 通过map.entries()转化为可迭代对象,再通过Object.fromEntries()转化为Object
for in 和 for of 区别
1. for in 可用于对象,也可以用于Array,因为Array也属于对象,因此会遍历出非Symbol类型的可迭代属性的key或者索引,包括Object.keys(),Object.values(),Object.entries()都是类似;如果希望遍历Symbol类型,需要通过Object.getOwnPropertySymbols 或 Reflect.ownKeys(obj) 来获得Symbol类型的键。
2. for of 是es6的新增特性,可以用于默认自带有迭代器接口的Array,Map,Set等,可以迭代出其值value,对于map则会迭代出 [key , value] 的可迭代对象形式 ; 需要注意的是由于Object并没有自带的迭代器接口,因此不能直接使用,但是也可以通过给其原型上手动添加迭代器对象达到使用 for of 的目的
call bind 和 apply
1. 三者的相同之处都是用来改变函数执行的上下文,即this指向,且三者都可以传参
2. bind 与其他两者最大的不同在于它不是同步执行的,bind接收多个参数,第一个参数是this上下文的指向,后面的参数则是执行时依次传递到函数的参数,返回结果是一个永久改变上下文指向的新函数 ;如果this参数为null或undefined,则不修改指向
3. call 是调用时同步执行的,第一个参数也是this,后面的参数列表也是依次传入函数中执行,若this指向null或者undefined,则this默认指向window(浏览器环境)
4. apply 也是同步执行的,但是只接收两个参数,第一个是this,第二个参数是一个数组,数组会传递到函数中进行同步执行,若this指向null或者undefined,则this默认指向window(浏览器环境)
js的继承,从原型链方面来谈一下
1. 原型链继承 : 子类构造函数的prototypr指向父类的实例,相当于重写子类的原型链,达到继承父类属性和方法(包括私有属性和公有方法)的目的
2. 借用构造函数继承 : 即在子类构造函数内利用call或者apply,将子类的this修改成父类构造函数的执行上下文,达到从子类构造函数内部调用父类方法的目的,缺点是不能继承父类原型的属性和方法
3. 组合式继承 :将上面两种方法结合,解决了第一种方法会覆盖子类原型方法的缺点,和第二种方法没办法继承父类原型属性的缺点,但是需要两次父类实例,内存开销大
4. 共享原型继承 :利用 Object.create(父类) 将父类作为子类变量的原型__proto__,Object.create()方法实现的是浅拷贝,多个实例的引用类型属性指向相同的父类,存在篡改父类属性的可能
let parent = { arr: [1,2,3] } let person1 = Object.create(parent) let person2 = Object.create(parent) console.log(person1.arr === person2.arr) //true
5. 寄生式继承 :在原型式的基础上优化,在函数内部新建一个变量来保存继承式的返回值,在这个变量身上可以添加属性和方法, 缺点没有解决
let parent = { arr: [1,2,3] } function clone(parent) { let son= Object.create(parent); son.getArr = function() { return this.arr } return son } let son= clone(parent) console.log(son.getArr()) // [1,2,3]
6. 寄生组合式继承 :
function inheritPrototype(Child, Parent) { var ParentPrototype= Object.create(Parent.prototype);//将父类prototype作为原型赋值给一个变量 ParentPrototype.constructor = Child; //给该变量设置构造器 Child.prototype = ParentPrototype; //最后该变量作为子类构造器的原型prototype }
7. es6的类继承
async和defer在script标签上的区别
defer是异步加载,延迟执行(顺序执行) ;async是异步加载,加载完毕马上执行(乱序执行)
commonJS和ES6模块化区别
推荐一位大佬的文章 : https://juejin.cn/post/6994224541312483336
CommonJS模块规范只适合用在服务端,浏览器上运行需要进行处理;ES6模块无论是在浏览器端还是服务端都是可以使用的,在服务端中,需要进行声明
CommonJS 模块输出的是一个值的拷贝 ; 而ES6 模块是静态导入导出的,起到tree shaking的作用,输出的是值的引用(无论是否基础类型), 因此不能直接修改引用值(对象的属性可以修改但是不建议,类似于const)
CommonJS 模块是运行时加载 ;ES6 模块是编译时输出接口
在CommonJS顶层,this
指向当前模块;在ES6模块,this
指向undefined(因为es6导入模块是在严格模式下)
ES6的静态引入不能处于代码块中,动态import可以
commonJS能在浏览器环境直接使用吗
不能,需要Browserify进行处理
谈一下vue2 和 vue3 响应式原理,为什么不同
vue2 :
1. 基于Object.defineProperty,对对象属性的读取、修改进行拦截(即数据劫持),在数据变动时发布消息给订阅者,触发相应的监听回调。
2. 缺点是不具备监听数组的能力,数组需要通过重写更新的一系列方法来实现拦截 ;且深度监听需要针对每个属性进行遍历,消耗大 ;对于对象属性的增加和删除无法起到监听作用
vue3 :
1. 基于es6的proxy和reflect对数据进行劫持和代理,可以监听数组的同时也能捕获到添加属性和删除属性的操作 ;由于不需要对data进行一次性遍历,也减少了消耗
2. 缺点是es6的新属性proxy存在兼容性问题,需要ie11以上
vuex如何进行异步操作
在Actions进行异步操作后将值传递给Mutations,之后也可以在dispatch接收其返回的promise值
用过react hook吗?--没有,那谈一下vue3的hook
vue3
中的hooks其实是函数写法,将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,类似于vue2
的mixin
。可以把实现同一个功能的代码组合在一起,不仅代码非常简洁清晰,而且便于很好地知道复用组件的来源。
本文作者:JOJOLai
本文链接:https://www.cnblogs.com/jojolai/p/16696899.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步