大家好,我是编程小6,很高兴遇见你,有问题可以及时留言哦。
脑子里陆陆续续过出来的一些面试题,文章会不断更新
注:“固定”这个词的含义,它指的固定是指只要传进去了 context,则 bind 中 return 出来的函数 this 便一直指向 context,除非 context 是个变量 6. 变量声明提升:js 代码在运行前都会进行 AST 解析,函数申明默认会提到当前作用域最前面,变量申明也会进行提升。但赋值不会得到提升。关于 AST 解析,这里也可以说是形成词法作用域的主要原因
这里如果面试官问到2,3,4,5,6中的一点,你能够把2,3,4,5,6整理到一起,串联起来进行统一的回答效果极佳
具体参考 从指向看JavaScript
详细参考 my-promise
function
关键字与函数名之间有一个星号;yield
表达式,定义不同的内部状态;next
指针移向下一个状态这里你可以说说 Generator
的异步编程,以及它的语法糖 async
和 awiat
,传统的异步编程。ES6 之前,异步编程大致如下
传统异步编程方案之一:协程,多个线程互相协作,完成异步任务。
基本用法
async function timeout (ms) {
await new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function asyncConsole (value, ms) {
await timeout(ms)
console.log(value)
}
asyncConsole('hello async and await', 1000)
注:最好把2,3,4 连到一起讲
/* 方案1 */
.left {
width: 120px;
float: left;
}
.right {
margin-left: 120px;
}
/* 方案2 */
.left {
width: 120px;
float: left;
}
.right {
width: calc(100% - 120px);
float: left;
}
.wrap {
width: 100%;
height: 200px;
}
.wrap > div {
height: 100%;
}
/* 方案1 */
.left {
width: 120px;
float: left;
}
.right {
float: right;
width: 120px;
}
.center {
margin: 0 120px;
}
/* 方案2 */
.left {
width: 120px;
float: left;
}
.right {
float: right;
width: 120px;
}
.center {
width: calc(100% - 240px);
margin-left: 120px;
}
/* 方案3 */
.wrap {
display: flex;
}
.left {
width: 120px;
}
.right {
width: 120px;
}
.center {
flex: 1;
}
/* 方案1 */
.wrap {
text-align: center
}
.center {
display: inline;
/* or */
/* display: inline-block; */
}
/* 方案2 */
.center {
width: 100px;
margin: 0 auto;
}
/* 方案2 */
.wrap {
position: relative;
}
.center {
position: absulote;
left: 50%;
transform: translateX(-50%);
}
/* 定高方案1 */
.center {
height: 100px;
margin: 50px 0;
}
/* 定高方案2 */
.center {
height: 100px;
position: absolute;
top: 50%;
margin-top: -25px;
}
/* 不定高方案1 */
.center {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
/* 不定高方案2 */
.wrap {
display: flex;
align-items: center;
}
.center {
width: 100%;
}
/* 不定高方案3 */
/* 设置 inline-block 则会在外层产生 IFC,高度设为 100% 撑开 wrap 的高度 */
.wrap::before {
content: '';
height: 100%;
display: inline-block;
vertical-align: middle;
}
.wrap {
text-align: center;
}
.center {
display: inline-block;
vertical-align: middle;
}
延伸: box-sizing
float 的值不为 none。
overflow 的值不为 visible。
position 的值不为 relative 和 static。
display 的值为 table-cell, table-caption, inline-block中的任何一个。
用处?常见的多栏布局,结合块级别元素浮动,里面的元素则是在一个相对隔离的环境里运行。
IFC中的line box一般左右都贴紧整个 IFC,但是会因为 float 元素而扰乱。float 元素会位于 IFC 与 line box 之间,使得 line box 宽度缩短。 同个 ifc 下的多个 line box 高度会不同。 IFC 中时不可能有块级元素的,当插入块级元素时(如 p 中插入 div )会产生两个匿名块与 div 分隔开,即产生两个 IFC ,每个 IFC 对外表现为块级元素,与 div 垂直排列。
用处?
水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生IFC,通过 text-align 则可以使其水平居中。
垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align: middle,其他行内元素则可以在此父元素下垂直居中
详细参考 css3中的BFC,IFC,GFC和FFC
详细细节参考 实现一个属于我们自己的简易MVVM库
扩充:如何监听数组变化
详细请参考 实现Virtual Dom && Diff
补充1:VDOM 的必要性?
创建真实DOM的代价高:真实的 DOM 节点 node 实现的属性很多,而 vnode 仅仅实现一些必要的属性,相比起来,创建一个 vnode 的成本比较低。
触发多次浏览器重绘及回流:使用 vnode ,相当于加了一个缓冲,让一次数据变动所带来的所有 node 变化,先在 vnode 中进行修改,然后 diff 之后对所有产生差异的节点集中一次对 DOM tree 进行修改,以减少浏览器的重绘及回流。
补充2:vue 为什么采用 vdom?
引入 Virtual DOM 在性能方面的考量仅仅是一方面。
性能受场景的影响是非常大的,不同的场景可能造成不同实现方案之间成倍的性能差距,所以依赖细粒度绑定及 Virtual DOM 哪个的性能更好还真不是一个容易下定论的问题。
Vue 之所以引入了 Virtual DOM,更重要的原因是为了解耦 HTML 依赖,这带来两个非常重要的好处是:
综上,Virtual DOM 在性能上的收益并不是最主要的,更重要的是它使得 Vue 具备了现代框架应有的高级特性。
上面提到的每个点,具体细节还得看自己的理解
详细内容传送门
延伸1:img iframe script 来发送跨域请求有什么优缺点?
优点:跨域完毕之后DOM操作和互相之间的JavaScript调用都是没有问题的
缺点:1.若结果要以URL参数传递,这就意味着在结果数据量很大的时候需要分割传递,巨烦。2.还有一个是iframe本身带来的,母页面和iframe本身的交互本身就有安全性限制。
优点:可以直接返回json格式的数据,方便处理
缺点:只接受GET请求方式
优点:可以访问任何url,一般用来进行点击追踪,做页面分析常用的方法
缺点:不能访问响应文本,只能监听是否响应
延伸2:配合 webpack 进行反向代理?
webpack 在 devServer 选项里面提供了一个 proxy 的参数供开发人员进行反向代理
'/api': {
target: 'http://www.example.com', // your target host
changeOrigin: true, // needed for virtual hosted sites
pathRewrite: {
'^/api': '' // rewrite path
}
},
然后再配合 http-proxy-middleware
插件对 api 请求地址进行代理
const express = require('express');
const proxy = require('http-proxy-middleware');
// proxy api requests
const exampleProxy = proxy(options); // 这里的 options 就是 webpack 里面的 proxy 选项对应的每个选项
// mount `exampleProxy` in web server
const app = express();
app.use('/api', exampleProxy);
app.listen(3000);
然后再用 nginx
把允许跨域的源地址添加到报头里面即可
说到 nginx
,可以再谈谈 CORS 配置,大致如下
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT, X-Mx-ReqToken, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 200;
}
}
http协议无状态中的 状态 到底指的是什么?!
【状态】的含义就是:客户端和服务器在某次会话中产生的数据
那么对应的【无状态】就意味着:这些数据不会被保留
but
首先得明确 http 缓存的好处
常见 http 缓存的类型
然后谈谈本地缓存
本地缓存是指浏览器请求资源时命中了浏览器本地的缓存资源,浏览器并不会发送真正的请求给服务器了。它的执行过程是:
与本地缓存相关的头有:Cache-Control、Expires,Cache-Control有多个可选值代表不同的意义,而Expires就是一个日期格式的绝对值。
Cache-Control
Cache-Control是HTPP缓存策略中最重要的头,它是HTTP/1.1中出现的,它由如下几个值
例如:
Cache-Control: public, max-age=1000
表示资源可以被所有用户以及代理服务器缓存,最长时间为1000秒。
Expires
Expires是HTTP/1.0出现的头信息,同样是用于决定本地缓存策略的头,它是一个绝对时间,时间格式是如Mon, 10 Jun 2015 21:31:12 GMT,只要发送请求时间是在Expires之前,那么本地缓存始终有效,否则就会去服务器发送请求获取新的资源。如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。他们可以这样组合使用
Cache-Control: public
Expires: Wed, Jan 10 2018 00:27:04 GMT
所谓的缓存协商
当第一次请求时服务器返回的响应头中存在以下情况时
那么浏览器第二次请求时就会与服务器进行协商,询问浏览器中的缓存资源是不是旧版本,需不需要更新,此时,服务器就会做出判断,如果缓存和服务端资源的最新版本是一致的,那么就无需再次下载该资源,服务端直接返回304 Not Modified 状态码,如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是200 Ok,那么服务端是根据什么来判断浏览器的缓存是不是最新的呢?其实是根据HTTP的另外两组头信息,分别是:Last-Modified/If-Modified-Since 与 ETag/If-None-Match。
Last-Modified 与 If-Modified-Since
如果两者相等或者大于服务器上的最新修改时间,那么表示浏览器的缓存是有效的,此时缓存会命中,服务器就不再返回内容给浏览器了,同时Last-Modified头也不会返回,因为资源没被修改,返回了也没什么意义。如果没命中缓存则最新修改的资源连同Last-Modified头一起返回。
第一次请求返回的响应头:
Cache-Control:max-age=3600
Expires: Fri, Jan 12 2018 00:27:04 GMT
Last-Modified: Wed, Jan 10 2018 00:27:04 GMT
第二次请求的请求头信息:
If-Modified-Since: Wed, Jan 10 2018 00:27:04 GMT
这组头信息是基于资源的修改时间来判断资源有没有更新,另一种方式就是根据资源的内容来判断,就是接下来要讨论的ETag与If-None-Match
ETag与If-None-Match
ETag/If-None-Match与Last-Modified/If-Modified-Since的流程其实是类似的,唯一的区别是它基于资源的内容的摘要信息(比如MD5 hash)来判断
浏览器发送第二次请求时,会把第一次的响应头信息ETag的值放在If-None-Match的请求头中发送到服务器,与最新的资源的摘要信息对比,如果相等,取浏览器缓存,否则内容有更新,最新的资源连同最新的摘要信息返回。用ETag的好处是如果因为某种原因到时资源的修改时间没改变,那么用ETag就能区分资源是不是有被更新。
第一次请求返回的响应头:
Cache-Control: public, max-age=31536000
ETag: "15f0fff99ed5aae4edffdd6496d7131f"
第二次请求的请求头信息:
If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"
现在我们常说的 “session”,是为了绕开 cookie 的各种限制,通常借助 cookie 本身和后端存储实现的,一种更高级的会话状态实现
session 的常见实现要借助cookie来发送 sessionID
防范:记住一点 “所有用户输入都是不可信的”,所以得做输入过滤和转义
详细点击 对于跨站脚本攻击(XSS攻击)的理解和总结
防范:用户操作验证(验证码),额外验证机制(token使用)等
详细点击 对于跨站伪造请求(CSRF)的理解和总结
个人准备重新捡回自己的公众号了,之后每周保证一篇高质量好文,感兴趣的小伙伴可以关注一波。