先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
2.和=的区别是什么
==
是抽象相等运算符,而===
是严格相等运算符。==
运算符是在进行必要的类型转换后,再比较。===
运算符不会进行类型转换,所以如果两个值不是相同的类型,会直接返回false
。使用==
时,可能发生一些特别的事情,例如:
1 == ‘1’; // true
1 == [1]; // true
1 == true; // true
0 == ‘’; // true
0 == ‘0’; // true
0 == false; // true
如果你对==
和===
的概念不是特别了解,建议大多数情况下使用===
3.箭头函数和普通函数有什么区别
-
函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象,用call
apply
bind
也不能改变this
指向 -
不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 -
不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用rest
参数代替。 -
不可以使用
yield
命令,因此箭头函数不能用作Generator
函数。 -
箭头函数没有原型对象
prototype
4.白屏时间
白屏时间是指浏览器从输入网址,到浏览器开始显示内容的时间。
Performance 接口可以获取到当前页面中与性能相关的信息,该类型的对象可以通过调用只读属性 Window.performance
来获得。
performance.timing.navigationStart
是一个返回代表一个时刻的 unsigned long long 型只读属性,为紧接着在相同的浏览环境下卸载前一个文档结束之时的 Unix 毫秒时间戳。如果没有上一个文档,则它的值相当于 PerformanceTiming.fetchStart。
所以将以下脚本放在 </head>
前面就能获取白屏时间。
参考资料:
5.当你在浏览器输入一个地址后发生了什么
6.页面大量图片,如何优化加载,优化用户体验
-
图片懒加载。在页面的未可视区域添加一个滚动事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。
-
如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
-
如果图片为css图片,可以使用CSSsprite,SVGsprite等技术。
-
如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
-
如果图片展示区域小于图片的真实大小,应在服务器端根据业务需要先进行图片压缩,图片压缩后大小与展示一致。
7.js网络请求性能优化之防抖与节流
防抖(debounce)
在函数需要频繁触发时,只有当有足够空闲的时间时,才执行一次。就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。
节流(thorttle)
预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。
区别
在发生持续触发事件时,防抖设置事件延迟并在空闲时间去触发事件,而节流则是隔一定的时间触发一次。
一个简单的防抖示例
let timer
input.on(‘input’, () => {
clearTimeout(timer)
// 停止输入 500 毫秒后开始搜索
timer = setTimeout(() => {
// 搜索
}, 500)
})
一个简单的节流示例
let isClick = false
button.on(‘click’, () => {
if (isClick) return
isClick = true
// 其他代码。。。
// 每 10 秒只允许点击一次
setTimeout(() => {
isClick = false
}, 10000)
})
参考资料:
8.如何做到修改url参数页面不刷新
HTML5引入了 history.pushState()
和 history.replaceState()
方法,它们分别可以添加和修改历史记录条目。
let stateObj = {
foo: “bar”,
};
history.pushState(stateObj, “page 2”, “bar.html”);
复制代码
假设当前页面为 foo.html
,执行上述代码后会变为 bar.html
,点击浏览器后退,会变为 foo.html
,但浏览器并不会刷新。 pushState()
需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和 (可选的) 一个 URL. 让我们来解释下这三个参数详细内容:
- 状态对象 — 状态对象
state
是一个 JavaScript 对象,通过pushState ()
创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate
事件就会被触发,且该事件的state
属性包含该历史记录条目状态对象的副本。
状态对象可以是能被序列化的任何东西。原因在于 Firefox 将状态对象保存在用户的磁盘上,以便在用户重启浏览器时使用,我们规定了状态对象在序列化表示后有640k的大小限制。如果你给 pushState()
方法传了一个序列化后大于 640k 的状态对象,该方法会抛出异常。如果你需要更大的空间,建议使用 sessionStorage
以及 localStorage
.
-
标题 — Firefox 目前忽略这个参数,但未来可能会用到。传递一个空字符串在这里是安全的,而在将来这是不安全的。二选一的话,你可以为跳转的
state
传递一个短标题。 -
URL — 该参数定义了新的历史URL记录。注意,调用
pushState()
后浏览器并不会立即加载这个 URL,但可能会在稍后某些情况下加载这个 URL,比如在用户重新打开浏览器时。新URL不必须为绝对路径。如果新URL是相对路径,那么它将被作为相对于当前 URL 处理。新 URL 必须与当前URL同源,否则pushState()
会抛出一个异常。该参数是可选的,缺省为当前 URL。
参考资料:
9.请用js去除字符串空格
去除所有空格
str.replace(/\s/g, ‘’)
去除两边空格
str.replace(/^\s+|\s+$/g, ‘’)
// 原生方法
str.trim()
10.创建对象有几种方法
- 字面量
const obj = {a: 1}
- 构造函数
function Obj(val) {
this.a = val
}
const obj = new Obj(1)
- Object.create
const obj = Object.create({a: 1})
11.null和undefined的区别
null
表示一个对象是“没有值”的值,也就是值为“空”
undefined
表示一个变量声明了没有初始化(赋值)
undefined
和 null
在if语句中,都会被自动转为false
undefined
不是一个有效的JSON,而 null
是
undefined
的类型(typeof)是 undefined
null
的类型(typeof)是 object
Javascript将未赋值的变量默认值设为 undefined
Javascript从来不会将变量设为 null
。 它是用来让程序员表明某个用var声明的变量时没有值的
12.异步求和
要求
假设有一台本地机器,无法做加减乘除运算,因此无法执行 a + b、a+ = 1 这样的 JS 代码,然后我们提供一个服务器端的 HTTP API,可以传两个数字类型的参数,响应结果是这两个参数的和,这个 HTTP API 的 JS SDK(在本地机器上运行)的使用方法如下:
asyncAdd(3, 5, (err, result) => {
console.log(result); // 8
});
模拟实现:
function asyncAdd(a, b, cb) {
setTimeout(() => {
cb(null, a + b);
}, Math.floor(Math.random()*100))
}
现在要求在本地机器上实现一个 sum 函数,支持以下用法:
(async () => {
const result1 = await sum(1, 4, 6, 9, 1, 4);
const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);
const result3 = await sum(1, 6, 0, 5);
console.log([result1, result2, result3]); // [25, 36, 12]
})();
要求 sum 能在最短的时间里返回以上结果
实现
function asyncAdd(a, b, cb) {
setTimeout(() => {
cb(null, a + b);
}, Math.floor(Math.random()*100))
}
function sum(…args) {
const result = []
function _sum(resolve, reject) {
new Promise((r, j) => {
let a = args.pop()
let b = args.pop()
a = a !== undefined? a : 0
b = b !== undefined? b : 0 // 如果访问的元素超出了数组范围,则转为 0
asyncAdd(a, b, (err, res) => {
if (err) j(err)
r(res)
})
if (args.length) {
_sum(resolve, reject)
}
})
.then(val => {
result.push(val)
setTimeout(() => {
if (args.length <= 0) {
resolve(sum(…result))
}
}, 100)
})
}
return new Promise((resolve, reject) => {
if (!args || !args.length) resolve(0)
if (args.length == 1) resolve(args[0])
_sum(resolve, reject)
})
}
(async () => {
const result1 = await sum(1, 4, 6, 9, 1, 4)
const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7)
const result3 = await sum(1, 6, 0, 5)
console.log([result1, result2, result3]) // [25, 36, 12]
})()
13.CommonJS,ES module 是什么,有什么区别?
它们都是一种模块规范,例如 Node 使用的就是 CommonJS 规范。ES module 则是语言标准上的模块规范。
区别:
-
CommonJS 模块使用
require()
和module.exports
,ES6 模块使用import
和export
。 -
CommonJS 模块输出的是一个值的浅拷贝,ES6 模块输出的是值的引用。
-
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
-
CommonJS 模块的
require()
是同步加载模块,ES6 模块的import
命令是异步加载,有一个独立的模块依赖的解析阶段。 -
ES6 模块之中,顶层的 this 指向 undefined;CommonJS 模块的顶层 this 指向当前模块,
-
对于循环加载的处理方法不同
第 3 个差异是因为 CommonJS 加载的是一个对象(即 module.exports
属性),该对象只有在脚本运行完才会生成。
而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
参考资料:
14.preload和prefetch
preload
preload
是 <link>
标签 rel
属性的属性值,同时需要配合 as
属性使用。
as
指定将要预加载的内容的类型,使得浏览器能够:
-
更精确地优化资源加载优先级。
-
匹配未来的加载需求,在适当的情况下,重复利用同一资源。
-
为资源应用正确的内容安全策略。
-
为资源设置正确的 Accept 请求头。
看一下这个示例:
这种做法将把 <link>
标签塞入一个预加载器中。
这个预加载器在不阻塞页面 onload 事件的情况下,去加载资源。
我们可以通过以下两个示例来作一个对比:
上面这个示例从加载到触发 onload 事件需要大概 1400 ms 的时间。再看一下使用 preload 预加载的时间:
window.onload = () => {
console.timeEnd(‘load’) // load: 10.8818359375ms
}
用 preload 来加载资源,只需要 10 ms 就触发了 onload 事件。
说明同样是下载文件,使用 preload 不会阻塞 onload 事件。
prefetch
prefetch
和 preload
不同,使用 prefetch
属性指定的资源将在浏览器空闲时间下下载。
在资源的请求头如果发现有下面这个属性,就代表它是通过 prefetch
加载的:
purpose: prefetch
另外,空闲时间是如何确定、如何获取的,目前还没有相关 API。
15.preload 和 defer 的区别
preload 和 defer 的相同点是异步下载。那它们的不同点是什么呢?
preload 下载的资源只有在遇到同样的 script 标签时,才会执行对应的脚本。例如下面预加载的 vue.js
:
只有在遇到下面的标签时,才会执行加载的 vue.js
:
defer 则是异步下载资源,在所有元素解析完成后,触发 DOMContentLoaded 事件前执行。
16.window.onload 和 DOMContentLoaded 的区别
当整个页面及所有依赖资源如样式表和图片都已完成加载时,将触发load事件。
它与 DOMContentLoaded不同,当纯HTML被完全加载以及解析时,DOMContentLoaded 事件会被触发,而不必等待样式表,图片或者子框架完成加载。
17.Object 与 Map 的区别
-
Object 只能选择字符、数值、符号作为 key,Map 则可以使用任何类型的数据作为 key。
-
Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。Chrome Opera 中使用 for-in 语句遍历 Object 属性时会遵循一个规律:它们会先提取所有 key 的 parseFloat 值为非负整数的属性,然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。其它浏览器则完全按照对象定义的顺序遍历属性。
选择 Object 还是 Map
对于多数Web开发任务来说,选择 Object 还是 Map 只是个人偏好问题,影响不大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。
1. 内存占用
Object 和 Map 的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。
不同浏览器的情况不同,但给定固定大小的内存, Map 大约可以比 Object 多存储50%的键/值对。
2. 插入性能
向 Object 和 Map 中插入新键/值对的消耗大致相当,不过插入Map 在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。
如果代码涉及大量插入操作,那么显然 Map 的性能更佳。
3. 查找速度
与插入不同,从大型 Object 和 Map 中查找键/值对的性能差异极小,但如果只包含少量键/值对,则 Object 有时候速度更快。在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。
这对 Map 来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择 Object 更好一些。
4. 删除性能
使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为 undefined 或 null 。但很多时候,这都是一 种讨厌的或不适宜的折中。
而对大多数浏览器引擎来说, Map 的 delete() 操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择 Map 。
参考资料:
18.为什么 WeakMap 和 WeakSet 的键只能使用对象?
是为了保证只有通过键对象的引用来取得值。
算法
-
冒泡排序
-
选择排序
-
快速排序
-
二叉树查找: 最大值、最小值、固定值
-
二叉树遍历
-
二叉树的最大深度
-
给予链表中的任一节点,把它删除掉
-
链表倒叙
-
如何判断一个单链表有环
由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择 Object 更好一些。
4. 删除性能
使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为 undefined 或 null 。但很多时候,这都是一 种讨厌的或不适宜的折中。
而对大多数浏览器引擎来说, Map 的 delete() 操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择 Map 。
参考资料:
18.为什么 WeakMap 和 WeakSet 的键只能使用对象?
是为了保证只有通过键对象的引用来取得值。
算法
-
冒泡排序
-
选择排序
-
快速排序
-
二叉树查找: 最大值、最小值、固定值
-
二叉树遍历
-
二叉树的最大深度
-
给予链表中的任一节点,把它删除掉
-
链表倒叙
-
如何判断一个单链表有环
[外链图片转存中…(img-ggMLZ8gY-1713638737409)]
由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-YaG5bYOI-1713638737410)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!