快速搞定前端JS面试 -- 第十三章 面试真题总结(要反复看的JS基础面试题)

concat函数(向数组后面追加一个数组)、map函数、filter函数(过滤)、slice函数(类似于深拷贝)


// 纯函数:1. 不改变源数组(没有副作用);2. 返回一个数组

const arr = [10, 20, 30, 40]

// concat

const arr1 = arr.concat([50, 60, 70])

// map

const arr2 = arr.map(num => num * 10)

// filter

const arr3 = arr.filter(num => num > 25)

// slice

const arr4 = arr.slice()

(2)非纯函数:push pop shift unshift、forEach、some 、every、 reduce

7. 数组slice和splice的区别


(1)功能区别:slice切片、splice剪接

(2)参数和返回值:返回值都为数组

(3)是否为纯函数:slice纯函数、splice非纯函数


const arr = [10, 20, 30, 40, 50]

// slice 纯函数

const arr1 = arr.slice()   // 10,20,30,40,50

const arr2 = arr.slice(1, 4)  // 20,30,40

const arr3 = arr.slice(2)   // 30,40,50

const arr4 = arr.slice(-2)    //40,50

// splice 非纯函数

const spliceRes = arr.splice(1, 2, 'a', 'b', 'c')   // 把1-2的位置移除再放入a,b,c

// const spliceRes1 = arr.splice(1, 2)    // 把1-2位置移除

// const spliceRes2 = arr.splice(1, 0, 'a', 'b', 'c')

console.log(spliceRes, arr)

8. Ajax请求get和post区别


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

get参数拼接在url上,post放在请求体内(数据体积可以更大),因此当进行上传提交操作时如果较大就是用post

安全性:post易于防止CSRF

9. [10, 20, 30].map(parseInt)


map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

parseInt() 函数可解析一个字符串,并返回一个整数 parseInt(string, radix),将string以radix进制转化为10进制


const res = [10, 20, 30].map(parseInt)

console.log(res)   //[10, NAN, NAN]

// 拆解

[10, 20, 30].map((num, index) => {

    return parseInt(num, index)

})

10. 闭包是什么?有何特性?有何影响?


闭包就是:有权访问另一个函数作用域变量的函数都是闭包

应用场景:函数作为参数被传递(函数在一个地方定义好之后,到另一个地方去执行)

函数作为返回值被返回(函数定义好之后会被返回到另一个地方执行)

机制:当我们调用一个闭包函数,在函数执行时,其上下文有个Scope属性,该属性作为一个作用域链包含有该函数被定义时所有外层的变量对象的引用,所以定义了闭包的函数虽然销毁了,但是其变量对象依然被绑定在函数inner上,保留在内存中。

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

影响:变量会常驻内存,得不到释放。因此闭包不要乱用,可能会影响性能(一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被垃圾回收器回收。但闭包让作用域里面的变量,在函数执行完之后依旧保存没有被垃圾回收处掉。)

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


event.stopPropagation()

event.preventDefault()

12. 如何减少DOM操作


DOM操作非常‘昂贵’(占用CPU,可能会造成浏览器重排,耗时),因此尽量避免频繁的DOM操作;

(1)缓存DOM查询结果

(2)多次DOM操作合并到一起

13. 解释jsonp的原理,为什么不是真正的Ajax


14. 函数声明和函数表达式的区别


函数声明 function fn() { … }

函数表达式 const fn = function() { … }

函数声明会在代码执行前预加载(类似变量提升),而函数表达式不会


// 函数声明

const res = sum(10, 20)

console.log(res)

function sum(x, y) {

    return x + y

}



// 函数表达式

var sum = function (x, y) {

    return x + y

}

var res = sum(10, 20)

console.log(res)

15. new Object()和Object.create()区别


{} 等同于new Object(), 原型 Object.prototype

ob1 = Object.create(null) 没有原型  obj2 = new Object()有原型  Object.create({ … })可以指定原型


const obj1 = {

    a: 10,

    b: 20,

    sum() {

        return this.a + this.b

    }

}

const obj2 = new Object({

    a: 10,

    b: 20,

    sum() {

        return this.a + this.b

    }

})

const obj21 = new Object(obj1) // obj1 === obj21

const obj3 = Object.create(null)  // {}没有属性没有原型

const obj4 = new Object() // {}有原型

// 意思创建一个空对象,把原型挂载到create内容上

const obj5 = Object.create({

    a: 10,

    b: 20,

    sum() {

        return this.a + this.b

    }

})

// 通过ob1创建obj6,那么obj6的原型指向obj1 obj6._proto_ === obj1

const obj6 = Object.create(obj1)  // obj6的原型指向obj1



16. 正则表达式


(1)用户名 字符串 字母开头 后面字母数字下划线,长度为6-30

const reg = / ^[a-zA-Z] \w {5,29} $ /

^开始 [ ] 选择 \w 字母数字下划线  {} 长度范围 $结尾 \d数字  +一次或多次   .匹配任意字符

(2)邮政编码   / \d{6} /

(3)小写英文字母   /^[a-z]+$ /

(4)英文字母 /^[a-zA-Z]+$/

(5)日期  /^\d{4}-\d{1,2}-\d{1,2}$/

(6)简单IP地址 /\d+\.\d+.\d+.\d+/          \. 表示.

常用正则表达式教程  https://www.runoob.com/regexp/regexp-syntax.html

17. 如何捕获JS程序中的异常


(1)手动捕获异常try-catch

(2)自动捕获异常 window.onerror


// 自动捕获

window.onerror = function (message, source, lineNum, colNum, error) {

     // 第一,对于跨域的js,如CDN的,不会有详细的报错信息

     // 第二,对于压缩的js,还要配合sourceMap反查到未压缩代码行列

}

18. 什么是JSON


json是一种数据格式,本质是一段字符串

json格式和JS对象结构一致,对JS语言更友好

window.JSON是全局对象(key都需要双引号),JSON.stringify JSON.parse

19. 获取当前页面url参数


(1)传统方法,查找Location.search

(2)URLSearchParams


// 传统方式

function query(name) {

    const search = location.search.substr(1) // 类似 array.slice(1)除去第一个

    // search: 'a=10&b=20&c=30'

    const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i') // i表示大小写不区分

    const res = search.match(reg)

    if (res === null) {

        return null

    }

    return res[2]  // 固定写法 输出b对应的值20

}

query('b')



// URLSearchParams

function query(name) {

    const search = location.search

    const p = new URLSearchParams(search)

    return p.get(name)

}

console.log( query('b') )



20. 介绍一下RAF requestAnimationFrame


在Web应用中,实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout或者setInterval 来实现,css3 可以使用 transition 和 animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame,顾名思义就是请求动画帧。

要想动画流畅,更新频率要60帧/秒,即16.67ms更新一次视图

setTimeout需要手动控制频率,而RAF浏览器会自动控制

后台标签或者隐藏iframe中(最小化),RAF会暂停,而setTimeout依然执行


// 3s 把宽度从 100px 变为 640px ,即增加 540px

// 60帧/s ,3s 180 帧 ,每次变化 3px

const $div1 = $('#div1')

let curWidth = 100

const maxWidth = 640

// RAF

function animate() {

    curWidth = curWidth + 3

    $div1.css('width', curWidth)

    if (curWidth < maxWidth) {

        window.requestAnimationFrame(animate) // 时间不用自己控制

    }

}

animate()

手写代码题

=========

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



// 判断是否是对象或数组(不考虑函数)

function isObject(obj) {

    return typeof obj === 'object' && obj !== null

}

// 全相等(深度)

function isEqual(obj1, obj2) {

    // 首先判断是否是对象

    if (!isObject(obj1) || !isObject(obj2)) {

        // 值类型(注意,参与 equal 的一般不会是函数)

        return obj1 === obj2

    }

    if (obj1 === obj2) {

        return true

    }

    // 两个都是对象或数组,而且不相等

    // 1. 先取出 obj1 和 obj2 的 keys ,比较个数

    const obj1Keys = Object.keys(obj1)

    const obj2Keys = Object.keys(obj2)

    if (obj1Keys.length !== obj2Keys.length) {

        return false

    }

    // 2. 以 obj1 为基准,和 obj2 依次递归比较

    for (let key in obj1) {

        // 比较当前 key 的 val —— 递归!!!

        const res = isEqual(obj1[key], obj2[key])

        if (!res) {

            return false

        }

    }

    // 3. 全相等

    return true

}



// 测试

const obj1 = {

    a: 100,

    b: {

        x: 100,

        y: 200

    }

}

const obj2 = {

    a: 100,

    b: {

        x: 100,

        y: 200

    }

}

// console.log( obj1 === obj2 )

console.log( isEqual(obj1, obj2) )



const arr1 = [1, 2, 3]

const arr2 = [1, 2, 3, 4]



2. 手写字符串trim方法,保证兼容(正则表达式)


trim  掐头去尾去空格


String.prototype.trim = unction () {

    return this.replace(/^\s+/,'').replace(/\s+$/,'')  // \s字符

}





3.将url参数解析为JS对象



// 传统方法,分析search

function queryToObj() {

    const res = {}

    const search = location.search.substr(1)  // 去掉?

    search.split('&').forEach(paramStr => {

        const arr = paramStr.split('=')

        const key = arr[0]

        const key = arr[1]

        res[key] = val

    })

    return res

}

// 使用URLSearchParams

function queryToObj() {

    const res = {}

    const pList = new URLSearchParams(location.search)

    pList.forEach((val, key) => {

        res[key] = val

    })

    return res

}

4. 手写flatern考虑多层级


将[1, 2, [3, 4, [10, 20, [100, 200]]], 5]变为[1, 2, 3, 4, 10, 20, 100, 200, 5]


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]

    }

    // oncat只能解决单层[]

    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)



5. 数组去重



// 传统方式

function unique(arr) {

    const res = []

    arr.forEach(item => {

        if (res.indexOf(item) < 0) { // 没有当前元素

            res.push(item)

        }

    })

    return res

}



// 使用 Set (无序,不能重复)

function unique(arr) {

    const set = new Set(arr)

    return [...set]   // 解构

}



const res = unique([30, 10, 20, 30, 40, 10])

console.log(res)



6. 手写深拷贝



function deepClone(obj = {}) {

    if (typeof obj !== 'object' || obj == null) {

        // 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

}

7. 手写一个简易的jQuery,考虑插件和扩展性



class jQuery {


### 最后

![](https://img-blog.csdnimg.cn/img_convert/d09f668d8fe540be624ae525b1a7b9d8.webp?x-oss-process=image/format,png)

![](https://img-blog.csdnimg.cn/img_convert/01ebf54be43c3bb1d1ee326b2d38142d.webp?x-oss-process=image/format,png)

**资料过多,篇幅有限**



>自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。

 30, 40, 10])

console.log(res)



6. 手写深拷贝



function deepClone(obj = {}) {

    if (typeof obj !== 'object' || obj == null) {

        // 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

}

7. 手写一个简易的jQuery,考虑插件和扩展性



class jQuery {


### 最后

[外链图片转存中...(img-ysn867G8-1718098799963)]

[外链图片转存中...(img-5UVTke4G-1718098799965)]

**资料过多,篇幅有限**



>自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值