你盼世界,我盼望你无bug
。Hello 你们好!我是霖呆呆!javascript
哈哈😄,这是一篇面试总结文章,抱歉,webpack
和HTTP
系列的先暂缓一下更新哈,Sorry~css
这篇文章是呆呆本身近期的一些面试汇总,经验是2年,算了一下有128道,基本都写了比较完善的答案,就算没有写也有推荐一些好的文章连接,文章篇幅较大,整理总结也花费了不少的时间和心血,题目也是根据公司规模的大小从易到难,算是见证了呆呆面试过程当中的不足与成长吧 😅。还但愿能帮助到正在一块儿努力求生存的小伙伴们。html
另外,看到标题了吗?"掘金技术征文"
,嘻嘻,要不要考虑帮这么"用心"
的呆呆拿拿大奖呢?放心放心,要真成了好处少不了大家😋。前端
"风浪没平息 我宣告奔跑的意义"
vue
"这不是叛逆 我只是淋了一场雨"
java
全部文章内容都已整理至 github.com/LinDaiDai/n… 快来给我Star呀😊~node
(由于近期面的主要都是一些深圳的中小公司,他们也还在招聘中,因此不便透露公司名称,还请你们理解...)react
4月22日上午webpack
缺点: 不一样浏览器对web标准默认值不一样,因此更容易出现对浏览器的兼容性问题。ios
改变a标签css属性的排列顺序
只须要记住LoVe HAte
原则就能够了:
link→visited→hover→active
复制代码
好比下面错误的代码顺序:
a:hover{ color: green; text-decoration: none; } a:visited{ /* visited在hover后面,这样的话hover事件就失效了 */ color: red; text-decoration: none; } 复制代码
正确的作法是将两个事件的位置调整一下。
注意⚠️各个阶段的含义:
a:link
:未访问时的样式,通常省略成a a:visited
:已经访问后的样式 a:hover
:鼠标移上去时的样式 a:active
:鼠标按下时的样式
const text = document.getElementById('text'); text.onclick = function (e) { console.log('onclick') } text.onfocus = function (e) { console.log('onfocus') } text.onmousedown = function (e) { console.log('onmousedown') } text.onmouseenter = function (e) { console.log('onmouseenter') } 复制代码
答案:
'onmouseenter' 'onmousedown' 'onfocus' 'onclick' 复制代码
对某些数据的修改就能自动更新视图,让开发者不用再去操做DOM,有更多的时间去思考业务逻辑。
首先Vue最核心的两个特色,响应式和组件化。
响应式:这也就是vue.js最大的优势,经过MVVM思想实现数据的双向绑定,经过虚拟DOM让咱们能够用数据来操做DOM,而没必要去操做真实的DOM,提高了性能。且让开发者有更多的时间去思考业务逻辑。
组件化:把一个单页应用中的各个模块拆分到一个个组件当中,或者把一些公共的部分抽离出来作成一个可复用的组件。因此组件化带来的好处就是,提升了开发效率,方便重复使用,使项目的可维护性更强。
虚拟DOM,固然,这个不是vue中独有的。
缺点:基于对象配置文件的写法,也就是options写法,开发时不利于对一个属性的查找。另一些缺点,在小项目中感受不太出什么,vuex的魔法字符串,对ts的支持。兼容性上存在一些问题。
另外还有评论区掘友黎生提供的一些缺点:
hash
模式的URL
中会夹杂着#
号,而history
没有。Vue
底层对它们的实现方式不一样。hash
模式是依靠onhashchange
事件(监听location.hash
的改变),而history
模式是主要是依靠的HTML5 history
中新增的两个方法,pushState()
能够改变url
地址且不会发送请求,replaceState()
能够读取历史记录栈,还能够对浏览器记录进行修改。URL
向后端发送HTTP
请求的时候,好比常见的用户手动输入URL
后回车,或者是刷新(重启)浏览器,这时候history
模式须要后端的支持。由于history
模式下,前端的URL
必须和实际向后端发送请求的URL
一致,例若有一个URL
是带有路径path
的(例如www.lindaidai.wang/blogs/id
),若是后端没有对这个路径作处理的话,就会返回404
错误。因此须要后端增长一个覆盖全部状况的候选资源,通常会配合前端给出的一个404
页面。hash:
window.onhashchange = function(event){ // location.hash获取到的是包括#号的,如"#heading-3" // 因此能够截取一下 let hash = location.hash.slice(1); } 复制代码
4月22日下午
null
表示一个"无"
的对象,也就是该处不该该有值;而undefined
表示未定义。Number(null)
为0
,而undefined
为NaN
。使用场景上:
null
:
undefined
:
冒泡排序:
function bubbleSort (arr) { for (let i = 0; i < arr.length; i++) { let flag = true; for (let j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { flag = false; let temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } if (flag) break; } return arr; } 复制代码
这个是优化事后的冒泡排序。用了一个flag
来优化,它的意思是:若是某一次循环中没有交换过元素,那么意味着排序已经完成了。
冒泡排序总会执行(N-1)+(N-2)+(N-3)+..+2+1趟,但若是运行到当中某一趟时排序已经完成,或者输入的是一个有序数组,那么后边的比较就都是多余的,为了不这种状况,咱们增长一个flag,判断排序是否在中途就已经完成(也就是判断有无发生元素交换)
数组去重:
Array.from(new Set(arr))
[...new Set(arr)]
for
循环嵌套,利用splice
去重indexOf
或者includes
去重sort
排序,而后用一个指针从第0
位开始,配合while
循环去重固然还有不少,例如用filter、reduce、Map、Object
等,具体能够看:
Array.from(new Set(arr))
或[...new Set(arr)]
var arr = [1,1,2,5,6,3,5,5,6,8,9,8]; console.log(Array.from(new Set(arr))) // console.log([...new Set(arr)]) 复制代码
for
循环嵌套,利用splice
去重:
function unique (origin) { let arr = [].concat(origin); for (let i = 0; i < arr.length; i++) { for (let j = i + 1; j < arr.length; j++) { if (arr[i] == arr[j]) { arr.splice(j, 1); j--; } } } return arr; } var arr = [1,1,2,5,6,3,5,5,6,8,9,8]; console.log(unique(arr)) 复制代码
新建数组,利用includes
去重:
function unique (arr) { let res = [] for (let i = 0; i < arr.length; i++) { if (!res.includes(arr[i])) { res.push(arr[i]) } } return res; } var arr = [1,1,2,5,6,3,5,5,6,8,9,8]; console.log(unique(arr)) 复制代码
先用sort
排序,而后用一个指针从第0
位开始,配合while
循环去重:
function unique (arr) { arr = arr.sort(); // 排序以后的数组 let pointer = 0; while (arr[pointer]) { if (arr[pointer] != arr[pointer + 1]) { // 若这一项和下一项不相等则指针往下移 pointer++; } else { // 不然删除下一项 arr.splice(pointer + 1, 1); } } return arr; } var arr = [1,1,2,5,6,3,5,5,6,8,9,8]; console.log(unique(arr)) 复制代码
4月23日上午
(从这家公司开始面试稍微有些难度了,面试官小哥哥人也很好,刚开始是一个高冷男神,可是在呆呆的猛烈回答下也终于仍是对我露出了微笑😄,还说他也是掘友,有看过个人文章...掘友真是无处不在啊,感动😹)
这道题我会先大概介绍一下Promise
:
Promise
是一个对象,它表明了一个异步操做的最终完成或者失败。因为它的then
方法和catch、finally
方法会返回一个新的Promise
因此能够容许咱们链式调用,解决了传统的回调地狱问题。
再说一下then
以及catch
方法:
(此处我是直接拿我以前的一篇文章《45道Promise题》那里的总结)
Promise
的状态一经改变就不能再改变。(见3.1).then
和.catch
都会返回一个新的Promise
。(上面的👆1.4证实了)catch
无论被链接到哪里,都能捕获上层未捕捉过的错误。(见3.2)Promise
中,返回任意一个非 promise
的值都会被包裹成 promise
对象,例如return 2
会被包装为return Promise.resolve(2)
。Promise
的 .then
或者 .catch
能够被调用屡次, 但若是Promise
内部的状态一经改变,而且有了一个值,那么后续每次调用.then
或者.catch
的时候都会直接拿到该值。(见3.5).then
或者 .catch
中 return
一个 error
对象并不会抛出错误,因此不会被后续的 .catch
捕获。(见3.6).then
或 .catch
返回的值不能是 promise 自己,不然会形成死循环。(见3.7).then
或者 .catch
的参数指望是函数,传入非函数则会发生值透传。(见3.8).then
方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候你能够认为catch
是.then
第二个参数的简便写法。(见3.9).finally
方法也是返回一个Promise
,他在Promise
结束的时候,不管结果为resolved
仍是rejected
,都会执行里面的回调函数。另外也能够说一下finally
方法:
.finally()
方法无论Promise
对象最后的状态如何都会执行
.finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()
函数中是无法知道Promise
最终的状态是resolved
仍是rejected
的
它最终返回的默认会是一个上一次的Promise对象值,不过若是抛出的是一个异常则返回异常的Promise
对象。
最后能够说一下all
以及race
方法:
Promise.all()
的做用是接收一组异步任务,而后并行执行异步任务,而且在全部异步操做执行完后才执行回调。.race()
的做用也是接收一组异步任务,而后并行执行异步任务,只保留取第一个执行完成的异步操做的结果,其余的方法仍在执行,不过执行结果会被抛弃。Promise.all().then()
结果中数组的顺序和Promise.all()
接收到的数组顺序一致。all和race
传入的数组中若是有会抛出异常的异步任务,那么只有最早抛出的错误会被捕获,而且是被then
的第二个参数或者后面的catch
捕获;但并不会影响数组中其它的异步任务的执行。这个,在上一题已经说到了:
all和race
传入的数组中若是有会抛出异常的异步任务,那么只有最早抛出的错误会被捕获,而且是被then
的第二个参数或者后面的catch
捕获;但并不会影响数组中其它的异步任务的执行。
因为它的then
方法和catch、finally
方法会返回一个新的Promise
因此能够容许咱们链式调用
一开始整个脚本做为一个宏任务执行
执行过程当中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
当前宏任务执行完出队,检查微任务列表,有则依次执行,直到所有执行完
执行浏览器UI线程的渲染工做
检查是否有Web Worker
任务,有则执行
执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
(具体能够看这里:juejin.cn/post/684490…
层级关系:
window > document > html > body 复制代码
window
是BOM
的核心对象,它一方面用来获取或设置浏览器的属性和行为,另外一方面做为一个全局对象。document
对象是一个跟文档相关的对象,拥有一些操做文档内容的功能。可是地位没有window
高。html
元素对象和document
元素对象是属于html
文档的DOM
对象,能够认为就是html
源代码中那些标签所化成的对象。他们跟div、select
什么对象没有根本区别。(我是这样记的,整个浏览器中最大的确定就是窗口window
了,那么进来的我无论你是啥,就算你是document
也得给我盘着)
第三个参数涉及到冒泡和捕获,是true
时为捕获,是false
则为冒泡。
或者是一个对象{passive: true}
,针对的是Safari
浏览器,禁止/开启使用滚动的时候要用到。
使用Event
使用customEvent
(能够传参数)
使用document.createEvent('CustomEvent')和initEvent()
建立自定义事件
原生自定义事件有三种写法:
Event
let myEvent = new Event('event_name'); 复制代码
customEvent
(能够传参数)let myEvent = new CustomEvent('event_name', { detail: { // 将须要传递的参数放到这里 // 能够在监听的回调函数中获取到:event.detail } }) 复制代码
document.createEvent('CustomEvent')和initEvent()
let myEvent = document.createEvent('CustomEvent');// 注意这里是为'CustomEvent' myEvent.initEvent( // 1. event_name: 事件名称 // 2. canBubble: 是否冒泡 // 3. cancelable: 是否能够取消默认行为 ) 复制代码
createEvent
:建立一个事件initEvent
:初始化一个事件能够看到,initEvent
能够指定3个参数。
(有些文章中会说还有第四个参数detail
,可是我查看了W3C
上并无这个参数,并且实践了一下也没有效果)
事件的监听
自定义事件的监听其实和普通事件的同样,使用addEventListener
来监听:
button.addEventListener('event_name', function (e) {}) 复制代码
事件的触发
触发自定义事件使用dispatchEvent(myEvent)
。
注意⚠️,这里的参数是要自定义事件的对象(也就是myEvent
),而不是自定义事件的名称('myEvent'
)
案例
来看个案例吧:
// 1. // let myEvent = new Event('myEvent'); // 2. // let myEvent = new CustomEvent('myEvent', { // detail: { // name: 'lindaidai' // } // }) // 3. let myEvent = document.createEvent('CustomEvent'); myEvent.initEvent('myEvent', true, true) let btn = document.getElementsByTagName('button')[0] btn.addEventListener('myEvent', function (e) { console.log(e) console.log(e.detail) }) setTimeout(() => { btn.dispatchEvent(myEvent) }, 2000) 复制代码
冒泡指的是:当给某个目标元素绑定了事件以后,这个事件会依次在它的父级元素中被触发(固然前提是这个父级元素也有这个同名称的事件,好比子元素和父元素都绑定了click
事件就触发父元素的click
)。
捕获则是从上层向下层传递,与冒泡相反。
(很是好记,你就想一想水底有一个泡泡从下面往上传的,因此是冒泡)
来看看这个例子:
<!-- 会依次执行 button li ul --> <ul onclick="alert('ul')"> <li onclick="alert('li')"> <button onclick="alert('button')">点击</button> </li> </ul> <script> window.addEventListener('click', function (e) { alert('window') }) document.addEventListener('click', function (e) { alert('document') }) </script> 复制代码
冒泡结果:button > li > ul > document > window
捕获结果:window > document > ul > li > button
并非全部的事件都有冒泡的,例如如下事件就没有:
onblur
onfocus
onmouseenter
onmouseleave
function myNew (fn, ...args) { let instance = Object.create(fn.prototype); let result = fn.call(instance, ...args) return typeof result === 'object' ? result : instance; } 复制代码
typeof
表示是对某个变量类型的检测,基本数据类型除了null
都能正常的显示为对应的类型,引用类型除了函数会显示为'function'
,其它都显示为object
。
而instanceof
它主要是用于检测某个构造函数的原型对象在不在某个对象的原型链上。
这只是 JS 存在的一个悠久 Bug。在 JS 的最第一版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头表明是对象然而 null 表示为全零,因此将它错误的判断为 object 。
instanceof
它主要是用于检测某个构造函数的原型对象在不在某个对象的原型链上。
算了,直接手写实现吧:
function myInstanceof (left, right) { let proto = Object.getPrototypeOf(left); while (true) { if (proto === null) return false; if (proto === right.prototype) return true; proto = Object.getPrototypeOf(proto) } } 复制代码
对于函数而言指向最后调用函数的那个对象,是函数运行时内部自动生成的一个内部对象,只能在函数内部使用;对于全局来讲,this
指向window
。
函数调用时,指向最后调用的那个对象
(答案参考童欧巴的一篇webpack
面试文章哦:「吐血整理」再来一打Webpack面试题(持续更新))
loader它是一个转换器,只专一于转换文件这一个领域,完成压缩、打包、语言编译,它仅仅是为了打包。而且运行在打包以前。
而plugin是一个扩展器,它丰富了webpack自己,为其进行一些其它功能的扩展。它不局限于打包,资源的加载,还有其它的功能。因此它是在整个编译周期都起做用。
HTTP的责任是去定义数据,在两台计算机相互传递信息时,HTTP规定了每段数据以什么形式表达才是可以被另一台计算机理解。
而TCP所要规定的是数据应该怎么传输才能稳定且高效的传递与计算机之间。
(还能够再扩展)
TCP为何可靠,是由于它有三次握手来保证双方都有接受和发送数据的能力。
字节流服务:将大块数据分割为以报文段为单位的数据包进行管理
虚拟DOM
本质就是用一个原生的JavaScript
对象去描述一个DOM
节点。是对真实DOM
的一层抽象。
因为在浏览器中操做DOM
是很昂贵的。频繁的操做DOM
,会产生必定的性能问题,所以咱们须要这一层抽象,在patch
过程当中尽量地一次性将差别更新到DOM
中,这样保证了DOM
不会出现性能不好的状况。
另外还有很重要的一点,也是它的设计初衷,为了更好的跨平tai,好比Node.js
就没有DOM
,若是想实现SSR
(服务端渲染),那么一个方式就是借助Virtual DOM
,由于Virtual DOM
自己是JavaScript
对象。
Vue2.x
中的虚拟DOM
主要是借鉴了snabbdom.js
,Vue3
中借鉴inferno.js
算法进行优化。
看三元的《(1.6w字)浏览器灵魂之问,请问你能接得住几个?》
分别从网络,解析,渲染来讲
面试的问题基本都答出来了,固然后面还有一个技术总监的电话面,主要是问了一些工做相关的问题。
其实这家公司开出的条件也挺让呆呆心动的,包括氛围感受也挺好,只不过可能还不是本身想要的吧,因此最终也是没去,挺惋惜的...若是面试个人那位小哥哥哥看到了这里,还请不要难过哈,咱们江湖会再见的😂。
4月27日
一面
并详细说一下前面三道
(嘻嘻,这个是呆呆留给大家的题目,考考大家,就不写答案了)
(实际上是呆呆当时只答出了前面三道😂)
this
指向问题,还有就是定时器它的执行机制以及eventLoop,再还有就是new
和不new
时this.num
的计算。JSONP
的了解,至于百万并发我写不出来能够理解。Node
因此直接摊牌了。二面
基本原理:主要就是利用 script
标签的src
属性没有跨域的限制,经过指向一个须要访问的地址,由服务端返回一个预先定义好的 Javascript
函数的调用,而且将服务器数据以该函数参数的形式传递过来,此方法须要先后端配合完成。
执行过程:
jsonpCallback = function (res) {}
)params
的形式包装script
标签的请求参数,而且声明执行函数(如cb=jsonpCallback
)jsonpCallback
),并以带上参数且调用执行函数的方式传递给前端script
标签返回资源的时候就会去执行jsonpCallback
并经过回调函数的方式拿到数据了。缺点:
GET
请求优势:
代码实现:
(具体能够看个人这篇文章:JSONP原理及实现)
<script> function JSONP({ url, params = {}, callbackKey = 'cb', callback }) { // 定义本地的惟一callbackId,如果没有的话则初始化为1 JSONP.callbackId = JSONP.callbackId || 1; let callbackId = JSONP.callbackId; // 把要执行的回调加入到JSON对象中,避免污染window JSONP.callbacks = JSONP.callbacks || []; JSONP.callbacks[callbackId] = callback; // 把这个名称加入到参数中: 'cb=JSONP.callbacks[1]' params[callbackKey] = `JSONP.callbacks[${callbackId}]`; // 获得'id=1&cb=JSONP.callbacks[1]' const paramString = Object.keys(params).map(key => { return `${key}=${encodeURIComponent(params[key])}` }).join('&') // 建立 script 标签 const script = document.createElement('script'); script.setAttribute('src', `${url}?${paramString}`); document.body.appendChild(script); // id自增,保证惟一 JSONP.callbackId++; } JSONP({ url: 'http://localhost:8080/api/jsonps', params: { a: '2&b=3', b: '4' }, callbackKey: 'cb', callback (res) { console.log(res) } }) JSONP({ url: 'http://localhost:8080/api/jsonp', params: { id: 1 }, callbackKey: 'cb', callback (res) { console.log(res) } }) </script> 复制代码
跨域的产生来源于现代浏览器所通用的同源策略
,所谓同源策略,是指只有在地址的:
均同样的状况下,才容许访问相同的cookie、localStorage,以及访问页面的DOM
或是发送Ajax
请求。若在不一样源的状况下访问,就称为跨域。
例如如下为同源:
http://www.example.com:8080/index.html http://www.example.com:8080/home.html 复制代码
如下为跨域:
http://www.example.com:8080/index.html http://www3.example.com:8080/index.html 复制代码
注意⚠️:
可是有两种状况:http
默认的端口号为80
,https
默认端口号为443
。
因此:
http://www.example.com:80 === http://www.example.com https://www.example.com:443 === https://www.example.com 复制代码
为何浏览器会禁止跨域?
简答:
首先,跨域只存在于浏览器端,由于咱们知道浏览器的形态是很开放的,因此咱们须要对它有所限制。
其次,同源策略主要是为了保证用户信息的安全,可分为两种:Ajax
同源策略和DOM
同源策略。
Ajax
同源策略主要是使得不一样源的页面不能获取cookie
且不能发起Ajax
请求,这样在必定层度上防止了CSRF
攻击。
DOM
同源策略也同样,它限制了不一样源页面不能获取DOM
,这样能够防止一些恶意网站在本身的网站中利用iframe
嵌入正gui的网站并迷惑用户,以此来达到窃取用户信息。
深答:
首先,跨域只存在于浏览器端。浏览器它为web
提供了访问入口,而且访问的方式很简单,在地址栏输入要访问的地址或者点击某个连接就能够了,正是这种开放的形态,因此咱们须要对它有所限制。
因此同源策略它的产生主要是为了保证用户信息的安全,防止恶意的网站窃取数据。分为两种:Ajax
同源策略与DOM
同源策略:
Ajax
同源策略它主要作了这两种限制:1.不一样源页面不能获取cookie
;2.不一样源页面不能发起Ajax
请求。我认为它是防止CSRF
攻击的一种方式吧。由于咱们知道cookie
这个东西它主要是为了解决浏览器与服务器会话状态的问题,它本质上是存储在浏览器或本地文件中一个小小的文本文件,那么它里面通常都会存储了用户的一些信息,包括隐私信息。若是没有Ajax
同源策略,恶意网站只须要一段脚本就能够获取你的cookie
,从而冒充你的身份去给其它网站发送恶意的请求。DOM
同源策略也同样,它限制了不一样源页面不能获取DOM
。例如一个假的网站利用iframe
嵌套了一个银行网站mybank.com,并把宽高或者其它部分调整的和原银行网站同样,仅仅只是地址栏上的域名不一样,如果用户没有注意的话就觉得这个是个真的网站。若是这时候用户在里面输入了帐号密码,若是没有同源策略,那么这个恶意网站就能够获取到银行网站中的DOM
,也就能拿到用户的输入内容以此来达到窃取用户信息的攻击。同源策略它算是浏览器安全的第一层屏障吧,由于就像CSRF
攻击,它只能限制不一样源页面cookie
的获取,可是攻击者还可能经过其它的方式来达到攻击效果。
(注,上面提到的iframe
限制DOM
查询,案例以下)
// HTML <iframe name="yinhang" src="www.yinhang.com"></iframe> // JS // 因为没有同源策略的限制,钓鱼网站能够直接拿到别的网站的Dom const iframe = window.frames['yinhang'] const node = iframe.document.getElementById('你输入帐号密码的Input') console.log(`拿到了这个${node},我还拿不到你刚刚输入的帐号密码吗`) 复制代码
参考:
跨域资源共享(CORS
)是一种机制,是W3C标准。它容许浏览器向跨源服务器,发出XMLHttpRequest
或Fetch
请求。而且整个CORS
通讯过程都是浏览器自动完成的,不须要用户参与。
而使用这种跨域资源共享
的前提是,浏览器必须支持这个功能,而且服务器端也必须赞成这种"跨域"
请求。所以实现CORS
的关键是服务器须要服务器。一般是有如下几个配置:
具体可看:developer.mozilla.org/zh-CN/docs/…
过程分析:
简单回答:
当咱们发起跨域请求时,若是是非简单请求,浏览器会帮咱们自动触发预检请求,也就是 OPTIONS 请求,用于确认目标资源是否支持跨域。若是是简单请求,则不会触发预检,直接发出正常请求。
浏览器会根据服务端响应的 header 自动处理剩余的请求,若是响应支持跨域,则继续发出正常请求,若是不支持,则在控制台显示错误。
详细回答:
浏览器先根据同源策略对前端页面和后台交互地址作匹配,若同源,则直接发送数据请求;若不一样源,则发送跨域请求。
服务器收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何容许跨域,则文件头里不包含 Access-Control-Allow-origin
字段,若配置过域名,则返回 Access-Control-Allow-origin + 对应配置规则里的域名的方式
。
浏览器根据接受到的 响应头里的 Access-Control-Allow-origin
字段作匹配,若无该字段,说明不容许跨域,从而抛出一个错误;如有该字段,则对字段内容和当前域名作比对,若是同源,则说明能够跨域,浏览器接受该响应;若不一样源,则说明该域名不可跨域,浏览器不接受该响应,并抛出一个错误。
在CORS
中有简单请求
和非简单请求
,简单请求是不会触发CORS
的预检请求的,而非简单请求会。
“需预检的请求”
要求必须首先使用 OPTIONS
方法发起一个预检请求到服务器,以获知服务器是否容许该实际请求。"预检请求“的使用,能够避免跨域请求对服务器的用户数据产生未预期的影响。
(关于更多CORS的内容能够看个人另外一篇文章:CORS原理及实现)
这个当时面试官和我说的是,中间会通过不少的站点,好比会通过湖南,或者其它城市,由各个城市的这些站点一层一层分发下去。
面的最惨的一次...由于此次面试是当天下午6点才去面的,在这以前呆呆已经通过了3轮面试的折磨,因此身心疲惫很不在状态。固然最主要的是本身确实准备的还不够充分,其实如今回过头来看看这些题都不太难的...
当天也小小的自闭了一下,整理好状态次日好好总结吧 😄。
4月28日
(当时是电话面,一个小时20分钟,问了我大概五六十道题,我能想到的一共是50题,还有一些记不起来了)
require()
方法;而ES6 Modules只能是字符串this
指向当前模块,ES6 Modules this
指向undefined
arguments
、require
、module
、exports
、__filename
、__dirname
关于第一个差别,是由于CommonJS 加载的是一个对象(即module.exports
属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
(具体能够看个人这篇文章:一篇不是标题党的CommonJS和ES6模块规范讲解)
模块的异步加载可使用AMD
或者CMD
规范。
(具体能够看个人这篇文章:一篇不是标题党的CommonJS和ES6模块规范讲解)
封闭开放式原则、安全性
(应该还有,可是没想到)
reduce
,初始值传入一个Promise.resolve()
,以后往里面不停的叠加.then()
。(相似于这里juejin.cn/post/684490…)forEach
,本质和reduce
原理相同。(相似于这里juejin.cn/post/684490…)ES9
中的for...await...of
来实现。并发的。不过Promise.all().then()
结果中数组的顺序和Promise.all()
接收到的数组顺序一致。
var trimReg = /(^\s+)|(\s+$)/g
;不事后来因为Vue
中有一个修饰符.trim
,使用起来更方便(如v-model.trim="msg"
)就用这种方式多一些;再或者也能够用ES10
新出的trimStart
和trimEnd
来去除首尾空格。var phoneReg = /^1[3456789]\d{9}$/g
。function getCookie(name) { var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)')); if (match) return unescape(match[2]); } 复制代码
(详细介绍能够看这里:每日一题-JS篇-根据name获取cookie中值的方法)
^
要是放在[]
里的话就表示"除了^后面的内容都能匹配"
,也就是非的意思。
例如:
(除了l
,其它都变成了"帅"
)
var str = 'lindaidai'; console.log(str.replace(/[^l]/g, '帅')); // l帅帅帅帅帅帅帅帅 复制代码
反之,若是是不在[]
里的话则表示开头匹配:
(只有l
变成了"帅"
)
var str = 'lindaidai'; console.log(str.replace(/^l/g, '帅')); 复制代码
hash
是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash
值都会更改,而且所有文件都共用相同的hash
值。(粒度整个项目)chunkhash
是根据不一样的入口进行依赖文件解析,构建对应的chunk
(模块),生成对应的hash
值。只有被修改的chunk
(模块)在从新构建以后才会生成新的hash
值,不会影响其它的chunk
。(粒度entry
的每一个入口文件)contenthash
是跟每一个生成的文件有关,每一个文件都有一个惟一的hash
值。当要构建的文件内容发生改变时,就会生成新的hash
值,且该文件的改变并不会影响和它同一个模块下的其它文件。(粒度每一个文件的内容)(具体能够看我简书上的这篇文章:www.jianshu.com/p/486453d81…)
这里只是说明了三种hash
的不一样...至于原理暂时没了解。
这个问题在上一个问题中已经说明了,要看webpack
的配置。
有三种状况:
hash
的话,是和整个项目有关的,有一处文件发生更改则全部文件的hash
值都会发生改变且它们共用一个hash
值;chunkhash
的话,只和entry
的每一个入口文件有关,也就是同一个chunk
下的文件有所改动该chunk
下的文件的hash
值就会发生改变contenthash
的话,和每一个生成的文件有关,只有当要构建的文件内容发生改变时才会给该文件生成新的hash
值,并不会影响其它文件。在webpack
中有两种处理图片的loader
:
file-loader
:解决CSS
等中引入图片的路径问题;(解决经过url
,import/require()
等引入图片的问题)url-loader
:当图片小于设置的limit
参数值时,url-loader
将图片进行base64
编码(当项目中有不少图片,经过url-loader
进行base64
编码后会减小http
请求数量,提升性能),大于limit参数值,则使用file-loader
拷贝图片并输出到编译目录中;(详细使用能够查看这里:霖呆呆的webpack之路-loader篇)
回流:
触发条件:
当咱们对 DOM 结构的修改引起 DOM 几何尺寸变化的时候,会发生回流
的过程。
例如如下操做会触发回流:
一个 DOM 元素的几何属性变化,常见的几何属性有width
、height
、padding
、margin
、left
、top
、border
等等, 这个很好理解。
使 DOM 节点发生增减
或者移动
。
读写 offset
族、scroll
族和client
族属性的时候,浏览器为了获取这些值,须要进行回流操做。
调用 window.getComputedStyle
方法。
回流过程:因为DOM的结构发生了改变,因此须要从生成DOM这一步开始,从新通过样式计算
、生成布局树
、创建图层树
、再到生成绘制列表
以及以后的显示器显示这整一个渲染过程走一遍,开销是很是大的。
重绘:
触发条件:
当 DOM 的修改致使了样式的变化,而且没有影响几何属性的时候,会致使重绘
(repaint
)。
重绘过程:因为没有致使 DOM 几何属性的变化,所以元素的位置信息不须要更新,因此当发生重绘的时候,会跳过生存布局树
和创建图层树
的阶段,直接到生成绘制列表
,而后继续进行分块、生成位图等后面一系列操做。
如何避免触发回流和重绘:
class
的方式。position
属性为absolute
或fixed
的元素上。display: none
,操做结束后再把它显示出来。由于在display
属性为none
的元素上进行的DOM操做不会引起回流和重绘createDocumentFragment
进行批量的 DOM 操做。transform
、opacity
、filter
这些属性能够实现合成的效果,也就是GPU
加速。box-sizing: content-box
(W3C盒模型,又名标准盒模型):元素的宽高大小表现为内容的大小。
box-sizing: border-box
(IE盒模型,又名怪异盒模型):元素的宽高表现为内容 + 内边距 + 边框的大小。背景会延伸到边框的外沿。
这里我是按照子弈的总结答的: juejin.cn/post/684490…
.box { display: flex; width: 100px; height: 100px; background-color: pink; } .box-center{ margin: auto; background-color: greenyellow; } 复制代码
.box { display: flex; width: 100px; height: 100px; background-color: pink; justify-content: center; align-items: center; } .box-center{ background-color: greenyellow; } 复制代码
.box { position: relative; height: 100px; width: 100px; background-color: pink; } .box-center{ position: absolute; left: 0; right: 0; bottom: 0; top: 0; margin: auto; width: 50px; height: 50px; background-color: greenyellow; } 复制代码
简单回答:
IE6~9
不支持,IE10~11
部分支持flex的2012版
,可是须要-ms-
前缀。
其它的主流浏览器包括安卓和IOS
基本上都支持了。
详细回答:
能够到Can I use
上去查看,官网地址为:caniuse.com/
比较经常使用的:
em
:定义字体大小时以父级的字体大小为基准;定义长度单位时以当前字体大小为基准。例父级font-size: 14px
,则子级font-size: 1em;
为font-size: 14px;
;若定义长度时,子级的字体大小若是为14px
,则子级width: 2em;
为width: 24px
。rem
:以根元素的字体大小为基准。例如html
的font-size: 14px
,则子级1rem = 14px
。%
:以父级的宽度为基准。例父级width: 200px
,则子级width: 50%;height:50%;
为width: 100px;height: 100px;
vw和vh
:基于视口的宽度和高度(视口不包括浏览器的地址栏工具栏和状态栏)。例如视口宽度为1000px
,则60vw = 600px;
vmin和vmax
:vmin
为当前vw
和vh
中较小的一个值;vmax
为较大的一个值。例如视口宽度375px
,视口高度812px
,则100vmin = 375px;
,100vmax = 812px;
不经常使用的:
ex和ch
:ex
以字符"x"
的高度为基准;例如1ex
表示和字符"x"
同样长。ch
以数字"0"
的宽度为基准;例如2ch
表示和2个数字"0"
同样长。移动端布局总结:
(总结来源:玲珑)
em:
定义字体大小时以父级的字体大小为基准;定义长度单位时以当前字体大小为基准。例父级font-size: 14px
,则子级font-size: 1em;
为font-size: 14px;
;若定义长度时,子级的字体大小若是为14px
,则子级width: 2em;
为width: 24px
。
rem:
以根元素的字体大小为基准。例如html
的font-size: 14px
,则子级1rem = 14px
。
一个简易版的初始化根元素字体大小。
页面开头处引入下面这段代码,用于动态计算font-size
:
(假设你须要的1rem = 20px
)
(function () { var html = document.documentElement; function onWindowResize() { html.style.fontSize = html.getBoundingClientRect().width / 20 + 'px'; } window.addEventListener('resize', onWindowResize); onWindowResize(); })(); 复制代码
document.documentElement
:获取document
的根元素html.getBoundingClientRect().width
:获取html
的宽度(窗口的宽度)window
的resize
事件通常还须要配合一个meta
头:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-sacle=1.0, maximum-scale=1.0, user-scalable=no" /> 复制代码
若是没有人为取改变根元素字体大小的话,默认是1rem = 16px
;根元素默认的字体大小是16px
。
实话实说没太作过。
css代码:
<style> .box { width: 100px; height: 100px; background-color: red; animation: spin 2s linear infinite; } @keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } } </style> 复制代码
html代码:
<div class="box"></div> 复制代码
语法:
animation: name duration timing-function delay iteration-count direction; 复制代码
值 | 描述 |
---|---|
animation-name | 规定须要绑定到选择器的 keyframe 名称。(mymove) |
animation-duration | 规定完成动画所花费的时间,以秒或毫秒计。(2s) |
animation-timing-function | 规定动画的速度曲线。(ease|linear|ease-in|cubic-bezier(n,n,n,n)) |
animation-delay | 规定在动画开始以前的延迟。(2s) |
animation-iteration-count | 规定动画应该播放的次数。(n | infinite) n次/无限 |
animation-direction | 规定是否应该轮流反向播放动画。(normal | alternate) 正常/反向 |
一句话介绍:steps()
功能符可让动画不连续。
地位和做用:和贝塞尔曲线(cubic-bezier()
修饰符)同样,均可以做为animation
的第三个属性值。
和贝塞尔曲线的区别:贝塞尔曲线像是滑梯且有4个关键字(参数),而steps
像是楼梯坡道且只有number
和position
两个关键字。
语法:
steps(number, position)
复制代码
start
和end
两个关键字,含义分别以下:
start
:表示直接开始。end
:表示戛然而止。是默认值。具体能够看这里:www.zhangxinxu.com/wordpress/2…
Chrome
浏览器 -> more tools
-> Remote devices
-> chrome://inspect/#devices
Mac
+ IOS
+ Safari
V8引擎帮助咱们实现了自动的垃圾回收管理,利用浏览器渲染页面的空闲时间进行垃圾回收。
(这里我用的是:juejin.cn/post/684490… 里的总结)
栈内存的回收:
栈内存调用栈上下文切换后就被回收,比较简单。
堆内存的回收:
V8的堆内存分为新生代内存和老生代内存,新生代内存是临时分配的内存,存在时间短,老生代内存存在时间长。
新生代内存回收机制:
老生代内存回收机制
(固然想要详细了解的话也能够看个人这篇文章:JavaScript进阶-内存机制(表情包初探))
因为我在项目中是会对axios
作一层封装,因此每次请求的域名也是写在配置文件中,有一个baseURL
字段专门用于存储它,因此只要改这个字段就能够达到替换全部请求http
为https
了。
固然后面我也有了解到:
利用meta
标签把http
请求换为https
:
<meta http-equiv ="Content-Security-Policy" content="upgrade-insecure-requests"> 复制代码
参考上一题👆。
在浏览器和服务器进行传输的时候,能够被nginx
代理所拦截,也能够被网关拦截。
HTTPS主要是采用对称密钥加密和非对称密钥加密组合而成的混合加密机制进行传输。
也就是发送密文的一方用"对方的公钥"进行加密处理"对称的密钥",而后对方在收到以后使用本身的私钥进行解密获得"对称的密钥",这在确保双发交换的密钥是安全的前提下使用对称密钥方式进行通讯。
对称密钥加密和非对称密钥加密都有它们各类的优缺点,而混合加密机制就是将二者结合利用它们各自的优势来进行加密传输。
好比既然对称密钥的优势是加解密效率快,那么在客户端与服务端肯定了链接以后就能够用它来进行加密传输。不过前提是得解决双方都能安全的拿到这把对称密钥。这时候就能够利用非对称密钥加密来传输这把对称密钥,由于咱们知道非对称密钥加密的优势就是能保证传输的内容是安全的。
因此它的好处是即保证了对称密钥能在双方之间安全的传输,又能使用对称加密方式进行通讯,这比单纯的使用非对称加密通讯快了不少。以此来解决了HTTP中内容可能被窃听的问题。
其它HTTP相关的问题:
如:
HTTPS的工做流程
混合加密机制的好处
数字签名
ECDHE握手和RSA握手
向前安全性
这些问题均可以看到个人这篇文章:HTTPS面试问答
这道题主要能够从数字签名
和数字证书
上来答。
当时我答的时候就把证书的颁发流程
、HTTPS
数字证书的验证过程完整的说了一遍就算过了。
具体能够看HTTPS面试问答中的第五、六、7
问。
这个无非就是配合If-None-Match
来达到一个协商缓存
的做用。值为服务器某个资源的惟一标识。
具体能够看个人这篇文章:霖呆呆你来讲说浏览器缓存吧
Token
其实就是访问资源的凭证。
通常是用户经过用户名和密码登陆成功以后,服务器将登录凭证作数字签名,加密以后获得的字符串做为token
。
它在用户登陆成功以后会返回给客户端,客户端主要有这么几种存储方式:
localStorage
中,每次调用接口的时候都把它当成一个字段传给后台cookie
中,让它自动发送,不过缺点就是不能跨域localStorage
中,每次调用接口的时候放在HTTP
请求头的Authorization
字段里(很明显我答的不够专业,欢迎补充,感谢😊)
(很明显我答的不够专业,欢迎补充,感谢😊)
用户登陆成功以后的一些信息
(很明显我答的不够专业,欢迎补充,感谢😊)
(很明显我答的不够专业,欢迎补充,感谢😊)
(很明显我答的不够专业,欢迎补充,感谢😊)
只会配置一些跨域方面的问题。
events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; location / { proxy_pass http://localhost:8887; add_header Access-Control-Allow-Origin *; } } } 复制代码
利用ngnix跨域的关键就是在配置文件中设置server
项,而后设置其中的location
属性,proxy_pass
:须要代理的服务器地址,add_header:给响应报文中添加首部字段,例如Access-Control-Allow-Origin
设置为*
,即容许全部的请求源请求。
具体能够看:Yiming君-面试题:nginx有配置过吗?反向代理知道吗?
咱们将请求发送到服务器,而后服务器对咱们的请求进行转发,咱们只须要和代理服务器进行通讯就好。因此对于客户端来讲,是感知不到服务器的。
唔...没有...
(...默默的点头)
唔...知道...
这里我是按照:
中的第13题答的。
放在methods
中,由于computed
会有惰性,并不能知道new Date()
的改变。
小小的写了一篇文章,能够看这里:数据权限如何控制
和面试官扯了一堆我数据权限判断的具体过程,其中可能有多个权限:并的状况000011110001&000011110002
,或的状况000011110001|000011110002
,以及如何作的权限匹配。最后面试官:
"因此那仍是用的字符串匹配咯?"
尬...我比较low
...用的字符串匹配...
(哇,真的绝了...1个小时20分钟50多道题,答的我口渴😂,不过也能够看出有不少移动端的我都没有答上来,面试官也表示理解,毕竟我主要是以PC端为主,因此居然也算是过了,很感谢这位面试官细心的帮我分析一些问题)
后来有了解这位面试官近期也跳槽去腾讯了,果真面完呆呆以后他就去大厂了,好人一辈子平安😂。
这家公司实际上是上家公司的总部,由于面完上家以后,HR也知道个人顾虑,想要去一个大点的团队,因此就把我推荐去了他们的总部。很是Nice的HR小姐姐,好感动,就算你看不到个人文章,我也仍是要感谢你 😂。
5月8日
一面(前端副总监)
(必问...)
看三元的《(1.6w字)浏览器灵魂之问,请问你能接得住几个?》
分别从网络,解析,渲染来讲
JS
代码在加载完以后是当即执行的,且JS
代码执行时会阻塞页面的渲染。
JS属于单线程,当咱们在加载script
标签内容的时候,渲染线程会被暂停,由于script
标签里可能会操做DOM
的,因此若是你加载script
标签又同时渲染页面确定就冲突了,所以说渲染线程(GUI
)和js引擎线程互斥。
Last-Modefied
配合If-Modified-Since
ETag
配合If-None-Match
也是个常见的问题了,不了解的小伙伴能够看个人这篇文章:霖呆呆你来讲说浏览器缓存吧
(当时面试官还重复了一下我说的这4个头部字段,本身回顾了一下我说的对不对,好可爱~)
Keep-Alive
是HTTP
的一个头部字段Connection
中的一个值,它是保证咱们的HTTP
请求能创建一个持久链接。也就是说创建一次TCP
链接便可进行屡次请求和响应的交互。它的特色就是只要有一方没有明确的提出断开链接,则保持TCP
链接状态,减小了TCP
链接和断开形成的额外开销。
另外,在HTTP/1.1
中全部的链接默认都是持久链接的,可是HTTP/1.0
并未标准化。
我工做中碰到主要是利用CORS
来解决跨域问题,说了一下它的原理以及后台须要如何作。
另外说到了JSONP
的原理,以及它的优势:兼容性好;缺点:只能进行GET
请求,且有安全问题。
还有说到了ngnix
反向代理来解决跨域。
其它的,我当时说我有看过一篇文章里面详细的介绍10多种跨域解决方案,可是本身没有过多的去了解。
哈哈,其实也就是秋风大大的这篇文章10种跨域解决方案(附终极大招)
这个当时答的没用过。
我知道它是能使得客户端和服务器之间存在持久的链接,并且双方均可以随时开始发送数据,这种方式本质没有使用 HTTP 的响应头,所以也没有跨域的限制。
(多的不会了)
(必问...)
(如下回答参考子弈小哥哥的面试分享:两年工做经验成功面试阿里P6总结
以及蔡徐坤小哥哥的2万字 | 前端基础拾遗90问)
XSS
XSS(Cross Site Script)跨站脚本攻击。指的是攻击者向网页注入恶意的客户端代码,经过恶意的脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
主要是分为三种:
存储型:即攻击被存储在服务端,常见的是在评论区插入攻击脚本,若是脚本被储存到服务端,那么全部看见对应评论的用户都会受到攻击。
反射型:攻击者将脚本混在URL里,服务端接收到URL将恶意代码当作参数取出并拼接在HTML里返回,浏览器解析此HTML后即执行恶意代码
DOM型:将攻击脚本写在URL中,诱导用户点击该URL,若是URL被解析,那么攻击脚本就会被运行。和前二者的差异主要在于DOM型攻击不通过服务端
如何防护XSS攻击
script
和<iframe>
等标签进行转义或者过滤CSRF
CSRF攻击(Cross-site request forgery)跨站请求伪造。是一种劫持受信任用户向服务器发送非预期请求的攻击方式,一般状况下,它是攻击者借助受害者的 Cookie 骗取服务器的信任,可是它并不能拿到Cookie,也看不到Cookie的内容,它能作的就是给服务器发送请求,而后执行请求中所描述的命令,以此来改变服务器中的数据,也就是并不能窃取服务器中的数据。
防护主要有三种:
验证Token
:浏览器请求服务器时,服务器返回一个token,每一个请求都须要同时带上token和cookie才会被认为是合法请求
验证Referer
:经过验证请求头的Referer来验证来源站点,但请求头很容易伪造
设置SameSite
:设置cookie的SameSite,可让cookie不随跨站请求发出,但浏览器兼容不一
点击挟持
预防策略:
top.location.hostname === self.location.hostname
;(这个来源于LuckyWinty: www.imooc.com/article/295…)
(必问...)
(回答参考:juejin.cn/post/684490…)
setTimeout
的运行机制:执行该语句时,是当即把当前定时器代码推入事件队列,当定时器在事件列表中知足设置的时间值时将传入的函数加入任务队列,以后的执行就交给任务队列负责。可是若是此时任务队列不为空,则需等待,因此执行定时器内代码的时间可能会大于设置的时间
说了一下它属于异步任务,而后说了一下还有哪些宏任务以及微任务,最后说了一下EventLoop
的执行过程。
一开始整个脚本做为一个宏任务执行
执行过程当中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
当前宏任务执行完出队,检查微任务列表,有则依次执行,直到所有执行完
执行浏览器UI线程的渲染工做
检查是否有Web Worker
任务,有则执行
执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
(具体能够看这里:juejin.cn/post/684490…
(啪啪啪,不长记性,其实以前面试有被问过,可是忘了再去了解了,这就吃亏了,没答上来)
requestAnimationFrame
是浏览器用于定时循环操做的一个接口,相似于setTimeout
,主要用途是按帧对网页进行重绘。对于JS
动画,用requestAnimationFrame
会比 setInterval
效果更好。
具体能够看:juejin.cn/post/684490…
同上...
(下面看着不少,但我确定不是全答哈,挑了几个来回答)
ES6
:
Class
模块import
和export
箭头函数
函数默认参数
...
扩展运输符容许展开数组
解构
字符串模版
Promise
let const
Proxy、Map、Set
对象属性同名能简写
ES7
:
includes
**
求幂运算符
ES8
:
async/await
Object.values()和Object.entries()
padStart()和padEnd()
Object.getOwnPropertyDescriptors()
,
ES9
:
for...await...of
...
展开符合容许展开对象收集剩余参数Promise.finally()
ES10
:
flat()
flatMap()
fromEntries()
trimStart
和trimEnd
matchAll
BigInt
try/catch
中报错容许没有err
异常参数Symbol.prototype.description
Function.toString()
调用时呈现本来源码的样子(还不了解的小伙伴能够看看浪里哥的这篇:盘点ES七、ES八、ES九、ES10新特性)
实话实话没作过,可是后来面试官告诉我:可使用canvas
来实现。具体作法等我写篇文章哈。
(当时我还反问了一句面试官:那批量图片压缩要怎么作呢?把他惊的...而后他和我说挺复杂的...)
1个前端(我),1个小程序老哥(IOS转行的),6个后台。
例举了我最经典的bpmn.js
,以此来引出我写了不少关于这方面的教材,以及创建了微信群,为国内的bpmn.js
社区贡献了一份力量...怎么高大上怎么来...
固然也有提到我GitHub
上的bpmn-chinese-document
项目只有100
多的Star
,他说理解,毕竟这东西用的人不是不少。
喊了个挺高的数,老哥笑了笑,你这个工做年限咱们可能给不到,而后扯了点别的。
(其实后面这些问题应该是等到HR面的时候问的,可是感受和面试官挺聊的来的我就先打听了)
二面(CTO)
绝了...又来
绝了...又来X2
当时答的是是用import
来按需引入,以及提到了Vue.use
。
但后来有去了解,babel-plugin-import
就能够实现。
估计面试官看错了...虽然个人项目有个组件库的功能,可是是基于Ant Design of Vue
二次开发的。
没了...
三面(HR)
问的问题有点多,我挑一些记得住的哈
(还有不少大佬的不少好文,不是呆呆不写在这里啊,是由于呆呆暂时只刷了这些,抱歉了😂)
你盼世界,我盼望你无bug
。这篇文章就介绍到了这里。
有总结的不足的地方还喜欢小伙伴能在评论区留言。
我是一只正在努力求生存的呆呆,也在这条路上不断的总结和成长,但愿本身可以坚持✊。
"风浪没平息 我宣告奔跑的意义"
"这不是叛逆 我只是淋了一场雨"
喜欢霖呆呆的小伙还但愿能够关注霖呆呆的公众号 LinDaiDai
或者扫一扫下面的二维码👇👇👇.
我会不定时的更新一些前端方面的知识内容以及本身的原创文章🎉
你的鼓励就是我持续创做的主要动力 😊.
相关推荐:
《【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)》
《【建议👍】再来40道this面试题酸爽继续(1.2w字用手整理)》
《【何不三连】比继承家业还要简单的JS继承题-封装篇(牛刀小试)》