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

// 传统方式

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为空,只有三个参数,是普通绑定

fn.call(target, event)

}

})

}

// 普通绑定

const btn1 = document.getElementById(‘btn1’)

bindEvent(btn1, ‘click’, function (event) {    // 注意不能使用箭头函数,否则获取的是上级window

// console.log(event.target) // 获取触发的元素

event.preventDefault()

alert(this.innerHTML)     // this

})

// 代理绑定

const div3 = document.getElementById(‘div3’)

bindEvent(div3, ‘click’, ‘a’, function (event) {

event.preventDefault()    // 阻止默认行为(页面页面调转)

alert(this.innerHTML) // 如果使用箭头函数的写法 event.target.innerHTML

})

10. 手写防抖和节流


// 防抖封装

function debounce(fn, delay = 500) {

// timer 是闭包中的

let timer = null

// 返回一个函数

return function () {

if (timer) {

clearTimeout(timer)

}

timer = setTimeout(() => {

fn.apply(this, arguments)

timer = null

}, delay)

}

}

input1.addEventListener(‘keyup’, debounce(function (e) {

console.log(e.target)

console.log(input1.value)

}, 600))

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

常用的JavaScript设计模式

  • 单体模式

  • 工厂模式

  • 例模式

函数

  • 函数的定义

  • 局部变量和全局变量

  • 返回值

  • 匿名函数

  • 自运行函数

  • 闭包

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)**
[外链图片转存中…(img-mUZTrPcc-1712768839637)]

常用的JavaScript设计模式

  • 单体模式

  • 工厂模式

  • 例模式

函数

  • 函数的定义

  • 局部变量和全局变量

  • 返回值

  • 匿名函数

  • 自运行函数

  • 闭包

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-wXrsAGen-1712768839637)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值