本文接上文的: 前端真题【我是来告诉你答案是什么】之一
接下来开始题目8 ~~
8. 题目8
8.1 关于作用域和自由变量的场景题-1
执行结果
8.2 判断字符串以字母开头,后面字母数字下划线,长度6-30
- 答案
const reg = /^[a-zA-Z]\w{5,29}$/
-
扩展
- 邮政编码:
/\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
函数定义之后,先不用管他,等执行的时候再看细节代码 答案
100
10
10
9. 题目9
9.1 手写字符串trim方法,保证浏览器兼容性
9.2 如何获取多个数字中的最大值
max(10, 20, 50, 30, 20, 14)
9.3 如何用JS 实现继承
- class 继承
- prototype 继承 由于class使用的普及 prototype 继承 就不太推荐了
10. 题目10
10.1 如何捕获JS中的异常
- 手动捕获
- 自动捕获
10.2 什么是JSON
- json 是一种数据格式,本质是一段字符串
- json 格式和JS对象结构一致,对JS语言更友好
window.JSON是一个全局对象:JSON.stringify、JSON.parse
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')
不用正则,也可用 “&”数组截取,来获取的
新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 对象
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 手写深拷贝
注意,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 有序和无序
对象里面的属性,都是无序的。数组里的数值都是有序的。
- 有序:操作慢
- 无序:操作快,但无序
如何结合两者优点呢?
- 二叉树、及其变种
13.2 Map 和 Object 的区别
- 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')
// 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')
13.3 Set和Array的区别
- 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')
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')
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
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)