乐趣区

关于前端:校招前端二面高频面试题合集

DOCTYPE(⽂档类型) 的作⽤

DOCTYPE 是 HTML5 中一种规范通用标记语言的文档类型申明,它的目标是 通知浏览器(解析器)应该以什么样(html 或 xhtml)的文档类型定义来解析文档,不同的渲染模式会影响浏览器对 CSS 代码甚⾄ JavaScript 脚本的解析。它必须申明在 HTML ⽂档的第⼀⾏。

浏览器渲染页面的两种模式(可通过 document.compatMode 获取,比方,语雀官网的文档类型是CSS1Compat):

  • CSS1Compat:规范模式(Strick mode),默认模式,浏览器应用 W3C 的规范解析渲染页面。在规范模式中,浏览器以其反对的最高规范出现页面。
  • BackCompat:怪异模式(混淆模式)(Quick mode),浏览器应用本人的怪异模式解析渲染页面。在怪异模式中,页面以一种比拟宽松的向后兼容的形式显示。

webpack 配置入口进口

module.exports={
    // 入口文件的配置项
    entry:{},
    // 进口文件的配置项
    output:{},
    // 模块:例如解读 CSS, 图片如何转换,压缩
    module:{},
    // 插件,用于生产模版和各项性能
    plugins:[],
    // 配置 webpack 开发服务性能
    devServer:{}}
简略形容了一下这几个属性是干什么的。形容一下 npm run dev / npm run build 执行的是哪些文件
通过配置 proxyTable 来达到开发环境跨域的问题,而后又能够扩大和他聊聊跨域的产生,如何跨域
最初能够在聊聊 webpack 的优化,例如 babel-loader 的优化,gzip 压缩等等

一个 tcp 连贯能发几个 http 申请?

如果是 HTTP 1.0 版本协定,个别状况下,不反对长连贯,因而在每次申请发送结束之后,TCP 连贯即会断开,因而一个 TCP 发送一个 HTTP 申请,然而有一种状况能够将一条 TCP 连贯放弃在沉闷状态,那就是通过 Connection 和 Keep-Alive 首部,在申请头带上 Connection: Keep-Alive,并且能够通过 Keep-Alive 通用首部中指定的,用逗号分隔的选项调节 keep-alive 的行为,如果客户端和服务端都反对,那么其实也能够发送多条,不过此形式也有限度,能够关注《HTTP 权威指南》4.5.5 节对于 Keep-Alive 连贯的限度和规定。

而如果是 HTTP 1.1 版本协定,反对了长连贯,因而只有 TCP 连接不断开,便能够始终发送 HTTP 申请,继续一直,没有下限;同样,如果是 HTTP 2.0 版本协定,反对多用复用,一个 TCP 连贯是能够并发多个 HTTP 申请的,同样也是反对长连贯,因而只有一直开 TCP 的连贯,HTTP 申请数也是能够没有下限地继续发送

typeof NaN 的后果是什么?

NaN 指“不是一个数字”(not a number),NaN 是一个“戒备值”(sentinel value,有非凡用处的惯例值),用于指出数字类型中的谬误状况,即“执行数学运算没有胜利,这是失败后返回的后果”。

typeof NaN; // "number"

NaN 是一个非凡值,它和本身不相等,是惟一一个非自反(自反,reflexive,即 x === x 不成立)的值。而 NaN !== NaN 为 true。

说一下 for…in 和 for…of 的区别?

for...of 遍历获取的是对象的键值, for...in 获取的是对象的键名;
for...in 会遍历对象的整个原型链, 性能十分差不举荐应用, 而 for...of 只遍历以后对象不会遍历原型链;
对于数组的遍历,for...in 会返回数组中所有可枚举的属性(包含原型链上可枚举的属性),for...of 只返回数组的下标对应的属性值;
总结:for...in 循环次要是为了遍历对象而生, 不实用遍历数组; for....of 循环能够用来遍历数组、类数组对象、字符串、Set、Map 以及 Generator 对象

即时通讯的实现:短轮询、长轮询、SSE 和 WebSocket 间的区别?

短轮询和长轮询的目标都是用于实现客户端和服务器端的一个即时通讯。

短轮询的基本思路: 浏览器每隔一段时间向浏览器发送 http 申请,服务器端在收到申请后,不管是否有数据更新,都间接进行响应。这种形式实现的即时通信,实质上还是浏览器发送申请,服务器承受申请的一个过程,通过让客户端一直的进行申请,使得客户端可能模仿实时地收到服务器端的数据的变动。这种形式的长处是比较简单,易于了解。毛病是这种形式因为须要一直的建设 http 连贯,重大节约了服务器端和客户端的资源。当用户减少时,服务器端的压力就会变大,这是很不合理的。

长轮询的基本思路: 首先由客户端向服务器发动申请,当服务器收到客户端发来的申请后,服务器端不会间接进行响应,而是先将这个申请挂起,而后判断服务器端数据是否有更新。如果有更新,则进行响应,如果始终没有数据,则达到肯定的工夫限度才返回。客户端 JavaScript 响应处理函数会在解决完服务器返回的信息后,再次发出请求,从新建设连贯。长轮询和短轮询比起来,它的长处是显著缩小了很多不必要的 http 申请次数,相比之下节约了资源。长轮询的毛病在于,连贯挂起也会导致资源的节约。

SSE 的根本思维: 服务器应用流信息向服务器推送信息。严格地说,http 协定无奈做到服务器被动推送信息。然而,有一种变通方法,就是服务器向客户端申明,接下来要发送的是流信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过去。这时,客户端不会敞开连贯,会始终等着服务器发过来的新的数据流,视频播放就是这样的例子。SSE 就是利用这种机制,应用流信息向浏览器推送信息。它基于 http 协定,目前除了 IE/Edge,其余浏览器都反对。它绝对于后面两种形式来说,不须要建设过多的 http 申请,相比之下节约了资源。

WebSocket 是 HTML5 定义的一个新协定议,与传统的 http 协定不同,该协定容许由服务器被动的向客户端推送信息。应用 WebSocket 协定的毛病是在服务器端的配置比较复杂。WebSocket 是一个全双工的协定,也就是通信单方是平等的,能够互相发送音讯,而 SSE 的形式是单向通信的,只能由服务器端向客户端推送信息,如果客户端须要发送信息就是属于下一个 http 申请了。

下面的四个通信协议,前三个都是基于 HTTP 协定的。

对于这四种即便通信协议,从性能的角度来看:WebSocket > 长连贯(SEE)> 长轮询 > 短轮询 然而,咱们如果思考浏览器的兼容性问题,程序就恰恰相反了: 短轮询 > 长轮询 > 长连贯(SEE)> WebSocket 所以,还是要依据具体的应用场景来判断应用哪种形式。

代码输入后果

var a = 10
var obj = {
  a: 20,
  say: () => {console.log(this.a)
  }
}
obj.say() 

var anotherObj = {a: 30} 
obj.say.apply(anotherObj) 

输入后果:10 10

我么晓得,箭头函数时不绑定 this 的,它的 this 来自原其父级所处的上下文,所以首先会打印全局中的 a 的值 10。前面尽管让 say 办法指向了另外一个对象,然而仍不能扭转箭头函数的个性,它的 this 依然是指向全局的,所以依旧会输入 10。

然而,如果是一般函数,那么就会有齐全不一样的后果:

var a = 10  
var obj = {  
  a: 20,  
  say(){console.log(this.a)  
  }  
}  
obj.say()   
var anotherObj={a:30}   
obj.say.apply(anotherObj)

输入后果:20 30

这时,say 办法中的 this 就会指向他所在的对象,输入其中的 a 的值。

CSS3 中有哪些新个性

  • 新增各种 CSS 选择器(: not(.input):所有 class 不是“input”的节点)
  • 圆角(border-radius:8px)
  • 多列布局(multi-column layout)
  • 暗影和反射(Shadoweflect)
  • 文字特效(text-shadow)
  • 文字渲染(Text-decoration)
  • 线性突变(gradient)
  • 旋转(transform)
  • 减少了旋转, 缩放, 定位, 歪斜, 动画, 多背景

什么是执行栈

能够把执行栈认为是一个存储函数调用的 栈构造,遵循先进后出的准则。当开始执行 JS 代码时,依据先进后出的准则,后执行的函数会先弹出栈,能够看到,foo 函数后执行,当执行结束后就从栈中弹出了。

平时在开发中,能够在报错中找到执行栈的痕迹:

function foo() {throw new Error('error')
}
function bar() {foo()
}
bar()

能够看到报错在 foo 函数,foo 函数又是在 bar 函数中调用的。当应用递归时,因为栈可寄存的函数是有 限度 的,一旦寄存了过多的函数且没有失去开释的话,就会呈现爆栈的问题

function bar() {  bar()}bar()

常⽤的 meta 标签有哪些

meta 标签由 namecontent 属性定义,用来形容网页文档的属性 ,比方网页的作者,网页形容,关键词等,除了 HTTP 规范固定了一些name 作为大家应用的共识,开发者还能够自定义 name。

罕用的 meta 标签:
(1)charset,用来形容 HTML 文档的编码类型:

<meta charset="UTF-8" >

(2)keywords,页面关键词:

<meta name="keywords" content="关键词" />

(3)description,页面形容:

<meta name="description" content="页面形容内容" />

(4)refresh,页面重定向和刷新:

<meta http-equiv="refresh" content="0;url=" />

(5)viewport,适配挪动端,能够管制视口的大小和比例:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

其中,content 参数有以下几种:

  • width viewport:宽度(数值 /device-width)
  • height viewport:高度(数值 /device-height)
  • initial-scale:初始缩放比例
  • maximum-scale:最大缩放比例
  • minimum-scale:最小缩放比例
  • user-scalable:是否容许用户缩放(yes/no)

(6)搜索引擎索引形式:

<meta name="robots" content="index,follow" />

其中,content 参数有以下几种:

  • all:文件将被检索,且页面上的链接能够被查问;
  • none:文件将不被检索,且页面上的链接不能够被查问;
  • index:文件将被检索;
  • follow:页面上的链接能够被查问;
  • noindex:文件将不被检索;
  • nofollow:页面上的链接不能够被查问。

script 标签中 defer 和 async 的区别

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

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

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

对 requestAnimationframe 的了解

实现动画成果的办法比拟多,Javascript 中能够通过定时器 setTimeout 来实现,CSS3 中能够应用 transition 和 animation 来实现,HTML5 中的 canvas 也能够实现。除此之外,HTML5 提供一个专门用于申请动画的 API,那就是 requestAnimationFrame,顾名思义就是 申请动画帧

MDN 对该办法的形容:

window.requestAnimationFrame() 通知浏览器——你心愿执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该办法须要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

语法: window.requestAnimationFrame(callback); 其中,callback 是 下一次重绘之前更新动画帧所调用的函数 (即下面所说的回调函数)。该回调函数会被传入 DOMHighResTimeStamp 参数,它示意 requestAnimationFrame() 开始去执行回调函数的时刻。该办法属于 宏工作,所以会在执行完微工作之后再去执行。

勾销动画: 应用 cancelAnimationFrame()来勾销执行动画,该办法接管一个参数——requestAnimationFrame 默认返回的 id,只须要传入这个 id 就能够勾销动画了。

劣势:

  • CPU 节能:应用 SetTinterval 实现的动画,当页面被暗藏或最小化时,SetTinterval 依然在后盾执行动画工作,因为此时页面处于不可见或不可用状态,刷新动画是没有意义的,齐全是节约 CPU 资源。而 RequestAnimationFrame 则齐全不同,当页面解决未激活的状态下,该页面的屏幕刷新工作也会被零碎暂停,因而跟着零碎走的 RequestAnimationFrame 也会进行渲染,当页面被激活时,动画就从上次停留的中央继续执行,无效节俭了 CPU 开销。
  • 函数节流 :在高频率事件(resize, scroll 等) 中,为了避免在一个刷新距离内产生屡次函数执行,RequestAnimationFrame 可保障每个刷新距离内,函数只被执行一次,这样既能保障流畅性,也能更好的节俭函数执行的开销,一个刷新距离内函数执行屡次时没有意义的,因为少数显示器每 16.7ms 刷新一次,屡次绘制并不会在屏幕上体现进去。
  • 缩小 DOM 操作:requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就实现,并且重绘或回流的工夫距离紧紧追随浏览器的刷新频率,一般来说,这个频率为每秒 60 帧。

setTimeout 执行动画的毛病:它通过设定间隔时间来一直扭转图像地位,达到动画成果。然而容易呈现卡顿、抖动的景象;起因是:

  • settimeout 工作被放入异步队列,只有当主线程工作执行完后才会执行队列中的工作,因而理论执行工夫总是比设定工夫要晚;
  • settimeout 的固定工夫距离不肯定与屏幕刷新间隔时间雷同,会引起丢帧。

TCP 和 UDP 的应用场景

  • TCP 利用场景: 效率要求绝对低,但对准确性要求绝对高的场景。因为传输中须要对数据确认、重发、排序等操作,相比之下效率没有 UDP 高。例如:文件传输(精确高要求高、然而速度能够绝对慢)、承受邮件、近程登录。
  • UDP 利用场景: 效率要求绝对高,对准确性要求绝对低的场景。例如:QQ 聊天、在线视频、网络语音电话(即时通讯,速度要求高,然而呈现偶然断续不是太大问题,并且此处齐全不能够应用重发机制)、播送通信(播送、多播)。

Number() 的存储空间是多大?如果后盾发送了一个超过最大本人的数字怎么办

Math.pow(2, 53),53 为有效数字,会产生截断,等于 JS 能反对的最大数字。

LRU 算法

实现代码如下:

//  一个 Map 对象在迭代时会依据对象中元素的插入程序来进行
// 新增加的元素会被插入到 map 的开端,整个栈倒序查看
class LRUCache {constructor(capacity) {this.secretKey = new Map();
    this.capacity = capacity;
  }
  get(key) {if (this.secretKey.has(key)) {let tempValue = this.secretKey.get(key);
      this.secretKey.delete(key);
      this.secretKey.set(key, tempValue);
      return tempValue;
    } else return -1;
  }
  put(key, value) {
    // key 存在,仅批改值
    if (this.secretKey.has(key)) {this.secretKey.delete(key);
      this.secretKey.set(key, value);
    }
    // key 不存在,cache 未满
    else if (this.secretKey.size < this.capacity) {this.secretKey.set(key, value);
    }
    // 增加新 key,删除旧 key
    else {this.secretKey.set(key, value);
      // 删除 map 的第一个元素,即为最长未应用的
      this.secretKey.delete(this.secretKey.keys().next().value);
    }
  }
}
// let cache = new LRUCache(2);
// cache.put(1, 1);
// cache.put(2, 2);
// console.log("cache.get(1)", cache.get(1))// 返回  1
// cache.put(3, 3);// 该操作会使得密钥 2 作废
// console.log("cache.get(2)", cache.get(2))// 返回 -1 (未找到)
// cache.put(4, 4);// 该操作会使得密钥 1 作废
// console.log("cache.get(1)", cache.get(1))// 返回 -1 (未找到)
// console.log("cache.get(3)", cache.get(3))// 返回  3
// console.log("cache.get(4)", cache.get(4))// 返回  4

如何进攻 CSRF 攻打?

CSRF 攻打能够应用以下办法来防护:

  • 进行同源检测,服务器依据 http 申请头中 origin 或者 referer 信息来判断申请是否为容许拜访的站点,从而对申请进行过滤。当 origin 或者 referer 信息都不存在的时候,间接阻止申请。这种形式的毛病是有些状况下 referer 能够被伪造,同时还会把搜索引擎的链接也给屏蔽了。所以个别网站会容许搜索引擎的页面申请,然而相应的页面申请这种申请形式也可能被攻击者给利用。(Referer 字段会通知服务器该网页是从哪个页面链接过去的)
  • 应用 CSRF Token 进行验证,服务器向用户返回一个随机数 Token,当网站再次发动申请时,在申请参数中退出服务器端返回的 token,而后服务器对这个 token 进行验证。这种办法解决了应用 cookie 繁多验证形式时,可能会被冒用的问题,然而这种办法存在一个毛病就是,咱们须要给网站中的所有申请都增加上这个 token,操作比拟繁琐。还有一个问题是个别不会只有一台网站服务器,如果申请通过负载平衡转移到了其余的服务器,然而这个服务器的 session 中没有保留这个 token 的话,就没有方法验证了。这种状况能够通过扭转 token 的构建形式来解决。
  • 对 Cookie 进行双重验证,服务器在用户拜访网站页面时,向申请域名注入一个 Cookie,内容为随机字符串,而后当用户再次向服务器发送申请的时候,从 cookie 中取出这个字符串,增加到 URL 参数中,而后服务器通过对 cookie 中的数据和参数中的数据进行比拟,来进行验证。应用这种形式是利用了攻击者只能利用 cookie,然而不能拜访获取 cookie 的特点。并且这种办法比 CSRF Token 的办法更加不便,并且不波及到分布式拜访的问题。这种办法的毛病是如果网站存在 XSS 破绽的,那么这种形式会生效。同时这种形式不能做到子域名的隔离。
  • 在设置 cookie 属性的时候设置 Samesite,限度 cookie 不能作为被第三方应用,从而能够防止被攻击者利用。Samesite 一共有两种模式,一种是严格模式,在严格模式下 cookie 在任何状况下都不可能作为第三方 Cookie 应用,在宽松模式下,cookie 能够被申请是 GET 申请,且会产生页面跳转的申请所应用。

代码输入后果

Promise.reject('err!!!')
  .then((res) => {console.log('success', res)
  }, (err) => {console.log('error', err)
  }).catch(err => {console.log('catch', err)
  })

输入后果如下:

error err!!!

咱们晓得,.then函数中的两个参数:

  • 第一个参数是用来解决 Promise 胜利的函数
  • 第二个则是解决失败的函数

也就是说 Promise.resolve('1') 的值会进入胜利的函数,Promise.reject('2')的值会进入失败的函数。

在这道题中,谬误间接被 then 的第二个参数捕捉了,所以就不会被 catch 捕捉了,输入后果为:error err!!!'

然而,如果是像上面这样:

Promise.resolve()
  .then(function success (res) {throw new Error('error!!!')
  }, function fail1 (err) {console.log('fail1', err)
  }).catch(function fail2 (err) {console.log('fail2', err)
  })

then 的第一参数中抛出了谬误,那么他就不会被第二个参数不活了,而是被前面的 catch 捕捉到。

代码输入后果

Promise.resolve().then(() => {console.log('1');
    throw 'Error';
}).then(() => {console.log('2');
}).catch(() => {console.log('3');
    throw 'Error';
}).then(() => {console.log('4');
}).catch(() => {console.log('5');
}).then(() => {console.log('6');
});

执行后果如下:

1 
3 
5 
6

在这道题目中,咱们须要晓得,无论是 thne 还是 catch 中,只有 throw 抛出了谬误,就会被 catch 捕捉,如果没有 throw 出谬误,就被继续执行前面的 then。

代码输入后果

function a(xx){
  this.x = xx;
  return this
};
var x = a(5);
var y = a(6);

console.log(x.x)  // undefined
console.log(y.x)  // 6

输入后果:undefined 6

解析:

  1. 最要害的就是 var x = a(5),函数 a 是在全局作用域调用,所以函数外部的 this 指向 window 对象。所以 this.x = 5 就相当于:window.x = 5。之后 return this,也就是说 var x = a(5) 中的 x 变量的值是 window,这里的 x 将函数外部的 x 的值笼罩了。而后执行 console.log(x.x),也就是 console.log(window.x),而 window 对象中没有 x 属性,所以会输入 undefined。
  2. 当指向 y.x 时,会给全局变量中的 x 赋值为 6,所以会打印出 6。
退出移动版