web前端面试宝典——带你直击面试重难点(40个经典题目,涵盖近90%的考点,码字2w,干货满满!)
Posted 前端杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web前端面试宝典——带你直击面试重难点(40个经典题目,涵盖近90%的考点,码字2w,干货满满!)相关的知识,希望对你有一定的参考价值。
系列文章目录
javascript 知识梳理,收录了web前端面试 95%以上 的高频考点,满满的干货。给你做一个高效的知识梳理,为你的面试保驾护航!
内容 | 参考链接 |
---|---|
html & CSS 篇 | HTML & CSS 篇 |
JavaScript 篇(一) | JavaScript 篇(一)【JS的三座大山 】原型和原型链、作用域和闭包、异步 |
JavaScript 篇(二) | JavaScript 篇(二)【JS 异步进阶】 |
JavaScript-Web-API 篇(一) | JavaScript-Web-API 篇(一)DOM、BOM、事件 |
JavaScript-Web-API 篇(二) | JavaScript-Web-API 篇(二)AJAX、存储 |
HTTP 篇 | HTTP 篇 |
性能优化篇 | 性能优化篇(手写防抖、手写节流、XXS攻击、XSRF攻击) |
经典面试题-JS篇 | 经典面试题 HTML、CSS、JavaScript篇 |
文章目录
- 系列文章目录
- var 和 let const 的区别
- typeof 能判断哪些类型
- 列举强制类型转换和隐式类型转换
- 手写深度比较 lodash.isEqual
- split() 和 join() 的区别
- pop、shift、push、unshift
- 数组的API,有哪些是纯函数
- 数组 slice 和 splice 的区别
- [10, 20, 30].map(parseInt) 输出结果
- ajax 请求 get 和 post 的区别
- 函数 call 、apply 和 bind 的区别
- 事件代理(委托)
- 闭包
- 阻止事件冒泡和默认行为
- 如何减少 DOM 操作
- jsonp 的本质是 ajax 吗
- document load 和 ready 的区别
- == 和 ===
- 函数声明和函数表达式的区别
- 关于 this 的场景题
- new Object() 和 Object.create() 区别
- 作用域和自由变量
- 作用域和自由变量 2
- 常见正则表达式
- 手写字符串 trim
- 获取多个数字中的最大值
- class 实现继承
- 如何捕获 JS 中的异常
- 什么是 JSON
- 获取当前页面 url 参数
- 将 url 参数解析为 JS 对象
- 数组去重
- 手写深拷贝
- Object.assign()
- 了解 RAF requestAnimationFrame
- 优化性能的考虑方面
- Map 和 Object 的区别
- Set 和 数组的区别
- WeakMap 和 WeakSet
- reduce 的使用
声明:全篇近两万字,耗时五天完成。涵盖了JavaScript 面试高频考点,码字不易,如果对你有帮助,还请多多支持!(先点赞,后观看,期待你的一键三连!)
var 和 let const 的区别
- var 是 ES5 语法,let const 是 ES6 语法;var 有变量提升
- var 和 let 是变量,可修改;const 是常量,不可修改
- let const 有块级作用域,var 没有
示例:变量提升
console.log(a) // undefined
var a = 100
// 相当于
var a
console.log(a) // undefined
a = 100
示例:块级作用域
for(let i = 0; i < 5; i++)
let j = i + 1
console.log(i)
typeof 能判断哪些类型
- undefined string number boolean symbol
- object(注意:typeof null === ‘object’)
- function
列举强制类型转换和隐式类型转换
- 强制:parseInt parseFloat toString
- 隐式:if、逻辑运算、==、+ 拼接字符串
手写深度比较 lodash.isEqual
- isObject 来判断传入的参数是否为对象
- 如果不是对象直接返回它们的全等
- 如果传入的是同一个对象或数组,直接返回 true
- 如果传入的是两个不相等的对象或数组
- 则先判断长度,不一样直接返回 false
- 一样的话,以 obj1 为基准,和 obj2 依次递归比较
- 不相等返回 false,全满足了返回 true
// 判断是否是对象或数组
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: 10,
b:
x: 100,
y: 200
const obj2 =
a: 10,
b:
x: 100,
y: 200
console.log(isEqual(obj1, obj2)) // true
split() 和 join() 的区别
Array.join()
方法是String.split()
方法的反向操作split('-')
把字符串去掉-
转为数组join('-')
把数组加上-
转为字符串
'1-2-3'.split('-')
[1, 2, 3].join('-')
pop、shift、push、unshift
以 arr 为例
const arr = [10, 20, 30]
pop:
- 功能:删除数组的最后一个元素
- 返回值:被删除的元素
- 是否对原数组造成影响:是
// pop
const popRes = arr.pop()
console.log(popRes, arr)
shift:
- 功能:删除数组的第一个元素
- 返回值:被删除的元素
- 是否对原数组造成影响:是
const shiftRes = arr.shift()
console.log(shiftRes, arr)
push:
- 功能:从尾部添加元素
- 返回值:数组的长度
- 是否对原数组造成影响:是
const pushRes = arr.push(40)
console.log(pushRes, arr)
unshift:
- 功能:从头部添加元素
- 返回值:数组的长度
- 是否对原数组造成影响:是
const unshiftRes = arr.unshift(5)
console.log(unshiftRes, arr)
数组的API,有哪些是纯函数
纯函数:
- 不改变源数组(没有副作用)
- 返回一个数组
const arr = [10, 20, 30]
concat:
// concat
const arr1 = arr.concat([40, 50])
console.log(arr, arr1)
map:
// map
const arr2 = arr.map(num => num * 2)
console.log(arr, arr2)
filter:
// filter
const arr3 = arr.filter(num => num > 15)
console.log(arr, arr3)
slice:
// slice
const arr4 = arr.slice(2)
console.log(arr, arr4)
数组 slice 和 splice 的区别
- 功能区别:slice 切片,splice 剪接
- 参数和返回值
- 是否纯函数
slice:
- slice 切片
- 参数可传可不传,返回值是切片后的数组
- 是纯函数(不改变原始数组)
const arr = [10, 20, 30, 40, 50]
// slice 纯函数
const arr1 = arr.slice()
const arr2 = arr.slice(1, 4)
const arr3 = arr.slice(2)
const arr4 = arr.slice(-2)
console.log(arr) // [10, 20, 30, 40, 50]
console.log(arr1) // [10, 20, 30, 40, 50]
console.log(arr2)// [20, 30, 40]
console.log(arr3) // [30, 40, 50]
console.log(arr4) // [40, 50]
splice:
- splice 剪接
- 参数可传可不传,返回值是剪接掉的元素的数组
- 非纯函数(改变原始数组)
- 解读:开始剪接的元素索引(
1
),剪接的元素个数(2
),要添加的元素('a', 'b', 'c'
)
const arr = [10, 20, 30, 40, 50]
// splice 非纯函数
const spliceRes = arr.splice(1, 2, 'a', 'b', 'c')
console.log(spliceRes) // [20, 30]
console.log(arr) // [10, 'a', 'b', 'c', 40, 50]
const arr = [10, 20, 30, 40, 50]
// splice 非纯函数
const spliceRes1 = arr.splice(1, 0, 'a', 'b', 'c')
console.log(spliceRes1) // []
console.log(arr) // [10, 'a', 'b', 'c', 20, 30, 40, 50]
const arr = [10, 20, 30, 40, 50]
// splice 非纯函数
const spliceRes2 = arr.splice(1, 2)
console.log(spliceRes2) // [20, 30]
console.log(arr) // [10, 40, 50]
[10, 20, 30].map(parseInt) 输出结果
map:
- 第一个参数是当前元素
- 第二个参数是当前索引值
parseInt:
- 第一个参数是要被解析的字符串
- 第二个参数是要解析的数字的基数(进制数 2~36)
const res = [10, 20, 30].map(parseInt)
console.log(res)
// 拆解
const res2 = [10, 20, 30].map((num, index) =>
return parseInt(num, index)
)
console.log(res2)
ajax 请求 get 和 post 的区别
- get 一般用于查询操作,post 一般用于提交操作
- get 参数拼接在 url 上,post 放在请求体内(数据体积可更大)
- 安全性:post 易于防止 CSRF 攻击
函数 call 、apply 和 bind 的区别
- call 传入的参数直接放进去
- apply 传入的参数是一个数组或类数组
- bind 返回的是一个新的函数,必须调用它才会被执行
fn.call(this, p1, p2, p3)
fn.apply(this, arguments)
fn.bind(this, p1, p2, p3)()
示例:
let zhangsan =
name: '张三',
age: 20,
myFun(from, to)
console.log(this.name + this.age, '来自' + from + '去往' + to)
let lisi =
name: '李四',
age: 22
zhangsan.myFun.call(lisi, '济南', '青岛')
zhangsan.myFun.apply(lisi, ['济南', '青岛'])
zhangsan.myFun.bind(lisi, '济南', '青岛')()
事件代理(委托)
- 把 每个 li 的点击事件委托给 ul
- 可以减少内存的消耗
- 可以减少重复性操作
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
...
<li>item n</li>
</ul>
//获取目标元素
const lis = document.getElementsByTagName('li')
//循环遍历绑定元素
for (let i = 0; i < lis.length; i++)
lis[i].onclick = function (event)
console.log(event.target.innerHTML)
闭包
闭包的影响:变量会常驻内存,得不到释放。闭包不要乱用
阻止事件冒泡和默认行为
- 阻止冒泡:
event.stopPropagation()
点击激活,不会弹出取消 - 阻止默认行为:
event.preventDefault()
点击超链接,不会跳转
<p id="p1">激活</p>
<a id="a1" href="https://baidu.com">取消</a>
const p1 = document.getElementById('p1')
const a1 = document.getElementById('a1')
const body = document.body
p1.addEventListener('click', function (event)
event.stopPropagation()
alert('激活')
)
body.addEventListener('click', function (event)
alert('取消')
)
a1.addEventListener('click', function(event)
event.preventDefault()
)
阻止冒泡 —> 点击激活,不会弹出取消:
如何减少 DOM 操作
- 缓存 DOM 查询结果
- 多次 DOM 操作,合并到一次插入
<ul id="list"></ul>
const list = document.getElementById('list')
// 创建一个文档片段,此时还没有插入到 DOM 结构中
const frag = document.createDocumentFragment()
for(let i = 0; i < 10; i++)
const li = document.createElement('li')
li.innerHTML = `List item $i`
// 先插入文档片段中
frag.appendChild(li)
// 都完成之后,再统一插入到 DOM 结构中
list.appendChild(frag)
jsonp 的本质是 ajax 吗
- 不是,因为没有用到 XMLHttpRequest 对象,所以 jsonp 不属于 ajax。
- 它是通过能够绕过跨域的
<script>
标签实现的
document load 和 ready 的区别
window.addEventListener('load', function()
// 页面的全部资源加载完才会执行,包括图片、视频等
)
window.addEventListener('DOMContentLoaded', function()
// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
)
== 和 ===
==
会尝试类型转换===
严格相等- 除了
==
null 之外,其他都用===
函数声明和函数表达式的区别
- 函数声明:function fn() …
- 函数表达式:const fn = function () …
示例:函数声明
const res = sum(10, 20)
console.log(res) // 30
function sum(x, y)
return x + y
示例:函数表达式
const res = sum(10, 20)
console.log(res) // 报错
const sum = function (x, y)
return x + y
用 var 声明:
关于 this 的场景题
- 第一个输出:this 指向当前对象 obj
- 第二个输出:this 指向 window
const obj =
count: 1,
getCount: function()
return this.count
console.log(obj.getCount()) // 1
const func = obj.getCount
console.log(func()) // undefined
new Object() 和 Object.create() 区别
- 等同于 new Object(),原型 Object.prototype
- Object.create(null) 没有原型
- 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 obj1 =
a: 10,
b: 20,
sum()
return this.a + this.b
const obj2 = new Object(obj1)
示例:
const obj1 = Object.create(null)
const obj2 = new Object(null)
示例:
const obj1 =
a: 10,
b: 20,
sum(
都说程序员工资高、待遇好,改变无数程序员职业生涯的金九银十快来了,你的小目标是什么 30K、40K,还是 16 新的 20K?作为一名 Java 开发工程师,当能力可以满足公司业务需求时,拿到超预期的奖励 Offer 并不算难。然而,提升 Java 核心能力最快、最有效,短期内升职加薪的方法,到底是什么?
首先,你需要跳出日常工作,接触更有深度、更前沿的顶级项目。一个简单的逻辑:大厂之所以能够给到高于行业水准的薪资,正是因为即使是普通开发人员,也要应对很多复杂的场景。这些复杂场景和项目,就像“墙外的世界”,没有看过,没有接触过,你就无法进行体系化的学习和建立认知,技术壁垒自然就出现了。
面试最重要的是什么?就是要直击面试官的痛点!
下面给大家分享的这本书可以让大家在大厂面试中和面试官有一战之力
Java面试
为什么要先给大家展示目录内容,因为这本书有足足1000多页资料,先给大家看目录可以让大家大概的了解本书内容!需要获取的小伙伴查看文末自取PDF资料!
内容展示:
资料免费获取方式:一键三连(点赞+转发+关注小编),扫下方二维码免费获取~