JavaScript常见面试真题总结
1. var、let和const的区别
var
是 ES5 语法,let conts
是 ES6 语法,var
有变量提升var
和let
是定义变量,变量可修改;const
是定义常量,不可修改let const
有块级作用域,var
没有
// 1. 变量提升
console.log(a) // undefined
var = 100
var a
console.log(a)
a = 100
console.log(b) // 报错
let b = 100
// 2. 块级作用域
// let 形成块级作用域
for(let i = 0; i < 10; i++) {
let j = i + 1
}
console.log(i, j) // 报错
// var 变量提升
for(var i = 0; i < 10; i++) {
var j = i + 1
}
console.log(i, j) // 10 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2. typeof能判断哪些类型
- 基本类型:string,number,boolean,Symbol,undefined
- 对象:object(注意,typeof null === 'object')
- 方法:function
3. 列举强制类型转换和隐式类型转换
- 强制类型转换:parseInt parseFloat toString 等
- 隐式类型转换:if、逻辑运算、==、+拼接字符串
4. 手写深度比较isEqual
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function isArray(obj) {
return Array.prototype.isArray(obj)
}
function isEqual(o1, o2) {
// 如果是其中一个不是对象,则直接比较
if (!isObject(o1) || !isObject(o2)) {
return o1 === o2
}
// 如果是同一个对象,即引用相同
if (o1 === o2) {
return true
}
// 如果有一个是对象,有一个是数组
if ((isObject(o1) && isArray(o2)) || (isArray(o1) && isObject(o2))) {
return false
}
// 两个都是对象或数组
const o1Keys = Object.keys(o1)
const o2Keys = Object.keys(o2)
if (o1Keys.length !== o2Keys.length) {
return false
}
for (let key in o1Keys) {
const res = isEqual(o1[key], o2[key])
if (!res) {
return false
}
}
return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
5. push pop和unshift shift
面试回答思路:
- 功能是什么
- 参数和返回值时什么
- 是否会对原数组造成影响
push
:在数组结尾添加一个元素,返回 lengthpop
:删除数组最后一个元素,返回被删除的元素unshift
:在数组的开头添加一个元素,返回 lengthshift
:删除数组第一个元素,返回被删除的元素
(1)改变原有数组的方法
push
pop
unshift
shift
(2)不改变原有数组的方法(纯函数)
concat
map
filter
slice
5. slice和splice的区别
1. slice
切片函数,无副作用,对原函数无影响
/**
* @param startIndex 切片开始的位置
* @param endIndex 切片结束的位置,返回的数组不包含该位置的元素
* @return 新的数组
*/
slice(startIndex, endIndex)
1
2
3
4
5
6
2
3
4
5
6
let arr = [10, 20, 30, 40, 50]
const arr1 = arr.slice() // [10, 20, 30, 40, 50], 不切片,返回新数组,相当于克隆
const arr2 = arr.slice(1, 3) // [20, 30]
const arr3 = arr.slice(2) // [30, 40], 从开始位置截取至末尾
const arr4 = arr.slice(-3) // [20, 30, 40], 从尾部往回截取
1
2
3
4
5
6
7
2
3
4
5
6
7
2. splice
剪接函数,有副作用,会对原函数造成影响
/**
* @param startIndex 开始删除的位置
* @param deleteCount 从startIndex起,删除的元素的个数
* @param items 拼接的items
* @return 包含被删除元素的数组
*/
splice(startIndex, deleteCount, ...items)
1
2
3
4
5
6
7
2
3
4
5
6
7
let arr = [10, 20, 30, 40]
// 删除 + 拼接
const arr1 = arr.splice(1, 2, 'a', 'b') // [20, 30],原数组:[10, 'a', 'b', 40]
// 只删除
const arr2 = arr.splice(1, 2) // [20, 30],原数组:[10, 40]
// 只删除
const arr3 = arr.splice(1, 0, 'a', 'b') // [ ],原数组[10, "a", "b", 20, 30, 40]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
6. [10, 20, 30].map(parseInt)
考察要点:
- map函数
- parseInt函数
- 函数简写拆解
答案:[10, Nan, Nan]
解析:
- map传入一个函数,返回传入函数作用于原数组的新数组
- parseInt:第一个参数为需要转换的数据,第二参数为进制(0和10都是十进制)
- 简写拆解:
[10, 20, 30].map((num, index) => parseInt(num, index))
1
7. get和post的区别
get
一般用于查询操作,post
一般用于提交数据get
参数拼接在 url 上,post
提交参数放在请求体中- 安全性:
post
易于防止 CSRF