前端真题【我是来告诉你答案是什么】之二

272 阅读1分钟

本文接上文的: 前端真题【我是来告诉你答案是什么】之一

接下来开始题目8 ~~

8. 题目8

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

image.png

执行结果

image.png

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

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

# 正则表达式 - 语法 | 菜鸟教程

# 正则表达式30分钟入门教程

  • 扩展

    • 邮政编码: /\d{6}/
    • 小写英文字母:/^[a-z]+$/
    • 英文字母:/^[a-zA-z]+$/
    • 日期格式:2019.12.1 /^/d{4}-/d{1,2}-/d{1,2}$/
    • 用户名:/^[a-zA-z]\w{5,17}$/
    • 简单的 IP 地址匹配:/\d+\.d+\d+\.\d+/

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

image.png

函数定义之后,先不用管他,等执行的时候再看细节代码 答案

100
10
10

9. 题目9

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

image.png

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

max(10, 20, 50, 30, 20, 14)

image.png

image.png

9.3 如何用JS 实现继承

  • class 继承
  • prototype 继承 由于class使用的普及 prototype 继承 就不太推荐了

10. 题目10

10.1 如何捕获JS中的异常

  • 手动捕获 image.png
  • 自动捕获 image.png

10.2 什么是JSON

  • json 是一种数据格式,本质是一段字符串
  • json 格式和JS对象结构一致,对JS语言更友好
  • window.JSON 是一个全局对象:JSON.stringifyJSON.parse

image.png json 不能用单引号,属姓名 也要用双引号

10.3 获取当前页面url 参数

传统方式,查找 location.search

// 传统方式
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')
    const res = search.match(reg)
    if (res === null) {
        return null
    }
    return res[2]
}
query('d')

image.png 不用正则,也可用 “&”数组截取,来获取的

新API,URLSearchParams

// URLSearchParams
function query(name) {
    const search = location.search
    const p = new URLSearchParams(search)
    return p.get(name)
}
console.log( query('b') )

11. 题目11

11.1 将url参数解析为JS 对象

image.png

image.png

11.2 手写数组 flatern,考虑多层级

// concat demo
const a = [1,2,[3,4]]
Array.prototype.concat.apply([], a) // (4) [1, 2, 3, 4]

js实现

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) // [1, 2, 3, 4, 10, 20, 100, 200, 5]

11.3 数组去重

  • 传统方式,遍历元素挨个比较,去重
// 传统方式
function unique(arr) {
    const res = []
    arr.forEach(item => {
        if (res.indexOf(item) < 0) {
            res.push(item)
        }
    })
    return res
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res)
  • 使用Set
// 使用 Set (无序,不能重复)
function unique(arr) {
    const set = new Set(arr)
    return [...set]
}

const res = unique([30, 10, 20, 30, 40, 10])
console.log(res)
  • 考虑计算效率
    • Set的效率更高

12. 题目12

12.1 手写深拷贝

image.png

注意,Object.assgin 不是深拷贝!

12.2 介绍一下 RAF requestAnimateFrame

  • 要想动画流畅,更新频率要60帧/s,即16.67ms更新一次视图
  • setTimeout 要手动控制更新频率,而RAF浏览器会自动控制
  • 后台标签或隐藏在iframe中,RAF会暂停,而setTimeout 依然执行

实现如下

  • 3s 把宽度从 100px 变为 640px ,即增加 540px
  • 60帧/s ,3s 180 帧 ,每次变化 3px
// index.html
<style>
    #div1 {
        width: 100px;
        height: 50px;
        background-color: red;
    }
</style>

<p>JS requestAnimateFrame演示</p>
<div id="div1"></div>

<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.js"></script>
<script src="./RAF.js"></script>
// RAF.js

// 3s 把宽度从 100px 变为 640px ,即增加 540px
// 60帧/s ,3s 180 帧 ,每次变化 3px

const $div1 = $('#div1')
let curWidth = 100
const maxWidth = 640

// // setTimeout
// function animate() {
//     curWidth = curWidth + 3
//     $div1.css('width', curWidth)
//     if (curWidth < maxWidth) {
//         setTimeout(animate, 16.7) // 自己控制时间
//     }
// }
// animate()

// RAF
function animate() {
    curWidth = curWidth + 3
    $div1.css('width', curWidth)
    if (curWidth < maxWidth) {
        window.requestAnimationFrame(animate) // 时间不用自己控制
    }
}
animate()

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

  • 原则:多使用内存、缓存,减少计算、减少网络请求
  • 方向:加载页面,页面渲染,页面操作流畅度

# 前端性能优化原理与实践

13. Map 和 Set 有序和无序

13.1 有序和无序

image.png

对象里面的属性,都是无序的。数组里的数值都是有序的。

image.png

  • 有序:操作慢
  • 无序:操作快,但无序

如何结合两者优点呢?

  • 二叉树、及其变种

13.2 Map 和 Object 的区别

扩展:# JavaScript版:数据结构之“字典”

  • API不同,Map可以以任意类型为key
  • Map 是有序结构(重要)
  • Map 操作同样很快
const obj = {
    key1: 'hello',
    key2: 100,
    key3: { x:100 }
}

const m = new Map([
    ['key1', 'hello'],
    ['key2', 100],
    ['key3',  { x: 100 }]
])
// m.set('name', 'perry')
// m.set('key1', 'hello world')
// m.delete('key2')
// m.has('key3')
// m.forEach((value, key) => console.log(key, value))
// m.size

Map 以任意类型为 key

// const o = { name: 'xxx' }
// m.set(o, 'object key')
// function fn() {}
// m.set(fn, 'fn key')

obj1 , obj2关联,但是没有引用关系,保持独立

// obj1.xxx = obj2

// m.set(obj1, obj2) // 关联,但是没有引用关系,保持独立
// m.get(obj1) // obj2

object 无序

const obj = {  2: 20, 3: 30, 1: 10 }
console.log(Object.keys(obj))

Map 有序的,但是还很快

// object 有多快?
const obj = {}
for (let i = 0; i < 1000 * 10000; i++) {
    obj[i + ''] = i
}
console.time('obj find')
obj['5000000']
console.timeEnd('obj find')
console.time('obj delete')
delete obj['5000000']
console.timeEnd('obj delete')

image.png

// Map 有多快
const m = new Map()
for (let i = 0; i < 1000 * 10000; i++) {
    m.set(i + '', i)
}
console.time('map find')
m.has('5000000')
console.timeEnd('map find')
console.time('map delete')
m.delete('5000000')
console.timeEnd('map delete')

image.png

13.3 Set和Array的区别

扩展:# JavaScript版:数据结构之“集合”

  • API 不同
  • Set 元素不能重复
  • Set 是无序结构,操作很快
const arr = [1, 10, 20, 30, 40, 50]
const set = new Set([10, 20, 30, 40])

set.add(50)
set.delete(20)
set.has(30)
set.size
set.forEach(val => console.log(val)) // 没有 index

Set 元素是不能重复的(数组去重)

Set 是无序的(快), arr 是有序的(慢)

arr 有多慢?

// arr 有多慢?
const arr = []
for (let i  = 0; i < 100 * 10000; i++) {
    arr.push(i)
}
console.time('arr unshift')
arr.unshift('a')
console.timeEnd('arr unshift')
console.time('arr push')
arr.push('b')
console.timeEnd('arr push')
console.time('arr find')
arr.includes(500000)
console.timeEnd('arr find')

image.png

set 有多快?

// set 有多快?
const set = new Set()
for (let i  = 0; i < 100 * 10000; i++) {
    set.add(i)
}
console.time('set add')
set.add('a')
console.timeEnd('set add')
console.time('set find')
set.has(500000)
console.timeEnd('set find')

image.png

14. WeakMap 和 WeakSet

  • 1、弱引用,防止内存泄漏
  • 2、WeakMap 只能用对象作为key,WeakSet 只能用对象作为value
  • 3、没有forEach和size, 只能用add、delete、has

WeakMap 弱引用,防止内存泄漏

//  WeakMap 弱引用,防止内存泄漏
const wMap = new WeakMap()
function fn() {
    const obj = { name: '双越' }
    wMap.set(obj, 'name info') // 只能用对象作为 key
}
fn()
// 没有 forEach size ,只能 has delete add
// 垃圾回收机制,标记清除,gc 垃圾清理不一定是及时的

WeakMap 场景

// WeakMap 场景
const userInfo = { name: '双越' }
const cityInfo = { city: '北京' }
// userInfo.city = cityInfo
wMap.set(userInfo, cityInfo) 
// 建立一种关联关系,而且两者保持独立,而且**不影响彼此的销毁逻辑**
wMap.get(userInfo)

WeakSet 弱引用,防止内存泄漏,只能用对象作为 value

// WeakSet 弱引用,防止内存泄漏,只能用对象作为 value 
// 没有 forEach size ,只能 has delete add
const wSet = new WeakSet()
// const set = new Set()
function fn() {
    const obj = { name: '双越' }
    wSet.add(obj)
    // set.add(obj)
}
fn()

15. 数组求和-Array reduce

传统数组求和

 // 传统
function sum(arr) {
    let res = 0 // 需要新定义一个变量
    arr.forEach(n => res = res + n)
    return res
}
const arr = [10, 20, 30, 40, 50]
sum(arr)

reduce 求和

const arr = [10, 20, 30, 40, 50]
const res = arr.reduce((sum, curVal, index, arr) => {
    console.log('reduce function ....')
    console.log('sum', sum)
    console.log('curVal', curVal)
    console.log('index', index)
    console.log('arr', arr)

    return sum + curVal // 返回值,会作为下一次执行时的第一个参数 sum 的值
}, 0)
console.log('res', res) // 150

image.png

reduce 简化

const res = arr.reduce((sum, curVal) => sum + curVal, 0)
console.log('res', res)

reduce 计数

const arr = [10, 20, 30, 40, 50, 10, 20, 30, 20]
const n = 30
const count = arr.reduce((count, val) => {
    return val === n ? count + 1 : count
}, 0)
console.log('count', count)

reduce 输出字符串

const arr = [
    { name: '张三', age: '20' },
    { name: '李四', age: '21' },
    { name: '小明', age: '22' },
]

// map实现
// const str = arr.map(item => {
//     return `${item.name} - ${item.age}`
// }).join('\n')
// console.log(str)

// reduce实现
const str = arr.reduce((s, item) => {
    return `${s}${item.name} - ${item.age}\n`
}, '')
console.log(str)