面试总结

一. 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文件中,类似于vue2mixin。可以把实现同一个功能的代码组合在一起,不仅代码非常简洁清晰,而且便于很好地知道复用组件的来源。

posted @ 2022-09-16 14:33  JOJOLai  阅读(33)  评论(0编辑  收藏  举报