先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
// a.js
import fetch from “node-fetch”;
let users;
export const fetchUsers = async () => {
const resp = await fetch(‘https://jsonplaceholder.typicode.com/users’);
users = resp.json();
}
fetchUsers();
export { users };
// usingAwait.js
import {users} from ‘./a.js’;
console.log('users: ', users);
console.log(‘usingAwait module’);
我们还可以立即调用顶层async函数(IIAFE):
import fetch from “node-fetch”;
(async () => {
const resp = await fetch(‘https://jsonplaceholder.typicode.com/users’);
users = resp.json();
})();
export { users };
这样会有一个缺点,直接导入的 users 是 undefined,需要在异步执行完成之后才能访问它:
// usingAwait.js
import {users} from ‘./a.js’;
console.log(‘users:’, users); // undefined
setTimeout(() => {
console.log(‘users:’, users);
}, 100);
console.log(‘usingAwait module’);
当然,这种方法并不安全,因为如果异步函数执行花费的时间超过100毫秒, 它就不会起作用了,users 仍然是 undefined。
另一个方法是导出一个 promise,让导入模块知道数据已经准备好了:
//a.js
import fetch from “node-fetch”;
export default (async () => {
const resp = await fetch(‘https://jsonplaceholder.typicode.com/users’);
users = resp.json();
})();
export { users };
//usingAwait.js
import promise, {users} from ‘./a.js’;
promise.then(() => {
console.log(‘usingAwait module’);
setTimeout(() => console.log(‘users:’, users), 100);
});
虽然这种方法似乎是给出了预期的结果,但是有一定的局限性:导入模块必须了解这种模式才能正确使用它。
而顶层await就可以消除这些缺点:
// a.js
const resp = await fetch(‘https://jsonplaceholder.typicode.com/users’);
const users = resp.json();
export { users};
// usingAwait.js
import {users} from ‘./a.mjs’;
console.log(users);
console.log(‘usingAwait module’);
顶级 await 在以下场景中将非常有用:
- 动态加载模块
const strings = await import(/i18n/${navigator.language}
);
- 资源初始化
const connection = await dbConnector();
- 依赖回退
let translations;
try {
translations = await import(‘https://app.fr.json’);
} catch {
translations = await import(‘https://fallback.en.json’);
}
目前,在这些地方已经支持 Top-level await:
-
V8 v8.9
-
Webpack 5.0.0
-
Babel
-
Chrome DevTools REPL
-
Node REPL
二、类的实例成员
1. 公共实例字段
公共类字段允许我们使用赋值运算符 (=) 将实例属性添加到类定义中。下面来一个计数器的例子:
import React, { Component } from “react”;
export class Incrementor extends Component {
constructor() {
super();
this.state = {
count: 0,
};
this.increment = this.increment.bind(this);
}
increment() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
Increment: {this.state.count}
);
}
}
在这个例子中,在构造函数中定义了实例字段和绑定方法,通过新的类语法,我们可以使代码更加直观。新的公共类字段语法允许我们直接将实例属性作为属性添加到类上,而无需使用构造函数方法。这样就简化了类的定义,使代码更加简洁、可读:
import React from “react”;
export class Incrementor extends React.Component {
state = { count: 0 };
increment = () => this.setState({ count: this.state.count + 1 });
render = () => (
Increment: {this.state.count}
);
}
有些小伙伴可能就疑问了,这个功能很早就可以使用了呀。但是它现在还不是标准的 ECMAScript,默认是不开启的,如果使用 create-react-app 创建 React 项目,那么它默认是启用的,否则我们必须使用正确的babel插件才能正常使用(@babel/preset-env)。
下面来看看关于公共实例字段的注意事项:
- 公共实例字段存在于每个创建的类实例上。它们要么是在
Object.defineProperty()
中添加,要么是在基类中的构造时添加(构造函数主体执行之前执行),要么在子类的super()返回之后添加:
class Incrementor {
count = 0
}
const instance = new Incrementor();
console.log(instance.count); // 0
- 未初始化的字段会自动设置为 undefined:
class Incrementor {
count
}
const instance = new Incrementor();
console.assert(instance.hasOwnProperty(‘count’));
console.log(instance.count); // undefined
- 可以进行字段的计算:
const PREFIX = ‘main’;
class Incrementor {
[${PREFIX}Count
] = 0
}
const instance = new Incrementor();
console.log(instance.mainCount); // 0
2. 私有实例字段、方法和访问器
默认情况下,ES6 中所有属性都是公共的,可以在类外检查或修改。下面来看一个例子:
class TimeTracker {
name = ‘zhangsan’;
project = ‘blog’;
hours = 0;
set addHours(hour) {
this.hours += hour;
}
get timeSheet() {
return ${this.name} works ${this.hours || 'nothing'} hours on ${this.project}
;
}
}
let person = new TimeTracker();
person.addHours = 2; // 标准 setter
person.hours = 4; // 绕过 setter 进行设置
person.timeSheet;
可以看到,在类中没有任何措施可以防止在不调用 setter 的情况下更改属性。
而私有类字段将使用哈希#前缀定义,从上面的示例中,我们可以修改它以包含私有类字段,以防止在类方法之外更改属性:
class TimeTracker {
name = ‘zhangsan’;
project = ‘blog’;
#hours = 0; // 私有类字段
set addHours(hour) {
this.#hours += hour;
}
get timeSheet() {
return ${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}
;
}
}
let person = new TimeTracker();
person.addHours = 4; // 标准 setter
person.timeSheet // zhangsan works 4 hours on blog
当我们尝试在 setter 方法之外修改私有类字段时,就会报错:
person.hours = 4 // Error Private field ‘#hours’ must be declared in an enclosing class
我们还可以将方法或 getter/setter 设为私有,只需要给这些方法名称前面加#即可:
class TimeTracker {
name = ‘zhangsan’;
project = ‘blog’;
#hours = 0; // 私有类字段
set #addHours(hour) {
this.#hours += hour;
}
get #timeSheet() {
return ${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}
;
}
constructor(hours) {
this.#addHours = hours;
console.log(this.#timeSheet);
}
}
let person = new TimeTracker(4); // zhangsan works 4 hours on blog
由于尝试访问对象上不存在的私有字段会发生异常,因此需要能够检查对象是否具有给定的私有字段。可以使用 in 运算符来检查对象上是否有私有字段:
class Example {
#field
static isExampleInstance(object) {
return #field in object;
}
}
查看更多公有和私有字段提案信息:https://github.com/tc39/proposal-class-fields
3. 静态公共字段
在ES6中,不能在类的每个实例中访问静态字段或方法,只能在原型中访问。ES 2022 将提供一种在 JavaScript 中使用 static 关键字声明静态类字段的方法。下面来看一个例子:
class Shape {
static color = ‘blue’;
static getColor() {
return this.color;
}
getMessage() {
return color:${this.color}
;
}
}
我们可以从类本身访问静态字段和方法:
console.log(Shape.color); // blue
console.log(Shape.getColor()); // blue
console.log(‘color’ in Shape); // true
console.log(‘getColor’ in Shape); // true
console.log(‘getMessage’ in Shape); // false
实例不能访问静态字段和方法:
const shapeInstance = new Shape();
console.log(shapeInstance.color); // undefined
console.log(shapeInstance.getColor); // undefined
console.log(shapeInstance.getMessage());// color:undefined
静态字段只能通过静态方法访问:
console.log(Shape.getColor()); // blue
console.log(Shape.getMessage()); //TypeError: Shape.getMessage is not a function
这里的 Shape.getMessage() 就报错了,这是因为 getMessage 不是一个静态函数,所以它不能通过类名 Shape 访问。可以通过以下方式来解决这个问题:
getMessage() {
return color:${Shape.color}
;
}
静态字段和方法是从父类继承的:
class Rectangle extends Shape { }
console.log(Rectangle.color); // blue
console.log(Rectangle.getColor()); // blue
console.log(‘color’ in Rectangle); // true
console.log(‘getColor’ in Rectangle); // true
console.log(‘getMessage’ in Rectangle); // false
4. 静态私有字段和方法
与私有实例字段和方法一样,静态私有字段和方法也使用哈希 (#) 前缀来定义:
class Shape {
static #color = ‘blue’;
static #getColor() {
return this.#color;
}
getMessage() {
return color:${Shape.#getColor()}
;
}
}
const shapeInstance = new Shape();
shapeInstance.getMessage(); // color:blue
私有静态字段有一个限制:只有定义私有静态字段的类才能访问该字段。这可能在我们使用 this 时导致出乎意料的情况:
class Shape {
static #color = ‘blue’;
static #getColor() {
return this.#color;
}
static getMessage() {
return color:${this.#color}
;
}
getMessageNonStatic() {
return color:${this.#getColor()}
;
}
}
class Rectangle extends Shape {}
console.log(Rectangle.getMessage()); // Uncaught TypeError: Cannot read private member #color from an object whose class did not declare it
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // TypeError: Cannot read private member #getColor from an object whose class did not declare it
在这个例子中,this 指向的是 Rectangle 类,它无权访问私有字段 #color。当我们尝试调用 Rectangle.getMessage() 时,它无法读取 #color 并抛出了 TypeError。可以这样来进行修改:
class Shape {
static #color = ‘blue’;
static #getColor() {
return this.#color;
}
static getMessage() {
return ${Shape.#color}
;
}
getMessageNonStatic() {
return color:${Shape.#getColor()} color
;
}
}
class Rectangle extends Shape {}
console.log(Rectangle.getMessage()); // color:blue
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // color:blue
静态字段目前是比较稳定的,并且提供了各种实现:
5. 类静态初始化块
静态私有和公共字段只能让我们在类定义期间执行静态成员的每个字段初始化。如果我们需要在初始化期间像 try … catch 一样进行异常处理,就不得不在类之外编写此逻辑。该提案就提供了一种在类声明/定义期间评估静态初始化代码块的优雅方法,可以访问类的私有字段。
先来看一个例子:
class Person {
static GENDER = “Male”
static TOTAL_EMPLOYED;
static TOTAL_UNEMPLOYED;
try {
// …
} catch {
// …
}
}
上面的代码就会引发错误,可以使用类静态块来重构它,只需将try…catch包裹在 static 中即可:
class Person {
static GENDER = “Male”
static TOTAL_EMPLOYED;
static TOTAL_UNEMPLOYED;
static {
try {
// …
} catch {
// …
}
}
}
此外,类静态块提供对词法范围的私有字段和方法的特权访问。这里需要在具有实例私有字段的类和同一范围内的函数之间共享信息的情况下很有用。
let getData;
class Person {
#x
constructor(x) {
this.#x = { data: x };
}
static {
getData = (obj) => obj.#x;
}
}
function readPrivateData(obj) {
return getData(obj).data;
}
const john = new Person([2,4,6,8]);
readPrivateData(john); // [2,4,6,8]
这里,Person 类与 readPrivateData 函数共享了私有实例属性。
三、Temporal
JavaScript 中的日期处理 Date() 对象一直是饱受诟病,该对象是1995 年受到 Java 的启发而实现的,自此就一直没有改变过。虽然Java已经放弃了这个对象,但是 Date() 仍保留在 JavaScript 中来实现浏览器的兼容。
Date() API 存在的问题:
-
只支持UTC和用户的PC时间;
-
不支持公历以外的日历;
-
字符串到日期解析容易出错;
-
Date 对象是可变的,比如:
const today = new Date();
const tomorrow = new Date(today.setDate(today.getDate() + 1));
console.log(tomorrow);
console.log(today);
此时,两个时间输出是一样的,不符合我们的预期。正因为 Date() 对象存在的种种问题。平时我们经常需要借助moment.js
、Day.js
等日期库,但是它们的体积较大,有时一个简单的日期处理就需要引入一个库,得不偿失。
目前,由于Date API 在很多库和浏览器引擎中的广泛使用,没有办法修复API的不好的部分。而改变Date API 的工作方式也很可能会破坏许多网站和库。
正因如此,TC39提出了一个全新的用于处理日期和时间的标准对象和函数——Temporal。新的Temporal API 提案旨在解决Date API的问题。它为 JavaScript 日期/时间操作带来了以下修复:
-
仅可以创建和处理不可变Temporal对象;
-
提供用于日期和时间计算的简单 API;
-
支持所有时区;
-
从 ISO-8601 格式进行严格的日期解析;
-
支持非公历。
Temporal 将取代 Moment.js 之类的库,这些库很好地填补了 JavaScript 中的空白,这种空白非常普遍,因此将功能作为语言的一部分更有意义。
由于该提案还未正式发布,所以,可以借助官方提供的prlyfill来测试。首选进行安装:
npm install @js-temporal/polyfill
导入并使用:
import { Temporal } from ‘@js-temporal/polyfill’;
console.log(Temporal);
Temporal 对象如下:
下面就来看看 Temporal 对象有哪些实用的功能。
1. 当前时间和日期
Temporal.Now 会返回一个表示当前日期和时间的对象:
// 自1970年1月1日以来的时间(秒和毫秒)
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;
文末
如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。
同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。
这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。
269页《前端大厂面试宝典》
包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。
前端面试题汇总
JavaScript
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
cn/img_convert/ca012d497e385d81af41f59005ccf698.png)
下面就来看看 Temporal 对象有哪些实用的功能。
1. 当前时间和日期
Temporal.Now 会返回一个表示当前日期和时间的对象:
// 自1970年1月1日以来的时间(秒和毫秒)
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;
文末
如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。
同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。
这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。
269页《前端大厂面试宝典》
包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。
前端面试题汇总
JavaScript
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-M16JBOhx-1713295482166)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!