前端面试系列基础 -- JS基础高频面试题

396 阅读6分钟

1、何为变量提升

var、let 、const的区别?

· var 是 ES5 语法,let、const是 ES6 语法,var 有变量提升

image.png

· var、let 是变量,可以修改;const 是常量,不可修改

· let、const 是块级作用域,var 没有;

typeof 返回哪些类型?

· undefined、string、number、boolean、symbol

· object (注意:typeof null === 'object')

· function

列举强制类型转换和隐式类型转换?

· 强制: parseInt、 parseFloat、toString等

· 隐式:if、逻辑运算、== 和 + 拼接字符串

2、手写深度比较 isEqual ?

手写深度比较,模拟 lodash.isEqual ?

image.png

// 判断是否是对象
function isObject(obj) {
    return typeof obj === 'object' && obj !== null
}

function isEqual(obj1, obj2) {

    if (!isObject(obj) || !isObject(obj2)) {
        // 判断如果不是对象,就比较值类型
        return obj1 === obj2;
    }

    let obj1keys = Object.keys(obj1)
    let obj2keys = Object.keys(obj2)

    // 判断对象或者数组长度是否相等
    if (obj1keys.length !== obj2keys.length) {
        return false
    }

    // 以obj1为基准,和obj2依次递归比较
    for (let key in obj1) {
        let res = isEqual(obj1[key], obj2[key])
        if (!res) {
            return false
        }
    }
    return true
}

let obj = {
    a: 100,
    b: {
        x: 100,
        y: 200
    }
}

let obj2 = {
    a: 100,
    b: {
        x: 100,
        y: 200
    }
}
let flag = isEqual(obj, obj2)

let arr1 = [1, 2, 3, 4]
let arr2 = [1, 2, 3, 4, 9]
let flag2 = isEqual(arr1, arr2)

console.log(flag2)

split()和join()的区别?

image.png

数组的 pop、push、unshift 和 shift分别做什么?

· 功能是什么?

· 返回值是什么?

· 是否对原数组造成影响?

pop: 方法移除数组的最后一个元素,并返回该元素。

push: 将新元素添加到数组的末尾,并返回新的长度。

unshift: 将新元素添加到数组的开头,并返回新的长度。

shift: 删除数组的第一个元素,并返回该元素。

array中纯函数的特点: 1、不会改变原数组;2、返回一个数组; 例如: concat、map、filter、slice

3、你是否真的会用数组map

数组 slice 和 splice的区别?

image.png

slice() 方法以新的数组对象,返回数组中被选中的元素。

slice() 方法选择从给定的 start 参数开始的元素,并在给定的 end 参数处结束,但不包括。不会改变原数组

splice() 方法向/从数组添加/删除项目,并返回删除的项目。会改变原数组

[10,20,30].map(parseInt) 的返回结果是什么?

image.png

image.png

主要考察拆解函数;parseInt()的第二个参数,进制转换(接收两个参数),parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。详细请看该博文:blog.csdn.net/josavion/ar…

ajax请求 get 和 post的区别?

· get 一般用于查询操作, post 一般用户提交操作

· get 参数拼接在 url上,post 放在请求体内(数据体积可更大)

· 安全性: post易于防止 CSRF

4、再学闭包

函数 call 和 apply 的区别?

image.png

事件代理(委托)是什么 ?

事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;DOM 中事件委托的实现是利用事件冒泡的机制;

委托的优点

1. 减少内存消耗

试想一下,若果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件;

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能;

因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是 ul 上,然后在执行事件的时候再去匹配判断目标元素;

所以事件委托可以减少大量的内存消耗,提高效率。

2. 动态绑定事件

比如上述的例子中列表项就几个,我们给每个列表项都绑定了事件;

在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;

如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;

所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

image.png

闭包是什么?有什么特性?有什么负面影响?

image.png image.png

5、回顾 DOM 操作和优化

如何阻止事件冒泡和默认行为?

image.png

查找、添加、删除和移动 DOM节点的方法?

如何减少 DOM 操作?

image.png

6、jsonp 本质是ajax吗?

解释jsonp 的原理,为何他不是真正的 ajax?

image.png

image.png

document load 和 ready 的区别?

image.png

== 和 === 的不同?

image.png

7、是否用过 Object.create() ?

函数声明和函数表达式的区别?

image.png

// // 函数声明
const res = sum(10, 20)
console.log(res)
function sum(x, y) {
    return x + y
}

// // 函数表达式
var res = sum(10, 20)
console.log(res)
var sum = function (x, y) {
    return x + y
}

image.png

new Object 和 Object.create()的区别?

image.png

关于 this 的场景题?

image.png 答案: 1 (this指向User)、 undefined(this指向window,所以为undefined)

8、常见的正则表达式?

关于作用域和自由变量的场景题 - 1

image.png 答案: 3

判断字符串以字母开头,后面字母数字下划线,长度6 - 30

image.png

关于作用域和自由变量的场景题 - 2

image.png 答案: 100、 10、10

9、如何获取最大值?

手写字符串trim()方法,保证浏览器兼容性?

image.png

如何获取多个数字中的最大值?

image.png

image.png

如何用JS实现继承?

class 继承

10、解析 URL 参数

如何捕获 JS 程序中的异常?

image.png

什么是 JSON ?

image.png

image.png

获取当前页面中 url 参数?

image.png image.png

11、数组去重有几种方式?

将 url 参数解析为 JS 对象?

方式一:

function urlFn() {
    let obj = {}
    let params = location.search.substr(1)  // 去掉前面的?
    // ?a=10&b=20&c=30
    params.split('&').forEach(item => {
        let arr = params.split('=')
        const key = arr[0]
        const value = arr[1]
        obj[key] = value
    })
    return obj
}

方式二:

function urlFn2() {
    let obj = {}
    let pList = new URLSearchParams(location.search)
    pList.forEach((val, key) => {
        obj[key] = val
    })
    return obj
}

手写数组 flatern, 考虑多层级?数组排平

image.png

image.png

function flat(arr) {
    // 验证 arr 中,还有没有深层数组 [1, 2, [3, 4]]
    const isDeep = arr.some(item => item instanceof Array)
    if (!isDeep) {
        return arr // 已经是 flatern [1, 2, 3, 4]
    }

    const res = Array.prototype.concat.apply([], arr)
    return flat(res) // 递归
}

const res = flat( [1, 2, [3, 4, [10, 20, [100, 200]]], 5] )
console.log(res)

数组去重?

image.png

// 传统方式
function unique(arr) {
    let res = []
    arr.forEach(item => {
        if (res.indexOf(item) < 0) {
            res.push(item)
        }
    })
    return res
}

let arr = unique([1,3,4,5, 2, 3, 4, 5, 6, 5, 6, 7])
console.log(arr)

// 使用Set (无序,不能重复),比传统方式快一点
function setUnique(arr) {
    const setArr = new Set(arr)
    return [...setArr]
}
let arr2 = setUnique([1,3,4,5, 2, 3, 4, 5, 6, 5, 6, 7])
console.log(arr2)

12、是否用过 requestAnimationFrame?

手写深拷贝?

image.png

function deepClone(obj={}) {
    if (typeof obj !== 'object' || obj == null) {
        return obj
    }
    // 初始化返回结果
    let result
    // 判断是对象还是数组
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }
    // 递归
    for (let key in obj) {
        // 保证key不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用
            result[key] = deepClone(obj[key])
        }
    }
    // 返回结果
    return result
}

介绍一下 RAF requestAnimationFrame?

image.png

前端性能如何优化?一般从几个方面考虑?

image.png