1. 我是皮皮虾首页
  2. 编程开发
  3. 前端

web前端面试题

1.宏任务、微任务与EventLoop

微任务:promise、process.nextTick、MutationObserver

宏任务:setTimeOut、setInterval、I/O、script

同一次事件循环中,微任务永远在宏任务之前执行。每次执行宏任务结束之后都会检查是否有可执行的微任务,有的话执行所有微任务,否则开始新的宏任务。

执行顺序:首先执行script下的任务,遇到同步任务直接执行。遇到宏任务则将其放入宏任务【队列】,遇到微任务则放入微任务【队列】,同步任务执行之后再依次执行微任务队列,最后依次执行宏任务队列,每个宏任务队列产生的微任务都要全部一次执行完才进入下一个宏任务的执行,直到结束。

一旦遇到await就立刻让出线程,阻塞后面的代码,等候之后对于await来说分两种情况:

1.promise对象:暂停执行await后面的代码,先执行async外面的同步代码,等着Promise对象fulfilled,然后把resolve的参数作为await表达式的运算结果

2.非promise对象:同上,外面的同步代码执行完毕后,再回到async内部,把promise的东西作为await表达式的结果

2.ESC执行环境栈

执行栈既是函数在执行时存储调用过程的栈,同样的,采取调用形式进行队列,先进后出的方式

function foo(i) { if (i < 0) return; console.log(‘begin:’+ i); foo(i – 1); console.log(‘end:’ + i); } foo(2); // 输出:// begin:2// begin:1// begin:0// end:0// end:1// end:2**`

3.如何判断一个对象是不是数组类型

1.从原型入手,Array.prototype.isPrototypeOf(obj),判断是否在obj的原型链中

2.也可以从构造函数入手,obj instanceof Array(typeof是只会返回基本类型)

3.typeof arr == “object” && arr.constructor == Array; //先判断是对象再进一步判断

4.根据对象的class属性(类属性),跨原型链调用toString()方法。Object.prototype.toString.call([]);

5.Array.isArray()方法

4.请求头包含的内容

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 //浏览器支持的请求类型

Accept-Encoding: gzip, deflate, sdch //浏览器能处理的压缩代码

Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 //浏览器当前设置语言

Connection: keep-alive    // 连接类型,持续连接

Content-Length: 29 //请求参数长度(post新增)

Content-Type: application/json;charset=UTF-8 //请求类型

Cookie

Host: fhs.fdsfj.com // 请求的地址域名和端口,不包括协议

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/58.0.3029.96 Safari/537.36 //浏览器的用户代理信息

Upgrade-Insecure-Requests:1 // http 自动升级到https,防止跨域问题但是域名端口都不同的不会提升

Origin: http://www.study.com //请求来源地址,包括协议

5.Javascript有哪几种方法定义函数

1.函数表达式;var func = function(arg0, arg1, … argN) { statements };

2.function声明;function functionName(arg0, arg1, … argN) { statements }

3.function构造函数;var function_name = new Function(arg1, arg2, …, argN, function_body);

4.ES6箭头函数

6.TCP/IP协议的三次握手和四次挥手

TCP/IP协议分层:应用层、运输层、网络层、网络接口层

6个标志域的各个选项功能:

1.URG:紧急标志。紧急标志为”1″表明该位有效。

2.ACK:确认标志。表明确认编号栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。

3.PSH:推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理。在处理Telnet或rlogin等交互模式的连接时,该标志总是置位的。

4.RST:复位标志。用于复位相应的TCP连接。

5.SYN:同步标志。表明同步序列编号栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。

6.FIN:结束标志。

TCP三次握手,即建立TCP连接

第一次握手:客户端把标志位SYN置为1,随机产生一个值seq=j,并将该数据包发送给服务端。客户端进入SYN_SENT状态,等待服务端确认

第二次握手:服务端收到数据包后通过SYN=1可以确定客户端想建立连接。于是把SYN和ACK标志位置为1,然后ack=j+1,再随机产生一个seq=k,将数据包发给客户端。服务端进入SYN_RECV状态

第三次握手:客户端收到数据包确认ack是否为j+1;把ACK标志位置为1,并且ack=k+1将数据包发给服务端,服务端检查数据包ack是否为k+1,ACK标志位是否为1,确认即建立连接成功,进入establish状态

TCP四次挥手,即终止TCP连接

第一次挥手:客户端发送FIN标志给服务端,进入FIN_WAIT_1状态

第二次挥手:服务端收到后发送一个ACK给客户端。确认序号为收到序号+1,服务端进入CLOSE_WAIT状态

第三次挥手:服务端发送FIN给客户端,用来关闭数据传送。进入LAST_ACK状态

第四次挥手:客户端收到FIN后,将ACK置为1,并且确认序号为收到序号+1,服务端进入到CLOSED状态

7.JS中new操作符原理

var obj = new A();

1.创建一个空对象obj;

2.将A的原型链赋给对象的_proto _ obj.proto = A.prototype;

3.构造函数对象的this指针指向这个对象。A.call(obj)

8.JS中的垃圾回收机制

必要性:因为每次创建字符串、数组、对象时都需要动态为他们分配内存来存储,一旦分配都要释放这些内存以便下次在使用,否则会导致内存耗尽系统崩溃。

垃圾回收方式:标记清除、计数引用

1.标记清除:每个变量进入环境的时候会标记为‘进入环境’,离开环境的时候释放内存。垃圾回收器在运行的时候把标记的变量以及变量引用的变量都删除,回收内存。

2.计数引用:当声明了一个变量并且用一个引用类型的值赋给它,那么这个变量的引用次数为1,当包含了对这个值的引用又取了其他值,则引用次数-1。当引用次数为0时回收改变量。缺点:存在内存泄露。比如对象通过各自的属性相互引用的话,就不会有垃圾回收的过程。

9.类的创建和继承

// 定义一个类

function Animal(name){

// 类的属性

this.name = name||’panda’;

// 实例方法

this.sleep = function(){

console.log(this.name+’正在睡觉’)

}

}

// 原型方法

Animal.prototype.eat = function(thing){

console.log(this.name+’正在吃’+thing)

}

Animal.prototype.age = ’18’;

// 原型链继承

function dog(){}

dog.prototype = new Animal();

var dogs = new dog();

// 基于原型链的继承,既是父类的实例也是子类的实例,缺点是无法实现多继承

// 构造函数继承—使用父类的构造函数来增强子类实例,等于复制父类的实例属性给子类 。缺点是可以实现多继承,但是不能继承原型链上的属性和方法

function bird(name){

Animal.call(this);

this.name = name||’cuicy’;

this.sing = function(){

console.log(this.name+’ is singing!’)

}

}

var birds = new bird();

//

// 实例继承(为父类实例添加新特性,作为子类实例返回)

// 拷贝继承(拷贝父类元素上的属性和方法)

// 组合继承(构造继承+原型链继承),继承父类的属性并保留传参的优点,通过父类实例作为子类原型,实现函数复用,缺点是调用了两次父类构造函数,生成了两份实例

function cat(name){

Animal.call(this);

this.name = name||’tom’

}

cat.prototype = new Animal();

//construtor属性返回对创建此对象的数组函数的引用

cat.prototype.constructor = cat;

var cats = new cat();

// 寄生组合继承-通过寄生方式,砍掉父类的实例属性,在调用两次父类的构造的时候,就不会初始化两份实例属性方法,较为推荐

function snake(){

Animal.call(this);

this.name = ‘snake’;

}

(function(){

// 创建一个没有实例方法的类

var Super =function(){};

Super.prototype = Animal.prototype;

snake.prototype = new Super()

})();

var snakes = new snake();

10.事件流

描述的是指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。包含三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

事件处理程序:1.HTML事件处理程序;2.DOM0级事件处理程序;3.DOM2级事件处理程序;4.IE事件处理程序;5.跨浏览器的事件处理程序

11.eval的作用—–将对应的字符串解析成js执行
12.websocket的实现和应用

websocket是HTML5的协议,支持持久连接。目的是在客户端和服务端之间建立一个不受限的双向通信的通道。服务器可以在任意时刻发送消息给浏览器。

请求格式如下:

GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
  1. GET请求的地址不是类似/path/,而是以ws://开头的地址;
  2. 请求头Upgrade: websocketConnection: Upgrade表示这个连接将要被转换为WebSocket连接;
  3. Sec-WebSocket-Key是用于标识这个连接,并非用于加密数据;
  4. Sec-WebSocket-Version指定了WebSocket的协议版本。如果服务器接受该请求则返回如下相应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string

为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?实际上HTTP协议是建立在TCP协议之上的,TCP协议本身就实现了全双工通信,但是HTTP协议的请求-应答机制限制了全双工通信。WebSocket连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用HTTP协议了,直接互相发数据吧。

13.类数组对象:arguments

是函数运行时的实参列表。arguments与形参是一一映射的。可以用arguments[n]获取参数,可以用arguments.length直接获取实参个数。属性callee装了当前正在运行的函数。可以用来实现递归(严格模式中被禁止使用)。ES6的rest参数

14.数组的扩展

1.扩展运算符。将一个数组转为用逗号分隔的参数序列。

应用:克隆数组:const a1=[…a2] = a1;合并数组:[…arr1,…arr2,…arr3];与解构赋值结合,用于生成数组:const[first,…rest] = [1,2,3,4,5],只能放在参数最后一位;字符串转为数组:[…’hello’];定义了遍历器(Iterator)接口的对象用扩展运算符转为真正的数组;map和set结构,generator函数

2.Array.from()。将两类对象转为真正的数组:类数组(array-like)对象和可遍历(iterable)对象。包括Set和Map

3.Array.of()。用于将一组值转换为数组。可用模拟实现 function Arrayof(){ return [].slice.call(arguments)}

4.copyWithin()。从指定位置的成员复制到其他位置(会覆盖原有成员)

Array.prototype.copyWithin(target, start = 0, end = this.length)

target(必需)开始替换位置,如果为负值,则是倒数。

start 从该位置开始读取数据,默认为0.如果是负值,表示从末尾开始计算

5.find()和findIndex():这两个方法都可以接受第二个参数,用来绑定回调函数的this对象

find方法找出第一个符合条件的数组成员。find方法的回调函数接受三个参数,依次为当前的值、当前的位置和原数组。

findIndex与find方法类似,返回第一个符合条件的数组成员的位置,所有都不符合条件则返回-1。

6.数组实例的fill()。使用给定值,填充一个数组。接受3个参数,依次为填充的值,填充起始位置和结束位置。如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。

7.数组实例的entries(),keys()和values()—用于遍历数组,都返回一个遍历器对象,可以用for…of循环遍历,keys()是对键名的遍历、values()是对键值的遍历、entries()是对键值对的遍历。

8.数组实例的includes()—–返回一个布尔值,是否包含给定的值。接受第二个参数,表示搜索的起始位置,默认为0,如果为负数,则表示倒数的位置,如果大于数组长度则会重置为从0开始。

9.数组实例的flat(),flatMap()—将嵌套的数组拉平,变成一维数组,返回一个新数组,对原数据没有影响。

flat()默认只会拉平一层,需要拉平几层参数就填几,可以用Infinity关键字作为参数,不管多少层嵌套都要转成一维数组。如果原数组有空位则会跳过空位。

flatMap()对原数组的每个成员执行一个函数。只能展开一层数组。相当于执行map()然后对返回值组成的数组执行flat()方法。还可以有第二个参数,用来绑定遍历函数里面的this。

10.数组的空位—有些会跳过空位,有些将空位视为undefined。

15.属性的遍历

(1)for…in:循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)

(2)Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)的键名

(3)Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

(4)Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有 Symbol 属性的键名。

(5)Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

16.Set和Map数据结构

(1)Set,类似于数组,但是成员的值是唯一不重复的。

[…new Set(array)]—去除数组的重复成员;[…new Set(‘arraaa’)].join(”)—去除字符串里面的重复字符。

Set结构的实例有以下属性:Set.protoType.constructor:构造函数;Set.prototype.size:返回Set实例的成员总数;Set.prototype.add(value):添加某个值,返回set结构本身;Set.prototype.delete(value):删除某个值,返回一个布尔值表示删除是否成功;Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员;Set.prototype.clear():清除所有成员,没有返回值。

Set结构的实例有4个遍历方法:Set.prototype.keys():返回键名的遍历器;Set.prototype.values():返回键值的遍历器;Set.prototype.entries:返回键值对的遍历器;Set.prototype.forEach():使用回调函数遍历每个成员

ps:还是之前整理的,可能有点过时,或者有些缩写

原创文章,作者:站长,如若转载,请注明出处:https://wsppx.cn/382/%e7%bd%91%e7%bb%9c%e5%bc%80%e5%8f%91/%e5%89%8d%e7%ab%af/

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注