先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
「先用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日上午
(从这家公司开始面试稍微有些难度了,面试官小哥哥人也很好,刚开始是一个高冷男神,但是在呆呆的猛烈回答下终于还是对我露出了微笑???,还说他也是掘友,有看过我的文章…掘友真是无处不在啊,感动???)
1. 描述一下Promise
这道题我会先大概介绍一下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
捕获;但并不会影响数组中其它的异步任务的执行。
2. Promise.all中如果有一个抛出异常了会如何处理
这个,在上一题已经说到了:
all和race
传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then
的第二个参数或者后面的catch
捕获;但并不会影响数组中其它的异步任务的执行。
3. Promise为什么能链式调用
由于它的then
方法和catch、finally
方法会返回一个新的Promise
所以可以允许我们链式调用
4. 描述一下EventLoop的执行过程
-
一开始整个脚本作为一个宏任务执行
-
执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
-
当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
-
执行浏览器UI线程的渲染工作
-
检查是否有
Web Worker
任务,有则执行 -
执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
(具体可以看这里:https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-1)
5. docoment,window,html,body的层级关系
「层级关系」:
window > document > html > body
-
window
是BOM
的核心对象,它一方面用来获取或设置浏览器的属性和行为,另一方面作为一个全局对象。 -
document
对象是一个跟文档相关的对象,拥有一些操作文档内容的功能。但是地位没有window
高。 -
html
元素对象和document
元素对象是属于html
文档的DOM
对象,可以认为就是html
源代码中那些标签所化成的对象。他们跟div、select
什么对象没有根本区别。
(我是这样记的,整个浏览器中最大的肯定就是窗口window
了,那么进来的我不管你是啥,就算你是document
也得给我盘着)
6. addEventListener函数的第三个参数
第三个参数涉及到冒泡和捕获,是true
时为捕获,是false
则为冒泡
7. 有写过原生的自定义事件吗
-
使用
Event
-
使用
customEvent
(可以传参数) -
使用
document.createEvent('CustomEvent')和initCustomEvent()
「创建自定义事件」
原生自定义事件有三种写法:
- 使用
Event
let myEvent = new Event(‘event_name’);
- 使用
customEvent
(可以传参数)
let myEvent = new CustomEvent(‘event_name’, {
detail: {
// 将需要传递的参数放到这里
// 可以在监听的回调函数中获取到:event.detail
}
})
- 使用
document.createEvent('CustomEvent')和initCustomEvent()
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)
8. 冒泡和捕获的具体过程
冒泡指的是:当给某个目标元素绑定了事件之后,这个事件会依次在它的父级元素中被触发(当然前提是这个父级元素也有这个同名称的事件,比如子元素和父元素都绑定了click
事件就触发父元素的click
)。
捕获则是从上层向下层传递,与冒泡相反。
(非常好记,你就想想水底有一个泡泡从下面往上传的,所以是冒泡)
来看看这个例子:
点击
冒泡结果:
button > li > ul > document > window
捕获结果:
window > document > ul > li > button
9. 所有的事件都有冒泡吗?
并不是所有的事件都有冒泡的,例如以下事件就没有:
-
onblur
-
onfocus
-
onmouseenter
-
onmouseleave
11. 描述下原型链
12. 手写new
function myNew (fn, …args) {
let instance = Object.create(fn.prototype);
let result = fn.call(instance, …args)
return typeof result === ‘object’ ? result : instance;
}
13. typeof和instanceof的区别
typeof
表示是对某个变量类型的检测,基本数据类型除了null
都能正常的显示为对应的类型,引用类型除了函数会显示为'function'
,其它都显示为object
。而
instanceof
它主要是**「用于检测某个构造函数的原型对象在不在某个对象的原型链上」**。14. typeof为什么对null错误的显示
这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object 。
15. 详细说下instanceof
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)
}
}
16. 一句话描述一下this
指向最后调用函数的那个对象,是函数运行时内部自动生成的一个内部对象,只能在函数内部使用
17. 函数内的this是在什么时候确定的?
函数调用时,指向最后调用的那个对象
18. apply/call/bind的相同和不同
19. webpack中的loader和plugin有什么区别
(答案参考童欧巴的一篇
webpack
面试文章哦:「吐血整理」再来一打Webpack面试题(持续更新))loader它是一个转换器,只专注于转换文件这一个领域,完成压缩、打包、语言编译,「它仅仅是为了打包」。并且运行在打包之前。
而plugin是一个扩展器,它丰富了webpack本身,为其进行一些其它功能的扩展。「它不局限于打包,资源的加载,还有其它的功能」。所以它是在整个编译周期都起作用。
20. HTTP和TCP的不同
HTTP的责任是去定义数据,在两台计算机相互传递信息时,HTTP规定了每段数据以什么形式表达才是能够被另外一台计算机理解。
而TCP所要规定的是数据应该怎么传输才能稳定且高效的传递与计算机之间。
(还可以再扩展)
21. TCP和UDP的区别
-
TCP是一个面向连接的、可靠的、基于字节流的传输层协议。
-
UDP是一个面向无连接的传输层协议。
TCP为什么可靠,是因为它有三次握手来保证双方都有接受和发送数据的能力。
字节流服务:将大块数据分割为以报文段为单位的数据包进行管理
22. 介绍一下虚拟DOM
虚拟
DOM
本质就是用一个原生的JavaScript
对象去描述一个DOM
节点。是对真实DOM
的一层抽象。由于在浏览器中操作
DOM
是很昂贵的。频繁的操作DOM
,会产生一定的性能问题,因此我们需要这一层抽象,在patch
过程中尽可能地一次性将差异更新到DOM
中,这样保证了DOM
不会出现性能很差的情况。另外还有很重要的一点,也是它的设计初衷,为了更好的跨平台,比如
Node.js
就没有DOM
,如果想实现SSR
(服务端渲染),那么一个方式就是借助Virtual DOM
,因为Virtual DOM
本身是JavaScript
对象。Vue2.x
中的虚拟DOM
主要是借鉴了snabbdom.js
,Vue3
中借鉴inferno.js
算法进行优化。23. 盒模型
24. 输入URL到页面的呈现
看三元的《(1.6w字)浏览器灵魂之问,请问你能接得住几个?》
https://juejin.im/post/5df5bcea6fb9a016091def69
分别从网络,解析,渲染来说
面试的问题基本都答出来了,当然后面还有一个技术总监的电话面,主要是问了一些工作相关的问题。
其实这家公司开出的条件也挺让呆呆心动的,包括氛围感觉也挺好,只不过可能还不是自己想要的吧,所以最终也是没去,挺可惜的…如果面试我的那位小哥哥哥看到了这里,还请不要难过哈,我们江湖会再见的???。
深圳某房地产公司
4月27日
一面
5道笔试题
并详细说一下前面三道
(额,呆呆能力有限只答出来了前面三道)
二面
1. JSON的原理以及手写一个实现
基本原理:主要就是利用
script
标签的src
属性没有跨域的限制,通过指向一个需要访问的地址,由服务端返回一个预先定义好的Javascript
函数的调用,并且将服务器数据以该函数参数的形式传递过来,此方法需要前后端配合完成。执行过程:
-
前端定义一个解析函数(如:
jsonpCallback = function (res) {}
) -
通过
params
的形式包装script
标签的请求参数,并且声明执行函数(如cb=jsonpCallback
) -
后端获取到前端声明的执行函数(
jsonpCallback
),并以带上参数且调用执行函数的方式传递给前端 -
前端在
script
标签返回资源的时候就会去执行jsonpCallback
并通过回调函数的方式拿到数据了。
缺点:
- 只能进行
GET
请求
优点:
- 兼容性好,在一些古老的浏览器中都可以运行
代码实现:
(具体可以看我的这篇文章:JSONP原理及实现:https://www.jianshu.com/p/88bb82718517)
2. 浏览器为什么要跨域?如果是因为安全的话那小程序或者其他的为什么没有跨域?
跨域的产生来源于现代浏览器所通用的
同源策略
,所谓同源策略,是指只有在地址的:-
协议名
-
域名
-
端口名
均一样的情况下,才允许访问相同的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
嵌入正规的网站并迷惑用户,以此来达到窃取用户信息。「深答」:
-
首先,跨域只存在于浏览器端。浏览器它为
web
提供了访问入口,并且访问的方式很简单,在地址栏输入要访问的地址或者点击某个链接就可以了,正是这种**「开放的形态」**,所以我们需要对它有所限制。 -
所以同源策略它的产生主要是为了保证用户信息的安全,防止恶意的网站窃取数据。分为两种:
Ajax
同源策略与DOM
同源策略:
同源策略它算是浏览器安全的第一层屏障吧,因为就像
CSRF
攻击,它只能限制不同源页面cookie
的获取,但是攻击者还可能通过其它的方式来达到攻击效果。(注,上面提到的
iframe
限制DOM
查询,案例如下)// HTML
// JS
// 由于没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom
const iframe = window.frames[‘yinhang’]
const node = iframe.document.getElementById(‘你输入账号密码的Input’)
console.log(
拿到了这个${node},我还拿不到你刚刚输入的账号密码吗
)-
Ajax
同源策略它主要做了这两种限制:1.不同源页面不能获取cookie
;2.不同源页面不能发起Ajax
请求。我认为它是防止CSRF
攻击的一种方式吧。因为我们知道cookie
这个东西它主要是为了解决浏览器与服务器会话状态的问题,它本质上是存储在浏览器或本地文件中一个小小的文本文件,那么它里面一般都会存储了用户的一些信息,包括隐私信息。如果没有Ajax
同源策略,恶意网站只需要一段脚本就可以获取你的cookie
,从而冒充你的身份去给其它网站发送恶意的请求。
-
DOM
同源策略也一样,它限制了不同源页面不能获取DOM
。例如一个假的网站利用iframe
嵌套了一个银行网站mybank.com,并把宽高或者其它部分调整的和原银行网站一样,仅仅只是地址栏上的域名不同,若是用户没有注意的话就以为这个是个真的网站。如果这时候用户在里面输入了账号密码,如果没有同源策略,那么这个恶意网站就可以获取到银行网站中的DOM
,也就能拿到用户的输入内容以此来达到窃取用户信息的攻击。
参考:
-
https://segmentfault.com/a/1190000015597029
-
https://juejin.im/post/5cad99796fb9a068ab40a29a
3. CORS跨域的原理
跨域资源共享(
CORS
)是一种机制,是W3C标准。它允许浏览器向跨源服务器,发出XMLHttpRequest
或Fetch
请求。并且整个CORS
通信过程都是浏览器自动完成的,不需要用户参与。而使用这种
跨域资源共享
的前提是,浏览器必须支持这个功能,并且服务器端也必须同意这种"跨域"
请求。因此实现CORS
的关键是服务器需要服务器。通常是有以下几个配置:-
「Access-Control-Allow-Origin」
-
「Access-Control-Allow-Methods」
-
「Access-Control-Allow-Headers」
-
「Access-Control-Allow-Credentials」
-
「Access-Control-Max-Age」
具体可看:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
过程分析:
「简单回答」:
-
当我们发起跨域请求时,「如果是非简单请求」,浏览器会帮我们自动触发预检请求,也就是 OPTIONS 请求,用于确认目标资源是否支持跨域。「如果是简单请求,则不会触发预检,直接发出正常请求。」
-
浏览器会根据服务端响应的 header 自动处理剩余的请求,如果响应支持跨域,则继续发出正常请求,如果不支持,则在控制台显示错误。
「详细回答」:
-
浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求;若不同源,则发送跨域请求。
-
服务器收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含
Access-Control-Allow-origin
字段,若配置过域名,则返回Access-Control-Allow-origin + 对应配置规则里的域名的方式
。 -
浏览器根据接受到的 响应头里的
Access-Control-Allow-origin
字段做匹配,若无该字段,说明不允许跨域,从而抛出一个错误;若有该字段,则对字段内容和当前域名做比对,如果同源,则说明可以跨域,浏览器接受该响应;若不同源,则说明该域名不可跨域,浏览器不接受该响应,并抛出一个错误。
在
CORS
中有简单请求
和非简单请求
,简单请求是不会触发CORS
的预检请求的,而非简单请求会。“需预检的请求”
要求必须首先使用OPTIONS
方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。(关于更多CORS的内容可以看我的另一篇文章:CORS原理及实现:https://www.jianshu.com/p/b2bdf55e1bf5)
4. CORS预请求OPTIONS就一定是安全的吗?
5. 在深圳的网页上输入百度,是怎么把这个请求发到北京的
这个当时面试官和我说的是,中间会经过很多的站点,比如会经过湖南,或者其它城市,由各个城市的这些站点一层一层分发下去。
6. 输入URL到页面的呈现
7. Vue的响应式原理
8. 那在这个响应式中一个数据改变它是怎么通知要更新的,也就是如何把数据和页面关联起来?
面的最惨的一次…因为这次面试是当天下午6点才去面的,在这之前呆呆已经经过了3轮面试的折磨,所以身心疲惫很不在状态。当然最主要的是自己确实准备的还不够充分,其实现在回过头来看看这些题都不太难的…
当天也小小的自闭了一下,整理好状态第二天好好总结吧 ???。
深圳某海外直播公司
4月28日
(当时是电话面,一个小时20分钟,问了我大概五六十道题,我能想到的一共是50题,还有一些记不起来了)
1. CommonJS和ES6模块的区别
-
CommonJS模块是运行时加载,ES6 Modules是编译时输出接口
-
CommonJS输出是值的拷贝;ES6 Modules输出的是值的引用,被输出模块的内部的改变会影响引用的改变
-
CommonJs导入的模块路径可以是一个表达式,因为它使用的是
require()
方法;而ES6 Modules只能是字符串 -
CommonJS
this
指向当前模块,ES6 Modulesthis
指向undefined
-
且ES6 Modules中没有这些顶层变量:
arguments
、require
、module
、exports
、__filename
、__dirname
关于第一个差异,是因为CommonJS 加载的是一个对象(即
module.exports
属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。(具体可以看我的这篇文章:https://juejin.im/post/5eaacd175188256d4345ea3a)
2. 模块的异步加载
模块的异步加载可以使用
AMD
或者CMD
规范。(具体可以看我的这篇文章:https://juejin.im/post/5eaacd175188256d4345ea3a)
3. 开发一个模块要考虑哪些问题?
封闭开放式原则、安全性
(应该还有,但是没想到)
4. 实现一个一组异步请求按顺序执行你有哪些方法?
-
利用
reduce
,初始值传入一个Promise.resolve()
,之后往里面不停的叠加.then()
。(类似于这里https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-51) -
利用
forEach
,本质和reduce
原理相同。(类似于这里https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-53) -
还可以用
ES9
中的for...await...of
来实现。
5. Promise.all()是并发的还是串行的?
并发的。不过
Promise.all().then()
结果中数组的顺序和Promise.all()
接收到的数组顺序一致。6. 平时写过哪些正则表达式
-
之前有用过用正则去除输入框的首尾空格,正则表达式为:
var trimReg = /(^\s+)|(\s+$)/g
;不过后来由于Vue
中有一个修饰符.trim
,使用起来更方便(如v-model.trim="msg"
)就用这种方式多一些;再或者也可以用ES10
新出的trimStart
和trimEnd
来去除首尾空格。 -
用于校验手机号的正则:
var phoneReg = /^1[3456789]\d{9}$/g
。 -
用正则写一个根据name获取cookie中的值的方法:
function getCookie(name) {
var match = document.cookie.match(new RegExp(‘(^| )’ + name + ‘=([^;]*)’));
if (match) return unescape(match[2]);
}
详细介绍可以看这里:每日一题-JS篇-根据name获取cookie中值的方法:https://github.com/LinDaiDai/niubility-coding-js/blob/master/%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98-JS%E7%AF%87.md#%E7%94%A8%E6%AD%A3%E5%88%99%E5%86%99%E4%B8%80%E4%B8%AA%E6%A0%B9%E6%8D%AEname%E8%8E%B7%E5%8F%96cookie%E4%B8%AD%E7%9A%84%E5%80%BC%E7%9A%84%E6%96%B9%E6%B3%95
7. 正则里的非如何实现的
^
要是放在[]
里的话就表示"除了^后面的内容都能匹配"
,也就是非的意思。例如:
(除了
l
,其它都变成了"帅"
)var str = ‘lindaidai’;
console.log(str.replace(/[^l]/g, ‘帅’));
// l帅帅帅帅帅帅帅帅
反之,如果是不在
[]
里的话则表示开头匹配:(只有
l
变成了"帅"
)var str = ‘lindaidai’;
console.log(str.replace(/^l/g, ‘帅’));
8. webpack几种hash的实现原理
-
hash
是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash
值都会更改,并且全部文件都共用相同的hash
值。(粒度整个项目) -
chunkhash
是根据不同的入口进行依赖文件解析,构建对应的chunk
(模块),生成对应的hash
值。只有被修改的chunk
(模块)在重新构建之后才会生成新的hash
值,不会影响其它的chunk
。(粒度entry
的每个入口文件) -
contenthash
是跟每个生成的文件有关,每个文件都有一个唯一的hash
值。当要构建的文件内容发生改变时,就会生成新的hash
值,且该文件的改变并不会影响和它同一个模块下的其它文件。(粒度每个文件的内容)
(具体可以看我简书上的这篇文章:https://www.jianshu.com/p/486453d81088)
这里只是说明了三种
hash
的不同…至于原理暂时没了解。9. webpack如果使用了hash命名,那是每次都会重写生成hash吗
这个问题在上一个问题中已经说明了,要看
webpack
的配置。有三种情况:
-
如果是
hash
的话,是和整个项目有关的,有一处文件发生更改则所有文件的hash
值都会发生改变且它们共用一个hash
值; -
如果是
chunkhash
的话,只和entry
的每个入口文件有关,也就是同一个chunk
下的文件有所改动该chunk
下的文件的hash
值就会发生改变 -
如果是
contenthash
的话,和每个生成的文件有关,只有当要构建的文件内容发生改变时才会给该文件生成新的hash
值,并不会影响其它文件。
10. webpack中如何处理图片的?
在
webpack
中有两种处理图片的loader
:-
file-loader
:解决CSS
等中引入图片的路径问题;(解决通过url
,import/require()
等引入图片的问题) -
url-loader
:当图片小于设置的limit
参数值时,url-loader
将图片进行base64
编码(当项目中有很多图片,通过url-loader
进行base64
编码后会减少http
请求数量,提高性能),大于limit参数值,则使用file-loader
拷贝图片并输出到编译目录中;
详细使用可以查看这里:霖呆呆的webpack之路-loader篇:https://github.com/LinDaiDai/niubility-coding-js/blob/master/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96/webpack/%E9%9C%96%E5%91%86%E5%91%86%E7%9A%84webpack%E4%B9%8B%E8%B7%AF-loader%E7%AF%87.md#file-loader
11. 说一下回流和重绘
「回流」:
触发条件:
当我们对 DOM 结构的修改引发 DOM 几何尺寸变化的时候,会发生
回流
的过程。例如以下操作会触发回流:
-
一个 DOM 元素的几何属性变化,常见的几何属性有
width
、height
、padding
、margin
、left
、top
、border
等等, 这个很好理解。 -
使 DOM 节点发生
增减
或者移动
。 -
读写
offset
族、scroll
族和client
族属性的时候,浏览器为了获取这些值,需要进行回流操作。 -
调用
window.getComputedStyle
方法。
回流过程:由于DOM的结构发生了改变,所以需要从生成DOM这一步开始,重新经过
样式计算
、生成布局树
、建立图层树
、再到生成绘制列表
以及之后的显示器显示这整一个渲染过程走一遍,开销是非常大的。「重绘」:
触发条件:
当 DOM 的修改导致了样式的变化,并且没有影响几何属性的时候,会导致
重绘
(repaint
)。重绘过程:由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,所以当发生重绘的时候,会跳过
生存布局树
和建立图层树
的阶段,直接到生成绘制列表
,然后继续进行分块、生成位图等后面一系列操作。「如何避免触发回流和重绘」:
-
避免频繁使用 style,而是采用修改
class
的方式。 -
将动画效果应用到
position
属性为absolute
或fixed
的元素上。 -
也可以先为元素设置
display: none
,操作结束后再把它显示出来。因为在display
属性为none
的元素上进行的DOM操作不会引发回流和重绘 -
使用
createDocumentFragment
进行批量的 DOM 操作。 -
对于 resize、scroll 等进行防抖/节流处理。
-
避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
-
利用 CSS3 的
transform
、opacity
、filter
这些属性可以实现合成的效果,也就是CPU
加速。
参考来源:https://juejin.im/post/5df5bcea6fb9a016091def69#heading-57
12. 盒模型及如何转换
box-sizing: content-box
(W3C盒模型,又名标准盒模型):元素的宽高大小表现为内容的大小。box-sizing: border-box
(IE盒模型,又名怪异盒模型):元素的宽高表现为内容 + 内边距 + 边框的大小。背景会延伸到边框的外沿。13. 实现水平垂直居中的几种方式
这里我是按照子弈的总结答的:https://juejin.im/post/5d690c726fb9a06b155dd40d#heading-81
- Flex布局(子元素是块级元素)
.box {
display: flex;
width: 100px;
height: 100px;
background-color: pink;
}
.box-center{
margin: auto;
background-color: greenyellow;
}
- Flex布局
.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;
}
14. flex的兼容性怎样
「简单回答:」
IE6~9
不支持,IE10~11
部分支持flex的2012版
,但是需要-ms-
前缀。其它的主流浏览器包括安卓和
IOS
基本上都支持了。「详细回答:」
-
IE10部分支持2012,需要-ms-前缀
-
Android4.1/4.2-4.3部分支持2009 ,需要-webkit-前缀
-
Safari7/7.1/8部分支持2012, 需要-webkit-前缀
-
IOS Safari7.0-7.1/8.1-8.3部分支持2012,需要-webkit-前缀
15. 你知道到哪里查看兼容性吗
可以到
Can I use
上去查看,官网地址为:https://caniuse.com/16. 移动端中css你是使用什么单位
「比较常用的」:
-
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"
一样长。
「移动端布局总结」:
-
移动端布局的方式主要使用rem和flex,可以结合各自的优点,比如flex布局很灵活,但是字体的大小不好控制,我们可以使用rem和媒体查询控制字体的大小,媒体查询视口的大小,然后不同的上视口大小下设置设置html的font-size。
-
可单独制作移动端页面也可响应式pc端移动端共用一个页面。没有好坏,视情况而定,因势利导
(总结来源:玲珑)
17. rem和em的区别
「em:」
定义字体大小时以父级的字体大小为基准;定义长度单位时以当前字体大小为基准。例父级
font-size: 14px
,则子级font-size: 1em;
为font-size: 14px;
;若定义长度时,子级的字体大小如果为14px
,则子级width: 2em;
为width: 24px
。「rem:」
以根元素的字体大小为基准。例如
html
的font-size: 14px
,则子级1rem = 14px
。18. 在移动端中怎样初始化根元素的字体大小
一个简易版的初始化根元素字体大小。
页面开头处引入下面这段代码,用于动态计算
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
头:19. 移动端中不同手机html默认的字体大小都是一样的吗
如果没有人为去改变根元素字体大小的话,默认是
1rem = 16px
;根元素默认的字体大小是16px
。20. 你做过哪些动画效果
实话实说没太做过。
21. 如果让你实现一个一直旋转的动画你会如何做
css代码:
html代码:
22. animation介绍一下
语法:
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) 正常/反向 |
23. animation有一个steps()功能符知道吗?
一句话介绍:
steps()
功能符可以让动画不连续。地位和作用:和贝塞尔曲线(
cubic-bezier()
修饰符)一样,都可以作为animation
的第三个属性值。和贝塞尔曲线的区别:贝塞尔曲线像是滑梯且有4个关键字(参数),而
steps
像是楼梯坡道且只有number
和position
两个关键字。语法:
steps(number, position)
-
number: 数值,表示把动画分成了多少段
-
position: 表示动画是从时间段的开头连续还是末尾连续。支持
start
和end
两个关键字,含义分别如下: -
start
:表示直接开始。
-
end
:表示戛然而止。是默认值。
具体可以看这里:https://www.zhangxinxu.com/wordpress/2018/06/css3-animation-steps-step-start-end/
24. 用过哪些移动端的调试工具
-
Chrome
浏览器 ->more tools
->Remote devices
->chrome://inspect/#devices
-
Mac
+IOS
+Safari
25. 说一下原型链
26. 详细说一下instanceof
27. V8的垃圾回收是发生在什么时候?
V8引擎帮助我们实现了自动的垃圾回收管理,「利用浏览器渲染页面的空闲时间进行垃圾回收。」
28. 具体说一下垃圾回收机制
(这里我用的是:https://juejin.im/post/5e8b261ae51d4546c0382ab4#heading-20 里的总结)
「栈内存的回收:」
栈内存调用栈上下文切换后就被回收,比较简单。
「堆内存的回收:」
V8的堆内存分为新生代内存和老生代内存,新生代内存是临时分配的内存,存在时间短,老生代内存存在时间长。
新生代内存回收机制:
- 新生代内存容量小,64位系统下仅有32M。新生代内存分为**「From、To」**两部分,进行垃圾回收时,先扫描From,将非存活对象回收,将存活对象顺序复制到To中,之后调换From/To,等待下一次回收
老生代内存回收机制
-
「晋升」:如果新生代的变量经过多次回收依然存在,那么就会被放入老生代内存中
-
「标记清除」:老生代内存会先遍历所有对象并打上标记,然后对正在使用或被强引用的对象取消标记,回收被标记的对象
-
「整理内存碎片」:把对象挪到内存的一端
(当然想要详细了解的话也可以看我的这篇文章:JavaScript进阶-内存机制(表情包初探))
29. 在项目中如何把http的请求换成https
由于我在项目中是会对
axios
做一层封装,所以每次请求的域名也是写在配置文件中,有一个baseURL
字段专门用于存储它,所以只要改这个字段就可以达到替换所有请求http
为https
了。当然后面我也有了解到:
利用
meta
标签把http
请求换为https
:30. 知道meta标签有把http换成https的功能吗?
参考上一题???。
31. http请求可以怎么拦截
在浏览器和服务器进行传输的时候,可以被
nginx
代理所拦截,也可以被网关拦截。32. https的加密方式
HTTPS主要是采用对称密钥加密和非对称密钥加密组合而成的混合加密机制进行传输。
也就是发送密文的一方用"对方的公钥"进行加密处理"对称的密钥",然后对方在收到之后使用自己的私钥进行解密得到"对称的密钥",这在确保双发交换的密钥是安全的前提下使用对称密钥方式进行通信。
33. 混合加密的好处
对称密钥加密和非对称密钥加密都有它们各种的优缺点,而混合加密机制就是将两者结合利用它们各自的优点来进行加密传输。
比如既然对称密钥的优点是加解密效率快,那么在客户端与服务端确定了连接之后就可以用它来进行加密传输。不过前提是得解决双方都能安全的拿到这把对称密钥。这时候就可以利用非对称密钥加密来传输这把对称密钥,因为我们知道非对称密钥加密的优点就是能保证传输的内容是安全的。
数据结构与算法
这一块在笔试、面试的代码题中考核较多,其中常考的数据结构主要有:数组、链表、队列、栈、Set、Map、哈希表等,不同数据结构有不同的方法以及储存原理,这些算是技术岗的必备知识。算法部分主要分为两大块,排序算法与一些其他算法题。
排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。
- 二叉树层序遍历
- B 树的特性,B 树和 B+树的区别
- 尾递归
- 如何写一个大数阶乘?递归的方法会出现什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
b4#heading-20 里的总结)「栈内存的回收:」
栈内存调用栈上下文切换后就被回收,比较简单。
「堆内存的回收:」
V8的堆内存分为新生代内存和老生代内存,新生代内存是临时分配的内存,存在时间短,老生代内存存在时间长。
新生代内存回收机制:
- 新生代内存容量小,64位系统下仅有32M。新生代内存分为**「From、To」**两部分,进行垃圾回收时,先扫描From,将非存活对象回收,将存活对象顺序复制到To中,之后调换From/To,等待下一次回收
老生代内存回收机制
-
「晋升」:如果新生代的变量经过多次回收依然存在,那么就会被放入老生代内存中
-
「标记清除」:老生代内存会先遍历所有对象并打上标记,然后对正在使用或被强引用的对象取消标记,回收被标记的对象
-
「整理内存碎片」:把对象挪到内存的一端
(当然想要详细了解的话也可以看我的这篇文章:JavaScript进阶-内存机制(表情包初探))
29. 在项目中如何把http的请求换成https
由于我在项目中是会对
axios
做一层封装,所以每次请求的域名也是写在配置文件中,有一个baseURL
字段专门用于存储它,所以只要改这个字段就可以达到替换所有请求http
为https
了。当然后面我也有了解到:
利用
meta
标签把http
请求换为https
:30. 知道meta标签有把http换成https的功能吗?
参考上一题???。
31. http请求可以怎么拦截
在浏览器和服务器进行传输的时候,可以被
nginx
代理所拦截,也可以被网关拦截。32. https的加密方式
HTTPS主要是采用对称密钥加密和非对称密钥加密组合而成的混合加密机制进行传输。
也就是发送密文的一方用"对方的公钥"进行加密处理"对称的密钥",然后对方在收到之后使用自己的私钥进行解密得到"对称的密钥",这在确保双发交换的密钥是安全的前提下使用对称密钥方式进行通信。
33. 混合加密的好处
对称密钥加密和非对称密钥加密都有它们各种的优缺点,而混合加密机制就是将两者结合利用它们各自的优点来进行加密传输。
比如既然对称密钥的优点是加解密效率快,那么在客户端与服务端确定了连接之后就可以用它来进行加密传输。不过前提是得解决双方都能安全的拿到这把对称密钥。这时候就可以利用非对称密钥加密来传输这把对称密钥,因为我们知道非对称密钥加密的优点就是能保证传输的内容是安全的。
数据结构与算法
这一块在笔试、面试的代码题中考核较多,其中常考的数据结构主要有:数组、链表、队列、栈、Set、Map、哈希表等,不同数据结构有不同的方法以及储存原理,这些算是技术岗的必备知识。算法部分主要分为两大块,排序算法与一些其他算法题。
排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。
- 二叉树层序遍历
- B 树的特性,B 树和 B+树的区别
- 尾递归
- 如何写一个大数阶乘?递归的方法会出现什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
[外链图片转存中…(img-BlsLel9R-1713090439396)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-T09Y1Vcq-1713090439397)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
-