WEB前端 面经

833 阅读7分钟

WEB前端 - JS部分

1.JS数据类型

  • 基本数据类型:Boolean、Number、String、undefined、Null、Symbol(ES6新增,表示独一无二的值);
  • 引用数据类型:Object、Array、Function;

2.判断数据类型的方法有哪些?

利用`typeof`可以判断数据的类型;  
A instanceof` B可以用来判断A是否为B的实例,**但它不能检测 null 和 undefined**;  
`B.constructor == A`可以判断A是否为B的原型,**但constructor检测 Object与instanceof不一样,还可以处理基本数据类型的检测**。

3.var、let、const的区别是什么?

varletconst都是用于声明变量或函数的关键字。其区别在于:

varletconst
作用域函数作用域块级作用域块级作用域
作用域内声明提升无(暂时性死区)
是否可重复声明
是否可重复赋值否(常量)
初始化时是否必需赋值

4.闭包

【概念】闭包就是引用了其他函数作用域中变量的函数,这种模式通常在函数嵌套结构中实现。里面的函数可以访问外面函数的变量,外面的变量的是这个内部函数的一部分。

【作用】1.加强封装,模拟实现私有变量。2实现常驻内存的变量。

【缺点】闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null

【应用场景】1.函数作为参数传递;2.函数作为返回值。

/**
  *JavaScript中的函数会形成了闭包。
*闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。
**/

function foo(){
  var num = 1
  function compute(){
    num++
    return num
  }
  return compute
}

var fn = foo()
fn()

// num 变量和 compute 函数就组成了一个闭包

5.浅拷贝与深拷贝

浅拷贝

【概念】浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享一块内存。修改时原对象也会受到影响。 【实现方法】

  • 利用“=”赋值操作符实现浅拷贝;
  • 数组的浅拷贝一般使用slice、concat;
  • 数组的浅拷贝 - 遍历;
  • 对象的浅拷贝 - Object.assign();
  • 对象的浅拷贝 - 扩展运算符;

深拷贝

【概念】深拷贝就是在拷贝数据的时候,将数据的所有引用结构都拷贝一份。简单的说就是,在内存中存在两个数据结构完全相同又相互独立的数据,将引用型类型进行复制,而不是只复制其引用关系。修改时原对象不在受到任何影响。 【实现方法】

  • 利用JSON对象中的parse和Stringify。
JSON.parse(JSON.stringify(obj))深拷贝弊端:
1.时间会变成字符串形式,而不是时间对象。
2.如果obj里面有function,undefined,则序列化的结果会把function,undefined丢失
3.如果obj里面有NaN,Infinity和-Infinity,则序列化的结果会变成null
4.JSON.stringify()只能序列化对象的可枚举的自有属性
5.如果obj里有RegExpError对象,则序列化的结果只能得到空对象
  • 利用递归来实现每一层都重新创建对象并赋值。

6.防抖与节流

防抖与节流函数时一种常用的高频触发优化方式,能对性能有较大的帮助。

防抖

【概念】将多次高频操作优化为只在最后一次执行,通常使用的场景时:用户输入,只需再输入完成后做一次输入校验即可。


/**
 * 防抖 (debounce)将多次高频操作优化为只在最后一次执行
 * 
 * @param {Function} fn 需要防抖函数
 * @param {Number} wait  需要延迟的毫秒数
 * @param {Boolean} immediate 可选参,设为true,debounce会在wait时间间隔的开始时立即调用这个函数
 * @return {Function}
 * 
 */
 const debounce= (fn, wait, immediate) =>{
    let timer = null

    return function() {
        let args = arguments
        let context = this

        if (immediate && !timer) {
            fn.apply(context, args)
        }

        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(context, args)
        }, wait)
    }
}

节流

【概念】每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景:滚动条事件或者resize事件,通常每隔100-500ms执行一次即可。


/**
 * 节流(throttle)将高频操作优化成低频操作,每隔 100~500 ms执行一次即可
 * 
 * @param {Function} fn 需要防抖函数
 * @param {Number} wait  需要延迟的毫秒数
 * @param {Boolean} immediate 可选参立即执行,设为true,debounce会在wait时间间隔的开始时立即调用这个函数
 * @return {Function}
 * 
 */
 const throttle =(fn, wait, immediate) =>{
    let timer = null
    let callNow = immediate
    
    return function() {
        let context = this,
            args = arguments

        if (callNow) {
            fn.apply(context, args)
            callNow = false
        }

        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(context, args)
                timer = null
            }, wait)
        }
    }
}

7.Array常见操作方法

- map:遍历数组,返回回调返回值组成的新数组;
- forEach:无法break,可以用try/catch中throw new Error来停止;
- filter:过滤
- some:有一项返回true,则整体为true;
- every:有一项返回false,则整体为false;
- join:通过制定链接符生成字符串;
- push/pop:未尾推入和弹出,改变原数组,返回推入/弹出项;
- unshift/shift:头部推入和弹出,改变原数组,返回操作项;
- sort(fn)/reverse:排序与反转,改变原数组;
- concat:连接数组,不影响原数组,浅拷贝;
- slice(start,end):返回截断后的新数组,不改变原数组;
- splice(start,number,value...): 返回删除原数组的数组,Value为插入项,改变原数组;
- indexOf/lastIndexOf(value,fromIndex):查找数组项,返回对应的小标;
- reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)
- flat: 数组拆解, flat: [1,[2,3]] --> [1, 2, 3]

8.Object常见操作方法

- Object.key(obj): 获取对象的可遍历属性(键);
- Object.values(obj):获取对象的可遍历属性(值);
- Object.entries(obj):获取对象可遍历键值对;
- Object.assign(targetObject,...object):合并对象可遍历属性;
- Object.is(value1,value2):判断两个值是否是相同的值;

9.浏览器存储Cookie、 LocalStorage 与 SessionStorage

Cookie

一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效
大小限制为4KB左右
每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
需要程序员自己封装,源生的Cookie接口不友好

LocalStorage

除非被清除,否则永久保存
一般为5MB
仅在客户端(即浏览器)中保存,不参与和服务器的通信
原生接口可以接受,亦可再次封装来对ObjectArray有更好的支持

SessionStorage

仅在当前会话下有效,关闭页面或浏览器后被清除
一般为5MB
仅在客户端(即浏览器)中保存,不参与和服务器的通信
原生接口可以接受,亦可再次封装来对ObjectArray有更好的支持

10.插槽

slot插槽,一般在组件内部使用,封装组件时,在组件内部不确定该位置是以何种形式的元素展示时,可以通过slot占据这个位置,该位置的元素需要父组件以内容形式传递过来。

11.mixin

mixin(混入), 它提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

使用场景: 不同组件中经常会用到一些相同或相似的代码,这些代码的功能相对独立。可以通过mixin 将相同或相似的代码提出来。

缺点:

  1. 变量来源不明确
  2. 多 mixin 可能会造成命名冲突(解决方式:Vue 3的组合API)
  3. mixin 和组件出现多对多的关系,使项目复杂度变高。