2022面试题整理(JS篇)

65 阅读4分钟

1,判断一个对象为空的方法

方法一:
将对象转换为字符串,判断是否为'{}',相等则对象为空
let obj = {}
console.log(JSON.stringify(obj) === '{}')

方法二:for in 循环
function emptyObj(obj){
    for(let key in obj) {
        return false //若不为空,可遍历,返回false
    }
    return true
}

方法三:
使用Object.keys()获取对象的key的集合,返回一个数组,如果该数组的长度等于0,则该对象为空
console.log(Object.keys(obj).length === 0)


方法四:
使用Object.getOwnPropertyNames()方法获取对象的属性名,存到数组中,判断数组长度
console.log(Objec.getOwnPropertyNames(obj).length === 0)

2,数组forEach和map方法的区别

相同点:
    1) 都可以遍历数组
    2) 每次执行都支持三个参数,item 数组的每一项, index 数组的索引,arr 当前数组
    3)匿名函数的this都指向window
    4)只能遍历数组
不同点:
    1)map有返回值,forEach没有返回值,也不能return
    2)map返回新的数组,map不会对空数组进行检测

3,判断数组类型的方法

方法一:isArray(推荐)
let arr = [1,2,3,4]
console.log(Array.isArray(arr)

方法二:instanceof
console.log(arr instanceof Array) // true

方法三:constructor
cconsole.log(arr.constructor === Array) // true

方法四:Object.prototype.toString.call()
console.log(Objec.prototype.toString.call(arr) === '[Object Array]')

方法五:isPrototypeof()
console.log(Array.isPrototypeof(arr))

4,构造函数

构造函数:是一种特殊的方法。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总于new运算符
yi起使用在创建对象的语句中。

5,new 一个对象的过程

1,创建一个新对象
2,将对象的原型指向构造函数的原型
3,将空对象作为构造函数的上下文(改变this指向)
4,对构造函数有返回值的处理(返回基本数据类型的值则忽略,返回引用数据类型的时,返回该数据)

6,promise是同步还是异步,promise的then()方法是同步还是异步,promise有几个状态

promise本身是同步,它的then方法是异步的
promise有三个状态,初始状态pending,成功状态 fulfilled, 失败状态rejected

7,实现异步的方法

方法一:async函数 (async await 将异步转换为同步)
方法二:promise的then方法,解决回掉地狱的问题,缺点是一旦执行不能停止,报错需要回掉函数捕获
方法三:事件监听
方法四:回掉函数,现在比较少用,容易造成回掉地狱

8,防抖和节流

防抖和节流都是为了解决事件频繁出发的问题

一,防抖:当持续触发事件时,在一定的时间内没有在触发事件,事件才会处理,如果在设定的时间内
又触发了事件,则重新开启定时器,执行最后一次触发事件(事件只执行一次)
    应用场景:scroll事件滚动,浏览器窗口的缩放resize事件,搜索框输入查询,按钮的提交事件等

代码
function debounce(fn, delay = 1000) {
    let time = null;
    return function() {
        // 获取当前this
        let _this = this
        // 判断time是否已经存在,如果存在直接清楚
        if(time) {
            clearTimeout(time)
        }
        time = setTimeout(() => {
            // 使用fn中的this,执行当前调用者,并传入参数
            fn.apply(_this, arguments)
        }, delay)
    }
}
function test() {
    console.log('测试防抖')
}

btn.addEventListener('click', debounce(test, 1000))



二,节流:在持续触发事件时,在一定时间内只调用一次函数,如果在规定时间内,再次触发该函数,则直接忽略
,主要目的就是减少一段时间的触发频率
应用场景:DOM元素拖拽功能实现,计算鼠标移动距离等

代码
function throttle(fn, delay = 1000) {
    let time = null
    return function(){
        let _this = this
        // 如果已经存在定时器,则不做处理
        if (!time) {
            time = setTimeout(() => {
                fn.apply(that, argument)
                // 完结时,将time改为null
                time = null
            }, delay)
        }
    }
}

9,闭包是什么

闭包:在一个函数里面再定义一个函数。内部函数可以调用外部函数的参数
闭包的用途:1,可以读取函数内部的变量 2,让变量始终保存到内存中
注意:闭包会使得函数中的变量都被保存到内存中,内存消耗很大,所以不能滥用闭包。(在IE中可能会导致内存泄露)

10,箭头函数与普通函数的区别,可以new一个箭头函数吗

1,写法不一样
    // 普通函数
    function fun(){
        console.log('普通函数')
    }
    //箭头函数
    let fun = () => {
        console.log('箭头函数')
    }
2,两者的this指向不同
    普通函数的this:谁调用该函数就指向谁
    箭头函数的this:书写代码时候的上下文环境对象的this,如果没有上下文环境,
 就指向最外层对象window
3,箭头函数的arguments指向其父级函数作用于的arguments4,箭头函数没有new.target
    new.target是用来检测函数是否被当作构造函数使用,它会返回一个指向构造函数的引用


不能new一个箭头函数,因为箭头函数不能作为构造函数使用