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

本文详细介绍了JavaScript中的闭包、DOM操作优化、正则表达式、异常处理、JSONP、函数声明与表达式、新Object()与Object.create()的区别、事件监听和动画API(RAF)、深拷贝以及简单的jQuery实现。此外,还提及了前端开发学习资源的分享。
摘要由CSDN通过智能技术生成

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 {

constructor(selector) {

const result = document.querySelectorAll(selector)

const length = result.length

for (let i = 0; i < length; i++) {

this[i] = result[i]

}

this.length = length

this.selector = selector

}

get(index) {

return this[index]

}

each(fn) {

for (let i = 0; i < this.length; i++) {

const elem = this[i]

fn(elem)

}

}

on(type, fn) {

return this.each(elem => {

elem.addEventListener(type, fn, false)

})

}

// 扩展很多 DOM API

}

// 插件

jQuery.prototype.dialog = function (info) {

alert(info)

}

// 扩展 “造轮子”

class myJQuery extends jQuery {

constructor(selector) {

super(selector)

}

// 扩展自己的方法

addClass(className) {

}

style(data) {

}

}

8. 手写bind函数


// 模拟 bind

Function.prototype.bind1 = function () {

// 将参数拆解为数组

const args = Array.prototype.slice.call(arguments)

// 获取 this(数组第一项)

const t = args.shift()     // 拿走数组第一项

// fn1.bind(…) 中的 fn1

const self = this

// bind返回一个函数

return function () {

return self.apply(t, args)

}

}

function fn1(a, b, c) {

console.log(‘this’, this)

console.log(a, b, c)

return ‘this is fn1’

}

const fn2 = fn1.bind1({x: 100}, 10, 20, 30)

const res = fn2()

console.log(res)

9. 通用的事件监听函数


function bindEvent(elem, type, selector, fn) {  // selector是个css选择器

if (fn == null) {   // 判断只传入三个参数

fn = selector

selector = null

}

elem.addEventListener(type, event => {

const target = event.target

if (selector) {

// 有selector时是代理绑定

if (target.matches(selector)) {  // 判断DOM元素是否符合css选择器

fn.call(target, event)

}

} else {

// selector为空,只有三个参数,是普通绑定
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

资料获取方式:点击蓝色传送门免费获取

if (selector) {

// 有selector时是代理绑定

if (target.matches(selector)) {  // 判断DOM元素是否符合css选择器

fn.call(target, event)

}

} else {

// selector为空,只有三个参数,是普通绑定
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-DoMXBHEO-1713805866066)]

[外链图片转存中…(img-54az79XS-1713805866066)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-UDsj8EBp-1713805866067)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-gffTxDzD-1713805866067)]

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

资料获取方式:点击蓝色传送门免费获取

[外链图片转存中…(img-2W5pc1vK-1713805866067)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值