先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
‘c’:[32,43,54],
‘d’:[4,56,20],
}
let merge = Object.values(deps).flat(Infinity);
其中使用Infinity
作为flat
的参数,使得无需知道被扁平化的数组的维度。
方法
方法仅仅是一个具有功能而非数据的对象属性。将方法定义为一个函数,它会有一个内部[[HomeObject]]属性来容纳这个方法从属的对象。
const person = {
// 是方法 [[HomeObject]] = person
sayHello () {
return ‘Hello’
}
}
// 不是方法
function sayBye () {
return ‘goodbye’
}
const friend = {
sayHello () {
return super.sayHello() + ‘!!!’
}
}
Object.setPrototypeOf(friend, person)
console.log(friend.sayHello()) // Hello!!!
friend.sayHello()
方法的[[HomeObject]]
属性值为friend
。friend
的原型是person
。super.sayHello()
相当于person.sayHello.call(this)
。
箭头函数
ES6 中引入了箭头函数,它是一种更加简洁的函数定义方式,在箭头函数中没有属于自己的 this 和arguments 对象,他们会从外部作用域继承 this 和 arguments。
const add = (a+b)=> a+b
箭头函数的定义方式更加简洁
模板字符串
模板字符串,它是一种更加灵活的字符串定义方式。模板字符串使用反引号()包裹字符串,可以在字符串中插入变量和表达式。
const age =18;
const message = My name is ${name}, and I am ${age} years old.;
console.log(message);//输出:My name is Alice, and I am 18 years old.
在上面的代码中,使用模板字符串定义了一个字符串变量message,并在其中插入了变量name和age的值。
在${}
中甚至可以放入任意的JavaScript表达式,进行运算,以及引用对象属性。
const name = ‘lili’;
const score = 80;
const result = ${name}的考试成绩${score > 60?'':'不'}及格
[] 结合模板字符串实现动态取值
对象的取值除了用 .
意外还可可以使用 []
访问动态属性名。
let obj = {
title1: ‘嘻嘻嘻’,
title2: ‘啦啦啦’
}
const number = 2
let name = obj[title${number}
]
也可以通过[]
为对象动态添加属性
cosnt index = 5
obj[title${index}
] = ‘哈哈哈’;
解构
解构是一种更加方便的变量赋值方式。解构赋值可以从数组或对象中提取值,并将其赋值给变量。
对象解构
必须为解构赋值提供初始化程序,同时如果解构 null 或者 undefined ,解构会发生错误。
const person = {
name: ‘AAA’,
age: 23
}
const { name, age } = person
console.log(name) // AAA
console.log(age) // 23
解构赋值
const person = {
name: ‘AAA’,
age: 23
}
let name, age
// 必须添加(),因为如果不加,{}代表是一个代码块,而语法规定代码块不能出现在赋值语句的左侧。
({ name, age } = person)
console.log(name) // AAA
console.log(age) // 23
解构默认值
使用解构赋值表达式时,如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为undefined,此时可以随意指定一个默认值。
const person = {
name: ‘AAA’,
age: 23
}
let { name, age, sex = ‘男’ } = person
// 同名 赋值 等价于
let {name:name,age:age,sex =‘男’ } = person
console.log(sex) // 男
let { name: name, age: age } = person含义是:在person对象中取键为name和age的值,并分别赋值给name变量和age变量。
非同名赋值
const person = {
name: ‘AAA’,
age: 23
}
let { name: newName, age: newAge } = person
console.log(newName) // AAA
console.log(newAge) // 23
// 在 vue 中的应用
const { params, query } = this.$route
// 解构data, 重命名为res
const { data: res } = await axios.get(‘/api’)
嵌套对象解构
const person = {
name: ‘AAA’,
age: 23,
job: {
name: ‘FE’,
salary: 1000
},
department: {
group: {
number: 1000,
isMain: true
}
}
}
// 在person中提取键为job、在person的嵌套对象department中提取键为group的值,并把其赋值给对应的变量。
let { job, department: { group } } = person
console.log(job) // { name: ‘FE’, salary: 1000 }
console.log(group) // { number: 1000, isMain: true }
注意解构的对象不能为 undefined
、null
。否则会报错,所以我们要给被解构的对象一个默认值避免报错的发生。
const {a,b,c,d,e} = obj || {};
数组解构
使用数组字面量,且解构操作全部在数组内完成,解构的过程是按值在数组中的位置进行提取的。
const colors = [‘red’, ‘green’, ‘blue’]
let [firstColor, secondColor] = colors
// 按需解构
let [,threeColor] = colors
console.log(firstColor) // red
console.log(secondColor) // green
console.log(threeColor) // blue
交换变量
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
嵌套数组
const colors = [‘red’, [‘green’, ‘lightgreen’], ‘blue’]
const [firstColor, [secondColor]] = colors
console.log(firstColor) // red
console.log(secondColor) // green
解构数组中的不定元素的原理能实现数组的复制
const colors = [‘red’, ‘green’, ‘blue’]
const concatColors = colors.concat()
const […restColors] = colors
console.log(concatColors) // [‘red’, ‘green’, ‘blue’]
console.log(restColors) // [‘red’, ‘green’, ‘blue’]
es6 中的运算符(??、??=、?.、?:)
?? 非空运算符
?? 运算符也被称为空值合并操作符。
如果第一个参数为 null 或 undefined 则返回第二个参数,否则返回第一个参数。
null ?? 8 // => 8
undefined || 8 // =>8
6 ?? 8 // => 6
0 ?? 8 // => 0
false ?? 8 // => false
‘’ ?? 8 // => ‘’
function(obj){
var a = obj ?? {}
}
等价于
function(obj){
var a;
if( obj === null || obj === undefined){
a = {}
} else {
a = obj;
}
}
而 || 运算符则是 判断两个值之间的关系,如果其中一个值为真,则返回该值,否则返回另一个值。若左侧操作数为假值时返回右侧操作数。
null || 8 // => 8
undefined || 8 // =>8
6 || 8 // => 6
0 || 8 // => 8
false || 8 //=> 8
‘’ || 8 // => 8
function(obj){
var a = obj || {}
}
等价于
function(obj){
var a;
if(obj === 0 ||
obj === “” ||
obj === false ||
obj === null ||
obj === undefined){
a = {}
} else {
a = obj;
}
}
js 中的假值包含:未定义 undefined、空对象 null、数值 0、 NaN、布尔 false,空字符串’'。
?? 运算符允许我们在忽略错误值(如 0 和空字符串)的同时指定默认值。
??= 空赋值运算符
??= 被称为空赋值运算符,与 ?? 运算符相似仅在左值为 null / undefined 时对其赋值。
var a = null
var b = 8
console.log(a ??= b) // => 8
相当于
console.log(a = (a ?? b)) // => 8
let c = 0;
c ??= b;
console.log©; // 0
a 的值为 null 或 undefined 时,则将 b 的值赋给a变量,否则 a 保持变量原有的值不变。
仅当值为 null 或 undefined 时,此赋值运算符才会赋值。
?. 可选链操作符
可选链运算符,用于判断一个对象是否存在某个属性或方法,如果存在则返回该属性或方法的值,否则返回undefined。
const person = {
name: ‘lili’,
age: 18,
pet:{
name: ‘haha’
}
};
const name = person?.name // ‘lili’
const sex = person?.sex // undefined
const petName = person?.pet?.name // ‘haha’
?. 同时也支持链式调用
?: 三元运算符
?: 三元运算符,用于根据一个条件来返回两个不同的值。
例如:a ? b : c 表示如果a的值为真,则返回b的值,否则返回c的值。
function isPass(score) {
return (score > 60) ? ‘及格’ : ‘不及格’
}
console.log(isPass(59)) // => 不及格
console.log(isPass(80)) // => 及格
symbol
Symbol作为原始数据类型的一种,表示独一无二的值, Symbol的应用其实利用了唯一性的特性。
如何使用 symbol 呢?
let a = Symbol(‘a’)
typeof a // ‘symbol’
// 使用Object()函数 可以得到一个Symbol()的对象形式
let b = Object(‘b’)
typeof b // ‘object’
symbol的应用
作为对象的属性
将symbol 作为对象的键名,可以避免键名的冲突
let a = Symbol() // 创建一个Symbol
let obj = {} // 创建一个对象
obj[a] = “hello world” // 通过obj[]将Symbol作为对象的键
全局共享 symbol
Symbol.for() 实现了 Symbol 的全局共享
遍历全局注册表中的的Symbol,当搜索到相同描述,那么会调用这个Symbol,如果没有搜索到,就会创建一个新的Symbol。
let a = Symbol.for(“a”)
let b = Symbol.for(“a”)
a === b // true
let a = Symbol(“a”)
let b = Symbol.for(“a”)
a === b // false
- 使用Symbol(“a”)直接创建,所以该Symbol(“a”)不在全局注册表中
- 使用Symbol.for(“a”)在全局注册表中寻找描述为a的Symbol,并没有找到,所以在全局注册表中又创建了一个描述为a的新的Symbol
- 秉承Symbol创建的唯一特性,所以a与b创建的Symbol不同,结果为false
如何判断 Symbol 是否在全局注册表中呢?
Symbol.keyFor()帮我们解决了这个问题,他可以通过变量名查询该变量名对应的Symbol是否在全局注册表中
let a = Symbol(“a”)
let b = Symbol.for(“a”)
Symbol.keyFor(a) // undefined
Symbol.keyFor(b) // ‘a’
Symbol 的类型不能强转
const uid = Symbol.for(‘uid’)
let object = {
[uid]: 123
}
const symbols = Object.getOwnPropertySymbols(object)
console.log(symbols.length) // 1
console.log(symbols[0]) // Symbol(uid)
而当我们在使用console.log()方法打印Symbol,会调用Symbol的String()方法,因此也可以直接调用String()方法输出Symbol。然而尝试将Symbol和一个字符串拼接,会导致程序抛出异常,Symbol也不能和每一个数学运算符混合使用,否则同样会抛出错误。
toPrimitive 类型转化
对于大多数标准对象,数字模式有以下特性,根据优先级的顺序排序如下:
- 调用
valueOf()
方法,如果结果为原始值,则返回。 - 否则,调用
toString()
方法,如果结果为原始值,则返回。 - 如果再无可选值,则抛出错误。
同样对于大多数标准对象,字符串模式有以下优先级顺序:
- 调用
toString()
方法,如果结果为原始值,则返回。 - 否则,调用
valueOf()
方法,如果结果为原始值,则返回。 - 如果再无可选值,则抛出错误。
set 、map
set 集合
Set 集合是一种有序列表,其中含有一些相互独立的非重复值,在 Set 集合中,不会对所存的值进行强制类型转换。
将 set 集合转为数组
const set = new Set([1, 2, 3, 4])
// 方法一:展开运算符
const arr1 = […set]
// 方法二:Array.from方法
const arr2 = Array.from(set)
console.log(arr1) // [1, 2, 3, 4]
console.log(arr2) // [1, 2, 3, 4]
还有一个小妙招哦
在合并数组的同时可以利用 set 进行去重合并
const a = [1,2,3]
const b = [1,5,6]
const c = […new Set([…a,…b])] // [1,2,3,5,6]
Map 集合
Map类型是一种存储着许多键值对的有序列表,其中的键名和对应的值支持所有的数据类型,键名的等价性判断是通过调用Object.is方法来实现的。
map 支持的方法
proxy
Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
let p = new Proxy(target, handler)
target 代表需要添加代理的对象,handler 用来自定义对象中的操作,比如可以用来自定义 set 或者 get 函数。
数据响应式
vue2中使用Object.definedProperty()方法来实现响应式,而在vue3 中使用Proxy :
- Proxy可以一次性为所有属性实现代理,无需遍历,性能更佳
- Proxy能监听到以前使用Object.definedProperty()监听不到的数据变动。
- 由于是ES6新增加的特性,所以浏览器兼容性方面比Object.definedProperty()差
Proxy 实现响应式:
Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法。
Reflect 与 Proxy 结合使用以实现和Object.defineProperty类似的功能,且性能更好。
let onWatch = (obj, setBind, getLogger) => {
let handler = {
get(target, property, receiver) {
getLogger(target, property)
return Reflect.get(target, property, receiver)
},
set(target, property, value, receiver) {
setBind(value, property)
return Reflect.set(target, property, value)
}
}
return new Proxy(obj, handler)
}
let obj = { a: 1 }
let p = onWatch(
obj,
(v, property) => {
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ct.set(target, property, value)
}
}
return new Proxy(obj, handler)
}
let obj = { a: 1 }
let p = onWatch(
obj,
(v, property) => {
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-5WGDaiKn-1713664157836)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!