JS面试题集合

闲了很久,来看看JS面试题

img

涩涩狗子镇楼!

1:延迟加载JS的方式?

async 与 defer

async 是解析与渲染DOM结构同时进行

defer虽然也是解析script脚本与渲染DOM同时进行,但是会等待DOM结构渲染完成以后再去加载script

1
2
<script defer src="../"><script>
<script async src="../"><script>

2:数据类型

javascript数据类型分为基本类型与引用类型两大类

基本类型:string,number,boolean,null,undefined,symbol,bigInt(存在争论,有些人认为不应该)

引用类型:object(object是一个大类,包含对象,数组,函数等引用类型)

3:null和undefined的区别

最初javascript木有undefined类型,是作者后续添加的,他本人认为不能将一切表示为无的值都设置为null,可以将无的基本类型设置为undefined

4:== 与 === 的区别

== 在数据比较时,会隐式转换(调用valueof进行转换对比),只比较值不比较类型

而===比较类型也比较值 必须到完全的相同,因此在项目中比较两个值应该采用===的方式

1
2
3
4
let a = 2
if(a == '2'){
console.log(' a = '2' ')
}

5:微任务和宏任务

script脚本中包含同步与异步逻辑,页面会首先执行同步代码,再执行异步代码

而异步代码又区分为微任务和宏任务,与事件循环机制相关

在执行宏任务之前,会查看页面有没有未执行的微任务,先清空页面微任务再执行宏任务

微任务:Promise.then

宏任务:定时器,事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
setTimeout(()=>{
console.log('123')
},2000)

new Promise((resolve,reject)=>{
console.log('promise')
resolve()
}).then(()=>{
console.log('then1')
resolve()
}).then(()=>{
console.log('then2')
resolve()
})

console.log('同步')

result: 'promise' '同步' 'then1' 'then2' '123'

6:作用域:smile_cat:

1:除了函数外 js是没有块级作用域的

1
2
3
4
5
6
7
8
9
10
function aa(){
let a = 10
}
aa()
console.log(a) ::a is not defined

for(var i = 1; i < 10 : i++){

}
console.log(i) : i = 10

2:作用域链 内部可以访问外部变量 外部无法访问内部变量 从内到外依次查找 遵循内部优先

1
2
3
4
5
6
7
8
let a = 10
function fn(){
function fnn(){
console.log(a)
}
fnn()
}
fn() : 10

3;声明变量不带var 那么就是挂载window上 任意位置都能访问

var a = b = 10 === var a = 10 window.b = 10

var a,b = 10 === var a = 10 var b = 10

4:js有变量提升 国外称为变量悬挂声明

1
2
3
4
5
6
function fn(){
//var str
console.log(str) // undefined
var str = 20
}
fn()

5:优先级

声明变量 > 声明普通函数 > 参数 > 变量提升

7:对象

1
2
3
4
5
6
7
console.log([1,2,3] === [1,2,3]) //false 因为两个对象都是new出来的并不相同

var a = {
a:1
}
var b = a
console.log(a === b) //true 因为史诗同一个引用对象 因此相同

对象的key都是字符串类型

1
2
3
4
5
6
7
8
9
10
11
有趣的面试题
var a = {}
var b = {
key:'a'
}
var c = {
key:'c'
}
a[b] = '123' // a[obj obj] = '123'
a[c] = '456' // a[obj obj] = '456'
console.log(a[b]) //console.log(a[obj obj])

对象是如何查找某个属性? 对象是通过构造函数生成的

1
2
3
4
5
6
7
8
9
function Fun(){
this.a = 'fun'
}
Fun.prototype.a = 'fun原型'
let obj = new Fun()
obj.a = '对象本身'
obj.__proto__.a = '对象原型'
console.log(obj.a) // '对象本身'
先查找对象本身 => 构造函数的内部 => 对象的原型 => 构造函数的原型 => 对象上一层原型

8:作用域 + this指向 + 原型

Loading——

9:判断数组方法

使用场景:虚拟dom判断子节点是不是数组

1:isArray

2:instanceof [坑多,typeof更多 不建议用]

3:原型判断

4::isPrototypeOf()

5:constructor

1
2
3
4
5
6
let arr = [1,2,3]
console.log(Array.isArray(arr)) //true
console.log(arr instanceof Array) //true
console.log(Object.prototype.toString.call(arr).indexOf('Array') != -1) //8 [Object Array]
console.log(Array.prototypee.isPrototypeOf(arr))
console.log(arr.constructor.toString().indexOf('Array') > -1)

10:slice与splice

slice的作用,splice是否会改变原数组

1
2
3
4
5
6
7
8
//slice截取作用 参数可以写一个 代表从该参数位置开始截取到最后
let arr = [a,b,c,d]
let arr2 = arr.slice(1,3) //从索引1开始 截取到3之前一位 [b,c] 返回新数组

//splice 删除 ,插入,替换 会改变原数组
let arr2 = [a,b,c,d]
let arr3 = arr2.splice(1,1) // b 返回删除的元素数组 原本的arr2 [a,c,d]
let arr4 = arr2.splice(1,1,'你好') // 从1开始 删除一个元素 在原本位置插入你好

11:多维数组最大值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let arr  = [
[4,4,5],
[10,123,123],
[123123,12,323,123]
]
分别找到每个数组最大的值
输出[5,123,123123]

code:
function(arr){
let newArr = []
arr.forEach((iitem,index)=>{
newArr.push(Math.max(...item))
})
reurn newArr
}

12:字符串新增方法实现某些功能

给字符串定义一个方法addStart,当传入该方法一个字符串时,返回当前字符串+参数前缀

1
2
3
String.prototype.addStr = function(str){
return str + this
}

13:找出字符串出现最多次数字符和次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1:
var str = '111222333333444444444444'
var obj = {}
for(var i = 0; i < str.length; i++){
if(obj[str[i]]){
obj[str[i]]++
}else{
obj[str[i]] = 1
}
}
console.log(obj) // {a:b:c:d:}
///统计最大值
var max = 0
for(var k in obj){
if(max < obj.key){
max = obj.key
}
}
for(var key in obj){
if(mx == obj[key]){
console.log(obj[key]) // 最多次数的字符
console.log(max) //最次数
}
}

14:new操作符

1:创建一个空的对象

2:将空对象的原型指向构造函数原型

3:将空对作为构造函数上下文(改变this指向)

4:对构造函数有返回值的处理判断 如果这个构造函数返回基本类型 那么会忽略 如果是引用类型则会返回这个引用类型 new失效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Fo(){

}
console.log(new Fo()) //obj 创建一个空的对象
console.log(new Fo.__proto__ === Fo.prototype)
console.log()

实现一个相同的函数
function Fun(age,name){
this.age = age
this.name = name
}
function create(fn,..args){
//创建空对象
var obj = {}
//将空对象原型指向构造函数原型
Object.setPrototypeOf(obj,fn.prototype)
//改变this指向
var result = fn.apply(obj.args)
//最后处理
return result instanceof Object ? result : obj
}
function(create(Fun,18,'lisi'))

15:闭包

1:闭包是什么

一个函数加上到创建函数作用域的连接 闭包关闭了函数在自由变量

js中尽量不要写全局变量 因为系统并不知道什么时候会垃圾回收

2:闭包可以解决什么问题【优点】

内部函数可以访问到外部函数局部变量

3:闭包的缺点

变量会驻留在内存中 造成内存损耗问题

内存泄露是在ie的情况

解决方式手动清空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function a (){
var b = 10
return function(){
console.log(b)
}
}
a()() // a()执行完以后没有销毁 因此a()()能够打印出b

//优点
let lis = document.getElementsByTagName('li')
for(var i = 0; i < 3; i++){
lis[i].onclick = function(){
console.log(i) // 3
}
}
改造成闭包的形式
for(var i = 0; i < 3; i++){
function((i){
lis[i].onclick = function(){
console.log(i) // 3
}
lis[i] = null //手动清空
})(i)
}

16:原型链

17:js继承方式

18:call,apply,bind区别

19:sort背后原理

20:深拷贝与浅拷贝

21:本次存储localStorage/sessionStorage与cookie区别

未完待续……