2024年JavaScript面试题(持续更新)

131 阅读2分钟

1. 基本类型和引用类型的区别?

主要在数据存储方式上的区别:基本类型的数据直接存储在栈内存中,而引用类型的数据在栈中存储的是一个地址,地址指向堆内存中的数据。
为什么采取这种方式来存储?因为引用类型的数据可能会非常大,复制值过程会非常慢,非常影响性能。

2. 栈内存和堆内存的区别的区别?

  • 有序性:后进先出的数据结构
  • 速度快:内存分配和释放的速度非常快
  • 内存大小:较小

  • 无序性:动态分配内存,管理复杂对象
  • 速度慢:由于需要处理复杂的数据结构,内存分配和释放的速度较慢
  • 内存大小:较大,需要存储复杂的和大量的数据

3. 手写深拷贝

const person = {
    name: 'zs',
    address: {
        city: 'wuhu'
    }
}
const person2 = deepClone(person)
person2.address.city = 'hefei'

function deepClone(obj) {
    if(typeof obj !== 'object' || obj == null) {
        return obj
    }
    let result = obj instanceof Array ? [] : {}
    for(let key in obj) {
        if(obj.hasOwnProperty(key)) {
            // 递归
            result[key] = deepClone(obj[key])
        }
    }
    return result
}
console.log(person)

4. 原型和原型链

原型和原型链

5. 闭包

概念

闭包(Closure)是指有权访问另一个函数作用域中的变量的函数,简单来说,当一个函数内部定义的函数可以访问外部函数的变量时,就形成了闭包。

表现

  • 函数作为参数被传递
function print(fn) {
    let a = 200
    fn()
}

const a = 100
function fn() {
    console.log(a)
}
print(fn) // 100
  • 函数作为返回值被返回
function create() {
    let a = 100
    return function () {
        console.log(a)
    }
}

const fn = create()
const a = 200
fn() // 100

自由变量的查找是在函数定义的地方向上级作用域查找,不是在执行的地方。

应用

  • 能够保存函数作用域内的变量,即使外部函数已经执行完毕,闭包仍能访问和操作这些变量
function outerFunction() {
    let count = 0
    return function () {
        count++
        console.log(count)
    }
}
let increment = outerFunction()
increment() // 1
  • 可以实现私有变量和方法
function createCounter() {
    let privateCount = 0
    return {
        increment: function() {
            privateCount++
            return privateCount
        },
        getCount: function() {
            return privateCount
        }
    }
}
let counter = createCounter()
counter.increment()
  • 在循环中创建异步操作时,闭包可以帮助保留正确的变量值
for (let i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i)
    }, 1000)
}

for (let i = 0; i < 5; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j)
        }, 1000)
    })(i)
}

6. this的使用

  • this取什么值,是在函数执行的时候确定的,不是在定义的时候确定的
  • 箭头函数没有自己的this
function fn1() {
    console.log(this)
}
fn1() // window
fn1.call({ x: 100 }) // { x: 100 }
const fn2 = fn1.bind({ x: 200 })
fn2() // { x: 200 }
const zs = {
    name: '张三',
    study() {
        console.log(this)
    },
    code() {
        setTimeout(function () {
            console.log(this)
        })
    },
    code2() {
        setTimeout(() => {
            console.log(this)
        })
    }
}
zs.study() // zs对象
zs.code() // window
zs.code2() // zs对象

class People {
    constructor(name) {
        this.name = name
    }
    study() {
        console.log(this)
    }
}
const ls = new People('ls')
ls.study() // ls对象

7. Event Loop(事件循环机制)

Event Loop

8. Promise

Promise