js考题-进阶篇(1)

2024-02-20 11:42:15发布
99

1. 简述下js的事件循环机制

由于js是单线程语言,同一个时间点只能执行一个任务。那如果同一个时间点,有多个任务,那到底谁先执行,谁后执行?
为了解决这个问题,js把任务分为3种,同步任务、宏任务、微任务。它们的优先级是:同步任务 > 微任务 > 宏任务
比如,此时有:2个同步任务,1个微任务,1个宏任务,js的执行流程是这样的 :
1. 从同步任务队列中获取任务,然后放到主线程执行;
2. 执行完毕后,再查看下同步任务队列是否还有任务,发现还有一个同步任务,执行步骤1;
3. 当同步任务队列没有了任务时,此时主线程会去微任务队列查看下是否有任务,发现有1个微任务,取出放到主线程执行;
4. 当微任务队列没有任务时,此时主线程会去宏任务队列查看下是否有宏任务,发现有1个宏任务,取出放到主线程执行;
5. 当所有任务队列的任务都被执行完毕时,此时已经没有任务了,则主线程会被休眠。直到下次任务队列中有任务时,则会被唤醒;

微任务:Promise.then、catch、finally、async/await
宏任务:setTimeout、setInterval、Dom事件、ajax事件


2. 网页的生成过程

1. HTML代码转化成DOM
2. CSS代码转化成CSSOM (CSS Object Model)
3. 结合DOM和CSSOM,生成一棵渲染树(渲染树包含每个节点的视觉信息。比如节点的宽、高、坐标、颜色、字体大小等。这里的节点指的是html标签)
4. 根据视觉信息,生成布局
5. 根据视觉信息,布局绘制(paint)在屏幕上


3. 当在浏览器上输入一个网址,其内部发生了什么?

当前URL是否存在缓存,若有缓存则直接使用缓存数据,否则 :
1、DNS解析 (DNS解析URL对应的IP) 
2、TCP连接 
3、HTTP请求
4、服务器处理请求 
5、浏览器接受HTTP响应
6、页面渲染
7、TCP断开连接


4. 作用域相关的知识

作用域的优先级:声明变量 > 声明普通函数 > 参数 > 变量提升

请参考这里: http://111.230.246.226:8080/article/336


5. JS对象相关知识

对象查找属性的优先级:先在对象本身找 ->  构造函数中找 -> 对象原型中找 -> 构造函数原型中找 -> 对象上一层原型中找

请参考这里: http://111.230.246.226:8080/article/337


6. new操作符具体做了什么?

1. 创建了一个空的对象
2. 将空对象的原型,指向与构造函数的原型
3. 改变this指向
4. 构造函数的返回值做处理判断,如果返回的是基本数据类型,则忽略返回值。如果是引用数据类型,则返回

验证过程

第1步

function Fun() {

}
console.log(new Fun())

第2步

function Fun() {

}
console.log(new Fun().__proto__ === Fun.prototype) // 输出true

第3步

function Fun() {
    console.log(this)  // 输出window
    this.name = 'lcf'
}
console.log( Fun() ) // 输出undefined

new了之后

function Fun() {
    console.log(this)  // 输出对象
    this.name = 'lcf'
}
console.log( new Fun() ) // 输出对象

第4步

function Fun() { 
    this.name = 'lcf'
    return 123
}
console.log( new Fun() ) // 输出对象。即使Fun返回的是123,但是这里的规则是如果Fun的return是引用类型,则按return的返回,否则忽略


7. 什么是闭包?优缺点是什么?具体可以用在什么地方?

什么是闭包?

函数b在函数a里面,并且函数b有用到函数a的变量,就叫闭包。如 :
function a() { // 函数a
    var num = 10;
    return function () { // 函数b
        console.log(num); // 用到函数a的变量
    }
}
var fun = a();
fun();

优缺点是什么?
优点:
1. 变量不会污染全局;
缺点:
1. 闭包较多的时候,会消耗内存,导致页面的性能下降,在IE浏览器中才会导致内存泄漏

具体可以用在什么地方?
防抖、节流、函数嵌套函数避免全局污染的时候

防抖和节流可以参考这篇文章: http://111.230.246.226:8080/article/261


8. 原型链

1.原型可以解决什么问题?
对象共享属性和共享方法

2.谁有原型?
函数拥有:prototype
对象拥有: __proto__

3.对象查找属性或者方法的顺序
先在对象本身找 -> 构造函数中找 -> 对象的原型找 -> 构造函数的原型找 -> 当前对象的__proto__找 -> 直到找到的值为null位置
上面的查找过程就叫原型链

原型链查找例子(查找顺序按数字大小进行)

var Person = function() {
this.name = 2;
}
Person.prototype.name = 4;

var p = new Person();
p.name = 1;
p.__proto__.name = 3;

console.log(p.name)

作者为什么要用原型来实现属性和方法的共享,可以参考这篇文章: https://blog.csdn.net/QQ408896436/article/details/79452570


9. js怎么实现继承?

请参考这篇文章: http://111.230.246.226:8080/article/338


10. call、apply、bind共同点是什么?不同点是什么?

这个视频讲解的很好,地址: https://www.bilibili.com/video/BV1Ug411F7fZ/?spm_id_from=333.337.search-card.all.click&vd_source=1c1f36c373bf5f183bb470989dc9a264

共同点
可以改变this的指向

不同点
1. call的第二个参数开始,是一个一个参数
2. apply的第二个参数,是一个数组
3. bind返回的是一个函数

不同点1例子

var tom = {
    quantity: 50, // 手机电量
    charge: function (q1, q2) { // 充电宝
        this.quantity = q1 + q2;
    }
}

var marry = {
    quantity: 0, // 手机电量
}

tom.charge.call(marry, 50, 20) // marry没有充电宝,拿tom的充电宝来用。第二个参数开始,是一个一个参数传递
console.log(marry.quantity) // 输出70

不同点2例子

var tom = {
    quantity: 50,
    charge: function (q1, q2) {
        this.quantity = q1 + q2;
    }
}

var marry = {
    quantity: 0,
}

tom.charge.apply(marry, [50, 20])
console.log(marry.quantity) // 输出70

不同点3例子

var tom = {
    quantity: 50,
    charge: function (q1, q2) {
        this.quantity = q1 + q2;
    }
}

var marry = {
    quantity: 0,
}

var fun = tom.charge.bind(marry);
fun(20,50)
console.log(marry.quantity)


11. 浅拷贝和深拷贝

请参考这篇文章: https://blog.csdn.net/QQ408896436/article/details/79343481


12. 前端性能优化的方法有哪些?

1.加载优化(减少http请求数),比如把多个小图片合并成雪碧图
2.合并压缩css样式表和js脚本
3.使用外链的css和js,第二次访问不会请求,从缓存处拿
4.使用CDN外链第三方库,减少项目包过大
5.服务器开启Gzip压缩
6.复杂动画效果用transform:translate 代替 position  left、right...以此来尽量减少回流和重绘
7.使用事件委托    
8.使用骨架屏


13. http的状态码分类

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

常见的状态码

状态码含义
200请求成
301表示页面/资源永久性的转移到另一个位置上
302表示页面/资源临时性的转移到另一个位置上
304使用缓存资源
401身份验证失败,一般是缺少token,获取token是错误的
403服务器拒绝访问,权限不足
404服务器无法找到被请求页面
500服务器错误
502网关错误


14. http和https区别

区别:

1、http传输数据是明文传输,不安全。https则是采用ssl加密传输数据,比http安全得多。
(https传输数据过程大概是服务器会准备2把钥匙和一个箱子,把一把钥匙和一个箱子发给用户,用户传递数据的时候,把数据放到箱子中,然后用钥匙锁上,在传递给服务器。然后服务器则用自己的钥匙把箱子打开)

2、端口不一样。http是80,https是443。
(这个只是默认端口不一样,实际上端口是可以改的)

3、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。


15. http报文相关

HTTP请求:请求行、请求头、空行、请求体(只有post请求才有请求体)
HTTP响应:响应行、响应头、空行、响应体

请求行
1. 请求方式(get还是post)
2. 请求路径
3. http协议版本

请求头
1. 主机地址
2. 端口号
3. 接受的数据类型

请求体
只有post请求才有请求体,就是请求接口时传递的参数

---------------------------------------------

响应行
1. 状态码
2. 状态描述
3. http协议版本

响应头
1. 服务器名称
2. 内容类型Content-Type
3. 响应时间

响应体
接口返回的数据

更多信息请参考这篇文章: https://zhuanlan.zhihu.com/p/464834232


16. 作用域和作用域链

作用域 :全局作用域、函数作用域、块级作用域
作用域链 :查找某个属性时,先在块级作用域查找,如果没有,则在函数作用域内查找,如果还没有,则到全局作用域查找

例子
let num = 1;

function fun() {
    let num = 2;
    if (true) {
        let num = 3;
    }
    console.log(num) // 2
}

fun()


17. 内存溢出和内存泄漏的区别

内存泄露:该回收的垃圾对象没有被回收,发生了内存泄露,垃圾对象越堆越多,可用内存越来越少,若可用内存无法存放新的垃圾对象,就导致内存溢出。
内存溢出:当前创建的对象的大小大于可用的内存容量大小,发生内存溢出。(比如一个只能装500毫升的水的杯子,现在装1000毫升的水,就会溢出)
内存泄露会导致内存溢出


18. 导致内存泄漏的一些场景

1、意外的全局变量泄露    
2、console.log  也是全局变量
3、闭包泄露  赋值给全局变量后,对函数的引用一直存在


19. 判断一个变量是不是空对象

Reflect.ownKeys(obj).lenght === 0

该方法比较准确,如果一个对象是用Symbol作为key的时候,这种判断比JSON.stringify准确


20. 箭头函数与普通函数的区别

1. this指向的问题,箭头函数中的this指向定义时候,外层第一个普通函数的this,并且不可修改(call、apply、bind)
2. 箭头函数不能当做构造函数
3. 箭头函数没有prototype
4. 箭头函数没有arguments


21. promise相关

请参考这篇文章: http://111.230.246.226:8080/article/305


22. find和filter的区别(都不会对原数组的内容进行改变)

区别一:返回的内容不同
    filter 返回的是新数组
    find   返回的是具体的内容

区别二:
    filter 返回整体(每一个匹配到的都返回)
    find   匹配到第一个即返回

例子

var arr = [1,2,3,4,5,6,7,8,9]

var res1 = arr.filter(function(num){
    return num > 5
});
console.log(res1) // 输出 [6, 7, 8, 9]

var res2 = arr.find(function(num){
    return num > 5
});
console.log(res2) // 输出6


23.  some和every的区别

some
如果有一项匹配则返回true

every
全部匹配才返回true

例子

var arr = [1,2,3,4,5,6,7,8,9]

var res1 = arr.some(function(num){
    return num > 5
});
console.log(res1) // true

var res2 = arr.every(function(num){
    return num > 5
});
console.log(res2) // false