前端面试比较好的回答

news2024/11/24 18:43:18

介绍一下Connection:keep-alive

什么是keep-alive

我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP协议为无连接的协议);

当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。

为什么要使用keep-alive

keep-alive技术的创建目的,能在多次HTTP之前重用同一个TCP连接,从而减少创建/关闭多个 TCP 连接的开销(包括响应时间、CPU 资源、减少拥堵等),参考如下示意图

客户端如何开启

在HTTP/1.0协议中,默认是关闭的,需要在http头加入"Connection: Keep-Alive”,才能启用Keep-Alive;

Connection: keep-alive

http 1.1中默认启用Keep-Alive,如果加入"Connection: close “,才关闭。

Connection: close

目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。

Promise.any

描述:只要 promises 中有一个fulfilled,就返回第一个fulfilledPromise实例的返回值。

实现

Promise.any = function(promises) {
    return new Promise((resolve, reject) => {
        if(Array.isArray(promises)) {
            if(promises.length === 0) return reject(new AggregateError("All promises were rejected"));
            let count = 0;
            promises.forEach((item, index) => {
                Promise.resolve(item).then(
                    value => resolve(value),
                    reason => {
                        count++;
                        if(count === promises.length) {
                            reject(new AggregateError("All promises were rejected"));
                        };
                    }
                );
            })
        }
        else return reject(new TypeError("Argument is not iterable"));
    });
}

代码输出结果

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
async1();
console.log('start')

输出结果如下:

async1 start
async2
start
async1 end

代码的执行过程如下:

  1. 首先执行函数中的同步代码async1 start,之后遇到了await,它会阻塞async1后面代码的执行,因此会先去执行async2中的同步代码async2,然后跳出async1
  2. 跳出async1函数后,执行同步代码start
  3. 在一轮宏任务全部执行完之后,再来执行await后面的内容async1 end

这里可以理解为await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中。

闭包产生的本质

当前环境中存在指向父级作用域的引用

代码输出结果

 var a=3;
 function c(){
    alert(a);
 }
 (function(){
  var a=4;
  c();
 })();

js中变量的作用域链与定义时的环境有关,与执行时无关。执行环境只会改变this、传递的参数、全局变量等

代码输出结果

Promise.resolve('1')
  .then(res => {
    console.log(res)
  })
  .finally(() => {
    console.log('finally')
  })
Promise.resolve('2')
  .finally(() => {
    console.log('finally2')
      return '我是finally2返回的值'
  })
  .then(res => {
    console.log('finally2后面的then函数', res)
  })

输出结果如下:

1
finally2
finally
finally2后面的then函数 2

.finally()一般用的很少,只要记住以下几点就可以了:

  • .finally()方法不管Promise对象最后的状态如何都会执行
  • .finally()方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是无法知道Promise最终的状态是resolved还是rejected
  • 它最终返回的默认会是一个上一次的Promise对象值,不过如果抛出的是一个异常则返回异常的Promise对象。
  • finally本质上是then方法的特例

.finally()的错误捕获:

Promise.resolve('1')
  .finally(() => {
    console.log('finally1')
    throw new Error('我是finally中抛出的异常')
  })
  .then(res => {
    console.log('finally后面的then函数', res)
  })
  .catch(err => {
    console.log('捕获错误', err)
  })

输出结果为:

'finally1'
'捕获错误' Error: 我是finally中抛出的异常

参考 前端进阶面试题详细解答

Promise.resolve

Promise.resolve = function(value) {
    // 1.如果 value 参数是一个 Promise 对象,则原封不动返回该对象
    if(value instanceof Promise) return value;
    // 2.如果 value 参数是一个具有 then 方法的对象,则将这个对象转为 Promise 对象,并立即执行它的then方法
    if(typeof value === "object" && 'then' in value) {
        return new Promise((resolve, reject) => {
           value.then(resolve, reject);
        });
    }
    // 3.否则返回一个新的 Promise 对象,状态为 fulfilled
    return new Promise(resolve => resolve(value));
}

JS 整数是怎么表示的?

  • 通过 Number 类型来表示,遵循 IEEE754 标准,通过 64 位来表示一个数字,(1 + 11 + 52),最大安全数字是 Math.pow(2, 53) - 1,对于 16 位十进制。(符号位 + 指数位 + 小数部分有效位)

vuex

vuex是一个专为vue.js应用程序开发的状态管理器,它采用集中式存储管理应用的所有组件的状态,并且以相
应的规则保证状态以一种可以预测的方式发生变化。

state: vuex使用单一状态树,用一个对象就包含来全部的应用层级状态

mutation: 更改vuex中state的状态的唯一方法就是提交mutation

action: action提交的是mutation,而不是直接变更状态,action可以包含任意异步操作

getter: 相当于vue中的computed计算属性

代码输出结果

var a, b
(function () {
   console.log(a);
   console.log(b);
   var a = (b = 3);
   console.log(a);
   console.log(b);   
})()
console.log(a);
console.log(b);

输出结果:

undefined 
undefined 
3 
3 
undefined 
3

这个题目和上面题目考察的知识点类似,b赋值为3,b此时是一个全局变量,而将3赋值给a,a是一个局部变量,所以最后打印的时候,a仍旧是undefined。

JS 隐式转换,显示转换

一般非基础类型进行转换时会先调用 valueOf,如果 valueOf 无法返回基本类型值,就会调用 toString

字符串和数字

  • “+” 操作符,如果有一个为字符串,那么都转化到字符串然后执行字符串拼接
  • “-” 操作符,转换为数字,相减 (-a, a * 1 a/1) 都能进行隐式强制类型转换
[] + {}{} + []

布尔值到数字

  • 1 + true = 2
  • 1 + false = 1

转换为布尔值

  • for 中第二个
  • while
  • if
  • 三元表达式
  • || (逻辑或) && (逻辑与)左边的操作数

符号

  • 不能被转换为数字
  • 能被转换为布尔值(都是 true)
  • 可以被转换成字符串 “Symbol(cool)”

宽松相等和严格相等

宽松相等允许进行强制类型转换,而严格相等不允许

字符串与数字

转换为数字然后比较

其他类型与布尔类型

  • 先把布尔类型转换为数字,然后继续进行比较

对象与非对象

  • 执行对象的 ToPrimitive(对象)然后继续进行比较

假值列表

  • undefined
  • null
  • false
  • +0, -0, NaN
  • “”

setInterval 模拟 setTimeout

描述:使用setInterval模拟实现setTimeout的功能。

思路setTimeout的特性是在指定的时间内只执行一次,我们只要在setInterval内部执行 callback 之后,把定时器关掉即可。

实现

const mySetTimeout = (fn, time) => {
    let timer = null;
    timer = setInterval(() => {
        // 关闭定时器,保证只执行一次fn,也就达到了setTimeout的效果了
        clearInterval(timer);
        fn();
    }, time);
    // 返回用于关闭定时器的方法
    return () => clearInterval(timer);
}

// 测试
const cancel = mySetTimeout(() => {
    console.log(1);
}, 1000);  
// 一秒后打印 1

js脚本加载问题,async、defer问题

  • 如果依赖其他脚本和 DOM 结果,使用 defer
  • 如果与 DOM 和其他脚本依赖不强时,使用 async

什么是作用域?

ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找

原型

JavaScript中的对象都有一个特殊的 prototype 内置属性,其实就是对其他对象的引用
几乎所有的对象在创建时 prototype 属性都会被赋予一个非空的值,我们可以把这个属性当作一个备用的仓库
当试图引用对象的属性时会出发get操作,第一步时检查对象本身是否有这个属性,如果有就使用它,没有就去原型中查找。一层层向上直到Object.prototype顶层

基于原型扩展描述一下原型链,什么是原型链,原型的继承,ES5ES6继承与不同点。

说一下slice splice split 的区别?

// slice(start,[end])
// slice(start,[end])方法:该方法是对数组进行部分截取,该方法返回一个新数组
// 参数start是截取的开始数组索引,end参数等于你要取的最后一个字符的位置值加上1(可选)。
// 包含了源函数从start到 end 所指定的元素,但是不包括end元素,比如a.slice(0,3);
// 如果出现负数就把负数与长度相加后再划分。
// slice中的负数的绝对值若大于数组长度就会显示所有数组
// 若参数只有一个,并且参数大于length,则为空。
// 如果结束位置小于起始位置,则返回空数组
// 返回的个数是end-start的个数
// 不会改变原数组
var arr = [1,2,3,4,5,6]
/*console.log(arr.slice(3))//[4,5,6] 从下标为0的到3,截取3之后的数console.log(arr.slice(0,3))//[1,2,3] 从下标为0的地方截取到下标为3之前的数console.log(arr.slice(0,-2))//[1,2,3,4]console.log(arr.slice(-4,4))//[3,4]console.log(arr.slice(-7))//[1,2,3,4,5,6]console.log(arr.slice(-3,-3))// []console.log(arr.slice(8))//[]*/
// 个人总结:slice的参数如果是正数就从左往右数,如果是负数的话就从右往左边数,
// 截取的数组与数的方向一致,如果是2个参数则截取的是数的交集,没有交集则返回空数组 
// ps:slice也可以切割字符串,用法和数组一样,但要注意空格也算字符

// splice(start,deletecount,item)
// start:起始位置
// deletecount:删除位数
// item:替换的item
// 返回值为被删除的字符串
// 如果有额外的参数,那么item会插入到被移除元素的位置上。
// splice:移除,splice方法从array中移除一个或多个数组,并用新的item替换它们。
//举一个简单的例子 
var a=['a','b','c']; 
var b=a.splice(1,1,'e','f'); 
 console.log(a) //['a', 'e', 'f', 'c']
 console.log(b) //['b']

 var a = [1, 2, 3, 4, 5, 6];
//console.log("被删除的为:",a.splice(1, 1, 8, 9)); //被删除的为:2
// console.log("a数组元素:",a); //1,8,9,3,4,5,6

// console.log("被删除的为:", a.splice(0, 2)); //被删除的为:1,2
// console.log("a数组元素:", a) //3,4,5,6
console.log("被删除的为:", a.splice(1, 0, 2, 2)) //插入 第二个数为0,表示删除0个  
console.log("a数组元素:", a) //1,2,2,2,3,4,5,6

// split(字符串)
// string.split(separator,limit):split方法把这个string分割成片段来创建一个字符串数组。
// 可选参数limit可以限制被分割的片段数量。
// separator参数可以是一个字符串或一个正则表达式。
// 如果separator是一个空字符,会返回一个单字符的数组,不会改变原数组。
var a="0123456";  
var b=a.split("",3);  
console.log(b);//b=["0","1","2"]
// 注意:String.split() 执行的操作与 Array.join 执行的操作是相反的。

代码输出结果

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

输出结果如下:

1
7
6
8
2
4
3
5
9
11
10
12

(1)第一轮事件循环流程分析如下:

  • 整体script作为第一个宏任务进入主线程,遇到console.log,输出1。
  • 遇到setTimeout,其回调函数被分发到宏任务Event Queue中。暂且记为setTimeout1
  • 遇到process.nextTick(),其回调函数被分发到微任务Event Queue中。记为process1
  • 遇到Promisenew Promise直接执行,输出7。then被分发到微任务Event Queue中。记为then1
  • 又遇到了setTimeout,其回调函数被分发到宏任务Event Queue中,记为setTimeout2
宏任务Event Queue微任务Event Queue
setTimeout1process1
setTimeout2then1

上表是第一轮事件循环宏任务结束时各Event Queue的情况,此时已经输出了1和7。发现了process1then1两个微任务:

  • 执行process1,输出6。
  • 执行then1,输出8。

第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。

(2)第二轮时间循环从**setTimeout1**宏任务开始:

  • 首先输出2。接下来遇到了process.nextTick(),同样将其分发到微任务Event Queue中,记为process2
  • new Promise立即执行输出4,then也分发到微任务Event Queue中,记为then2
宏任务Event Queue微任务Event Queue
setTimeout2process2
then2

第二轮事件循环宏任务结束,发现有process2then2两个微任务可以执行:

  • 输出3。
  • 输出5。

第二轮事件循环结束,第二轮输出2,4,3,5。

(3)第三轮事件循环开始,此时只剩setTimeout2了,执行。

  • 直接输出9。
  • process.nextTick()分发到微任务Event Queue中。记为process3
  • 直接执行new Promise,输出11。
  • then分发到微任务Event Queue中,记为then3
宏任务Event Queue微任务Event Queue
process3
then3

第三轮事件循环宏任务执行结束,执行两个微任务process3then3

  • 输出10。
  • 输出12。

第三轮事件循环结束,第三轮输出9,11,10,12。

整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。

代码输出结果

function Foo(){
    Foo.a = function(){
        console.log(1);
    }
    this.a = function(){
        console.log(2)
    }
}

Foo.prototype.a = function(){
    console.log(3);
}

Foo.a = function(){
    console.log(4);
}

Foo.a();
let obj = new Foo();
obj.a();
Foo.a();

输出结果:4 2 1

解析:

  1. Foo.a() 这个是调用 Foo 函数的静态方法 a,虽然 Foo 中有优先级更高的属性方法 a,但 Foo 此时没有被调用,所以此时输出 Foo 的静态方法 a 的结果:4
  2. let obj = new Foo(); 使用了 new 方法调用了函数,返回了函数实例对象,此时 Foo 函数内部的属性方法初始化,原型链建立。
  3. obj.a() ; 调用 obj 实例上的方法 a,该实例上目前有两个 a 方法:一个是内部属性方法,另一个是原型上的方法。当这两者都存在时,首先查找 ownProperty ,如果没有才去原型链上找,所以调用实例上的 a 输出:2
  4. Foo.a() ; 根据第2步可知 Foo 函数内部的属性方法已初始化,覆盖了同名的静态方法,所以输出:1

说一下HTTP和HTTPS协议的区别?

1HTTPS协议需要CA证书,费用较高;HTTP协议不需要
2HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
3、使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
4HTTP协议连接很简单,是无状态的;HTTPS协议是具有SSLHTTP协议构建的可进行加密传输、身份认证的网络协议,HTTP更加安全

script标签中defer和async的区别

如果没有defer或async属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。

defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,其区别如下:

  • 执行顺序: 多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行;
  • 脚本是否并行执行:async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行;defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/101236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【笔记】canvas 绘制足球 —— 第一步 画个球体

文章目录一、球体分析二、足球结构分析三、canvas常用API四、画个球体1.初始化2.代码五、加上足球的皮肤一、球体分析 先上两张图 球坐标转直角坐标 xρsin(φ)cos(θ)x \rho \times sin(\varphi) \times cos(\theta) xρsin(φ)cos(θ) yρsin(φ)sin(θ)y \rho \times si…

柴油,光伏模块,风力涡轮机,电池和水力抽水蓄能组成的混合隔离微电网的设计(Matlab实现)

目录 0 引言 1 概述 2 HYMOD 软件操作 2.1 设计的三个阶段 3 HYMOD 软件架构 4 系统和元件的可靠性 5 微电网设计示例 6 Matlab代码与结论 7 操作指南 7.1 概述 7.2 操作 7.3 软件具体操作 0 引言 本文介绍了混合微电网优化设计 (Hymod) 软件。该软件具有最先进…

Redis发布和订阅

Redis发布和订阅1.什么是发布和订阅2.Redis命令演示发布订阅1.什么是发布和订阅 Redis发布订阅(pub/sub)是一种消息通信模式:发布者(pub)发送消息,订阅者(sub)接收消息。 Redis客户端可以订阅任意数量的频道。 2.Redis命令演示发布订阅 打开两个终端 终…

python教程二十 输入和输出

输出格式美化 Python两种输出值的方式: 表达式语句和 print() 函数。 第三种方式是使用文件对象的 write() 方法,标准输出文件可以用 sys.stdout 引用。 如果你希望输出的形式更加多样,可以使用 str.format() 函数来格式化输出值。 如果你希望将输出…

记录在苹果mac os系统上使用51单片机仿真软件Proteus

目录 1.安装Wineskin shell 指令 2.安装Wrapper 点击update ​​​​​​​ 1.安装Wineskin 首先我们需要安装一个程序: 可以将在Windows系统上才能运行exe文件打包为mac系统可执行的文件。 shell 指令 brew install --no-quarantine gcenx/wine/unofficial…

气体在线监测仪——排水管井内的有害气体监测

一、产品概述 气体在线监测仪内部采用模块化设计,可对雨污水管井内的有害气体进行在线监测,设备采用高精度、高分辨率的原装进口气体传感器,具有体积小、重量轻、设计简洁、高性价比、多参数高集成、安装方便等特点。 气体在线监测仪广泛应…

Java IO

目录 一、File 类 二、RandomAccessFile 三、流类 四、字节流 4.1 、InputStream 4.2、OutputStream 五、字符流 5.1、Reader 5.2、Writer 六、管道流 七、ByteArrayInputStream 和 ByteArrayOutputStream 八、System.out 和 System.in 九、打印流 十、DataOutp…

【Leetcode】单值二叉树、 相同的树、对称二叉树、另一颗树的子树、二叉树遍历、二叉树的前序遍历

文章目录OJ链接单值二叉树相同的树对称二叉树另一颗树的子树二叉树遍历二叉树的前序遍历OJ链接 1、【单值二叉树】OJ链接 2、【相同的树】OJ链接 3、【对称二叉树】OJ链接 4、【另一棵树的子树】OJ链接 5、【二叉树遍历】OJ链接 6、【二叉树的前序遍历】OJ链接 单值二叉树 >…

R语言用线性模型进行臭氧预测: 加权泊松回归,普通最小二乘,加权负二项式模型,多重插补缺失值

最近我们被客户要求撰写关于线性模型的研究报告,包括一些图形和统计输出。在这篇文章中,我将从一个基本的线性模型开始,然后尝试找到一个更合适的线性模型。 数据预处理 由于空气质量数据集包含一些缺失值,因此我们将在开始拟合…

driftingblues3靶机(auth.log日志、命令执行)

环境准备 靶机链接:百度网盘 请输入提取码 提取码:yc07 虚拟机网络链接模式:桥接模式 攻击机系统:kali linux 2021.1 信息收集 1.探测目标靶机开放端口和服务情况 2.用dirsearch扫描出目录 dirsearch -u 192.168.1.101 漏洞…

【Python】ValueError: Grouper for ‘Code‘ not 1-dimensional

目录:ValueError: Grouper for Code not 1-dimensional解决一、问题描述二、问题分析2.1 构建的DataFrame两列列名一样2.2 情况2三、问题解决一、问题描述 在我进行pandas的groupby分组的时候,我们的数据集如下: 但是在分组时,出…

Oracle sql性能优化案例

v$sql 表字段说明: sql_id:唯一性标识; sql_fulltext:SQL执行内容; elapsed_time:消逝时间,即自然耗费的时间,单位是微妙,10的-6次方秒; cpu_time&#…

手机也可以轻松码代码!两款手机端代码最佳神器Pydroid和Pythonista!

Pyroid是一款支持Android系统的移动代码编译器。 Python 3可以说是Android上一个易于使用且功能强大的Python 3 IDE,它可以帮助您在Android上使用Python、Jupyter笔记本等。 安装 我们可以从应用程序商店下载并安装。安装完成后,需要在第一次打开Python…

我用python生成了一亿棵不同的圣诞树 | 使用Python代码自动生成圣诞树轮廓

圣诞将至,这次来试试用Python代码过圣诞节把~挑战生成一亿棵圣诞树。 文章目录前言一、为什么能生成一亿棵圣诞树?二、怎么根据圣诞树图片生成对应的圣诞树轮廓1.读取圣诞树图片2.二值化圣诞树图片3.提取圣诞树图片轮廓4.显示圣诞树轮廓总结前言 圣诞将…

数据结构作业——第十六周--排序

1 . 单选题 简单 5分 对整数序列(8,9,10,4,5,6,20,1,2)进行递增排序,采用每趟冒出一个最小元素的冒泡排序算法,需要进行的趟数是____…

重新定义“创新”,戴森以发明家精神引领科技突破

自创立以来,戴森坚持精益工程、寻求颠覆性解决方案,现已成为行业领先的全球科技公司。而在前沿产品背后,其创新理念、发明家精神为戴森一系列不可复制的核心科技和突破性产品奠定了基石。 2022年12月18日,第二届戴森科技节在深圳启…

【pyclipper+增材CAM】轮廓偏置

在增材打印CAM中,我们需要在切片得到的每层轮廓中规划生成打印路径。传统的三轴3D打印的常见填充方式有:轮廓平行填充和方向平行填充。其中轮廓平行填充主要是通过轮廓偏置实现的。 pyclipper安装使用 Python下安装pyclipper库,命令行输入p…

ZigBee环境配置与工程创建 -- IAR for 8051 8.10

IAR8.10版本的安装相对于10.30.1版本的安装要简单的过,同样是做ZigBee的裸机项目开发工具,10版本之前都是旧版的操作界面,如果后期运行协议栈的话可以适配Z-Stask2.5.1a版本 文章目录1. IAR环境安装2.IAR for 8051工程创建3.工程配置4.工程编…

星火计划学习笔记——Apollo决策规划技术详解及实现(以交通灯场景检测为例)

文章目录1. Apollo决策技术详解1.1 Planing模块运行机制1.2 Apollo决策功能的设计与实现1.2.1参考路径 Reference Line1.2.2 交规决策 Traffic rule process1.2.3 路径决策 Path decider1.2.4 速度决策 Speed decider1.2.5 Planing模块运行流程1.2.6 场景 Scenarios2. 交规决策…

AW EC2实例

Hello大家好,我们今天的课时内容是EC2。 EC2大家应该都是比较熟悉了,相信绝大部分人应该都用过。这部分涉及到的内容肯定是比较多的,希望大家对于一些基础的概念已经有所了解了,这个课时我和大家一起总结一下。 当然&#xff0c…