├── fe
├── base
│ └── .gitkeep
├── master
│ └── .gitkeep
├── senior
│ └── .gitkeep
├── inProgress
│ └── .gitkeep
└── prompt
│ └── news.md
├── src
├── giteeApi
│ ├── .gitkeep
│ └── issue
│ │ ├── interface.ts
│ │ ├── consts.ts
│ │ ├── getIssue.ts
│ │ └── writeIssue.ts
├── mdToPDF
│ ├── .gitkeep
│ └── index.ts
├── githubApi
│ ├── file
│ │ ├── demo.html
│ │ ├── consts.ts
│ │ ├── temp.md
│ │ └── demo.md
│ ├── releaseNote
│ │ ├── interface.ts
│ │ ├── request.ts
│ │ ├── index.ts
│ │ └── helper.ts
│ ├── writeTagForLocal
│ │ ├── interface.ts
│ │ ├── request.ts
│ │ └── index.ts
│ ├── issue
│ │ ├── test.ts
│ │ ├── interface.ts
│ │ ├── updateIssue.ts
│ │ ├── consts.ts
│ │ ├── index.test.ts
│ │ ├── htmlWriteIssue.ts
│ │ ├── getReleaseNoteCount.ts
│ │ ├── search.ts
│ │ ├── writeIssue.ts
│ │ ├── index.ts
│ │ ├── getIssue.ts
│ │ └── helper.ts
│ └── otherRepo
│ │ └── nodeIndex
│ │ ├── consts.ts
│ │ └── index.ts
├── ChatGPT
│ ├── office
│ │ └── index.ts
│ └── community
│ │ └── index.ts
└── spider
│ ├── crawlee_demo
│ ├── demo2.ts
│ ├── demo3.ts
│ ├── demo5.ts
│ ├── demo1.ts
│ ├── demo4.ts
│ └── demo6.ts
│ ├── juejin
│ ├── index.ts
│ ├── __tests__
│ │ ├── getFrontendArticles.integration.test.ts
│ │ ├── getFrontendArticles.test.ts
│ │ └── utils.test.ts
│ ├── batchCrawlArticles.ts
│ ├── utils.ts
│ └── getRecentQuection.ts
│ └── job_zhipin
│ ├── index.ts
│ └── test.html
├── .gitattributes
├── jest.config.js
├── utils
├── helper.ts
├── requestKit.ts
├── repoConfig.ts
└── apiUrl.ts
├── .prettierrc
├── .gitignore
├── index.js
├── temp
└── juejin_interview
│ ├── 2025_06.md
│ ├── 2025_05.md
│ ├── 2025_01.md
│ ├── 2025_04.md
│ ├── 2024_12.md
│ ├── 2024_10_01.md
│ ├── 2025_02.md
│ ├── 2024_09_01.md
│ ├── 2024_11_02.md
│ ├── 2024_12_02.md
│ └── 2025_03.md
├── package.json
├── README.md
├── books
└── 2023年
│ ├── 0.0.14.md
│ ├── 0.0.13.md
│ ├── 2023-03-28 更新.md
│ └── 2023-06-06 更新.md
├── doc.md
└── tsconfig.json
/fe/base/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fe/master/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fe/senior/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fe/inProgress/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/giteeApi/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/mdToPDF/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/githubApi/file/demo.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=TypeScript
2 | *.html linguist-language=TypeScript
3 | *.css linguist-language=TypeScript
4 |
5 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: "ts-jest",
3 | testEnvironment: "node",
4 | testMatch: ["**/__tests__/**/*.test.ts"],
5 | };
6 |
--------------------------------------------------------------------------------
/src/githubApi/releaseNote/interface.ts:
--------------------------------------------------------------------------------
1 | export interface CreateReleaseParams {
2 | tag_name: string;
3 | name: string;
4 | body: string;
5 | }
6 |
--------------------------------------------------------------------------------
/src/githubApi/writeTagForLocal/interface.ts:
--------------------------------------------------------------------------------
1 | export interface WriteContentForLocalOptions {
2 | path: string;
3 | fileName: string;
4 | content: string;
5 | }
6 |
--------------------------------------------------------------------------------
/src/giteeApi/issue/interface.ts:
--------------------------------------------------------------------------------
1 | export interface WriteRequestOptions {
2 | title: string;
3 | body?: string;
4 | milestone?: number;
5 | labels?: string;
6 | }
7 |
--------------------------------------------------------------------------------
/src/githubApi/issue/test.ts:
--------------------------------------------------------------------------------
1 | import { search } from "@src/githubApi/issue/search";
2 |
3 | search(["forwardRef"]).then(res => {
4 | console.log("yanle - logger: res", res?.toLocaleString() || res);
5 | });
6 |
--------------------------------------------------------------------------------
/utils/helper.ts:
--------------------------------------------------------------------------------
1 | export function base64ToString(b64: string) {
2 | return Buffer.from(b64, "base64").toString();
3 | }
4 |
5 | export function stringToBase64(str: string) {
6 | return Buffer.from(str).toString("base64");
7 | }
8 |
--------------------------------------------------------------------------------
/src/githubApi/file/consts.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | export const htmlPath = path.resolve(__dirname, "./demo.html");
4 | export const tempFilePath = path.resolve(__dirname, "./temp.md");
5 | export const filePath = path.resolve(__dirname, "./demo.md");
6 |
--------------------------------------------------------------------------------
/utils/requestKit.ts:
--------------------------------------------------------------------------------
1 | import { Octokit } from "octokit";
2 | import axios from "axios";
3 | const config = require("./configToken.json");
4 |
5 | export const octokit = new Octokit({
6 | auth: config.token,
7 | });
8 |
9 | export const giteeApi = axios.create();
10 |
--------------------------------------------------------------------------------
/src/githubApi/issue/interface.ts:
--------------------------------------------------------------------------------
1 | export interface WriteIssueOptions {
2 | title: string;
3 | body: (() => string) | string;
4 | labels?: string[];
5 | milestone?: number;
6 | }
7 |
8 | export interface UpdateIssueOptions extends WriteIssueOptions {
9 | issue_number?: string | number;
10 | }
11 |
--------------------------------------------------------------------------------
/src/githubApi/otherRepo/nodeIndex/consts.ts:
--------------------------------------------------------------------------------
1 | export const labels = {
2 | react: "React 专题",
3 | js: "JS 与 ES",
4 | style: "css 与 样式",
5 | interview: "面试问题",
6 | canvas: "canvas",
7 | algorithm: "数据结构、算法、设计模式",
8 | chrome: "浏览器",
9 | engineering: "工程化",
10 | linuxDevops: "Linux & Devops",
11 | recommend: "总结归档",
12 | optimization: "性能优化",
13 | okr: "OKR",
14 | node: "NodeJS",
15 | application: "应用类",
16 | test: "单元测试",
17 | chromeExtensions: "谷歌浏览器扩展程序",
18 | };
19 |
--------------------------------------------------------------------------------
/src/giteeApi/issue/consts.ts:
--------------------------------------------------------------------------------
1 | import { MileStone } from "@src/githubApi/issue/consts";
2 | import repoConfig from "@utils/repoConfig";
3 |
4 | export const giteeMileStone = {
5 | [MileStone.base]: 184143, // 初级
6 | [MileStone.inProgress]: 184144, // 中级
7 | [MileStone.senior]: 184145, // 高级别
8 | [MileStone.master]: 184146, // 资深
9 | };
10 |
11 | const { owner, repo } = repoConfig.gitee.interviewRepo;
12 | const { access_token } = repoConfig.gitee;
13 |
14 | export { owner, repo, access_token };
15 |
--------------------------------------------------------------------------------
/src/giteeApi/issue/getIssue.ts:
--------------------------------------------------------------------------------
1 | import { giteeApiUrl } from "@utils/apiUrl";
2 | import { giteeApi } from "@utils/requestKit";
3 | import { access_token, owner, repo } from "@src/giteeApi/issue/consts";
4 | import dayjs from "dayjs";
5 |
6 | // 发起请求
7 | export const getIssueRequest = (preDate: string) => giteeApi.get(giteeApiUrl.getIssue(owner, repo), {
8 | params: {
9 | access_token,
10 | owner,
11 | repo,
12 | per_page: 100,
13 | page: 1,
14 | since: dayjs(preDate).format("YYYY-MM-DDTHH:mm:ssZ"),
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "bracketSpacing": true,
4 | "embeddedLanguageFormatting": "auto",
5 | "htmlWhitespaceSensitivity": "css",
6 | "insertPragma": false,
7 | "jsxBracketSameLine": false,
8 | "jsxSingleQuote": false,
9 | "printWidth": 120,
10 | "proseWrap": "preserve",
11 | "quoteProps": "as-needed",
12 | "requirePragma": false,
13 | "semi": true,
14 | "singleQuote": false,
15 | "tabWidth": 2,
16 | "trailingComma": "es5",
17 | "useTabs": false,
18 | "vueIndentScriptAndStyle": false
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | coverage/
8 | /doc/
9 | /mock2easy/
10 |
11 | # production
12 | /build
13 | /coverage
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 | .idea
22 | .idea/
23 | .vscode/
24 |
25 |
26 | npm-debug.log*
27 | yarn-debug.log*
28 | yarn-error.log*
29 | yarn.lock
30 | package-lock.json
31 |
32 | configToken.json
33 | authConfigToken.ts
34 |
35 | storage
36 |
--------------------------------------------------------------------------------
/src/ChatGPT/office/index.ts:
--------------------------------------------------------------------------------
1 | // 使用官方 api
2 |
3 | const config = require("@utils/configToken.json");
4 | const { Configuration, OpenAIApi } = require("openai");
5 |
6 | const configuration = new Configuration({
7 | apiKey: config.openai_api_key,
8 | });
9 | const openai = new OpenAIApi(configuration);
10 |
11 | const main = async () => {
12 | const completion = await openai.createCompletion({
13 | model: "text-davinci-003",
14 | prompt: "代理的方式有哪些?",
15 | });
16 |
17 | console.log(completion.data.choices[0].text);
18 | };
19 |
20 | main();
21 |
22 | export {};
23 |
--------------------------------------------------------------------------------
/src/mdToPDF/index.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs";
2 | import * as path from "path";
3 | import { mdToPdf } from "md-to-pdf";
4 |
5 | const main = async () => {
6 | const filePath = path.resolve(__dirname, "../../books/2023-08-20 更新.md");
7 | const outputPath = path.resolve(__dirname, "../../books/2023-08-20 更新.pdf");
8 |
9 | const pdf = await mdToPdf({ path: filePath }, { page_media_type: "print" }).catch(console.error);
10 |
11 | if (pdf) fs.writeFileSync(outputPath, pdf.content);
12 |
13 | console.log('yanle - logger: ', filePath);
14 | };
15 |
16 | main();
17 |
18 | export {};
19 |
--------------------------------------------------------------------------------
/src/githubApi/issue/updateIssue.ts:
--------------------------------------------------------------------------------
1 | import { UpdateIssueOptions } from "@src/githubApi/issue/interface";
2 | import { octokit } from "@utils/requestKit";
3 | import { apiUrl } from "@utils/apiUrl";
4 | import repoConfig from "@utils/repoConfig";
5 |
6 | // 更新
7 | const update = (options: UpdateIssueOptions) => octokit.request(apiUrl.updateIssue, {
8 | ...options,
9 | ...repoConfig.interviewRepo,
10 | });
11 |
12 | // 更新 issue
13 | export const updateIssue = async (remote: any) => {
14 | const promiseList = [
15 | // 写入 github
16 | () => update({
17 | ...remote,
18 | body: remote.body(),
19 | }),
20 |
21 | ];
22 |
23 |
24 | };
25 |
--------------------------------------------------------------------------------
/src/githubApi/writeTagForLocal/request.ts:
--------------------------------------------------------------------------------
1 | import dayjs from "dayjs";
2 | import { octokit } from "@utils/requestKit";
3 | import { apiUrl } from "@utils/apiUrl";
4 | import repoConfig from "@utils/repoConfig";
5 |
6 | /**
7 | * @param path 更新文件的 path
8 | * @param content 更新文件的内容, base 64 格式更新
9 | */
10 | export const updateContentFile = (path: string, content: string) => {
11 | return octokit.request(apiUrl.updateContent, {
12 | ...repoConfig.interviewRepo,
13 | path,
14 | message: `update - file: ${dayjs().format("YYYY-MM-DDTHH:mm:ssZ")}`,
15 | committer: {
16 | name: "yanlele",
17 | email: "331393627@qq.com",
18 | },
19 | content,
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/src/githubApi/issue/consts.ts:
--------------------------------------------------------------------------------
1 | export enum MileStone {
2 | base = 1, // 初级
3 | inProgress, // 中级
4 | senior, // 高级别
5 | master, // 资深
6 | }
7 |
8 | export const labels = {
9 | network: "网络",
10 | js: "JavaScript",
11 | ts: "TypeScript",
12 | node: "Nodejs",
13 | css: "CSS",
14 | chrome: "浏览器",
15 | frameWork: "web框架",
16 | engineering: "工程化",
17 | application: "web应用场景",
18 | code: "代码实现/算法",
19 | };
20 |
21 | export const company = {
22 | alibaba: "阿里巴巴",
23 | tencent: "腾讯",
24 | baidu: "百度",
25 | mi: "小米",
26 | mt: "美团",
27 | pdd: "PDD",
28 | jd: "京东",
29 | netEase: "网易",
30 | shopee: "Shopee",
31 | quic: "快手",
32 | dd: "滴滴",
33 | xiaohongshu: "小红书",
34 | other: "TOP100互联网",
35 | };
36 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo2.ts:
--------------------------------------------------------------------------------
1 | import { PlaywrightCrawler, Dataset } from "crawlee";
2 |
3 | const crawler = new PlaywrightCrawler({
4 | async requestHandler({ request, page, enqueueLinks, log }) {
5 | const title = await page.title();
6 | log.info(`Title of ${request.loadedUrl} is '${title}'`);
7 | await Dataset.pushData({ title, url: request.loadedUrl });
8 | await enqueueLinks();
9 | },
10 | // When you turn off headless mode, the crawler
11 | // will run with a visible browser window.
12 | headless: false,
13 |
14 | // Let's limit our crawls to make our tests shorter and safer.
15 | maxRequestsPerCrawl: 50,
16 | });
17 |
18 | // Add first URL to the queue and start the crawl.
19 | crawler.run(["https://crawlee.dev"]);
20 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | let obj = {
2 | name: "yanle",
3 | age: 20,
4 | getName: () => {
5 | const _getName = () => {
6 | console.log("this.getName", this.name);
7 | };
8 | _getName();
9 | },
10 | getAge: function() {
11 | const _getAge = () => {
12 | console.log("this.getAge", this.age);
13 | };
14 | _getAge();
15 | },
16 | extend: {
17 | name: "le",
18 | age: 20,
19 | getName: function() {
20 | console.log("name: ", this.name);
21 | },
22 | getAge: () => {
23 | console.log("age: ", this.age);
24 | },
25 | },
26 | };
27 |
28 | obj.getName();
29 | obj.getAge();
30 |
31 | obj.extend.getName();
32 | obj.extend.getAge();
33 |
34 | obj.extend.getName.bind(obj)();
35 | obj.extend.getAge.bind(obj)();
36 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo3.ts:
--------------------------------------------------------------------------------
1 | import { RequestQueue, CheerioCrawler } from "crawlee";
2 |
3 | const runner = async () => {
4 | const requestQueue = await RequestQueue.open();
5 | await requestQueue.addRequest({ url: "https://crawlee.dev" });
6 |
7 | const crawler = new CheerioCrawler({
8 | requestQueue,
9 | // The `$` argument is the Cheerio object
10 | // which contains parsed HTML of the website.
11 | async requestHandler({ $, request }) {
12 | // Extract
text with Cheerio.
13 | // See Cheerio documentation for API docs.
14 | const title = $("title").html();
15 | console.log(`The title of "${request.url}" is: ${title}.`);
16 | },
17 | });
18 |
19 | await crawler.run();
20 | };
21 |
22 | runner();
23 |
--------------------------------------------------------------------------------
/fe/prompt/news.md:
--------------------------------------------------------------------------------
1 | # 角色:
2 |
3 | 你是一位具有 20 年工作经验的资深 Web 前端技术开发工程师。
4 |
5 | ## 目标:
6 |
7 | - 扫描全网获取最近双周内的 Web 前端技术领域的最新热点文章。
8 | - 总结并编写一份详细的双周前端领域热点周报。
9 |
10 | ## 技能:
11 |
12 | - 深厚的 Web 前端技术知识和行业经验。
13 | - 强大的信息搜集和分析能力。
14 |
15 | ## 工作流程:
16 |
17 | 1. 使用网络搜索工具和技术社区资源,搜集最近双周内发布的关于 Web 前端技术的文章。
18 | 2. 筛选涉及行业动态与趋势、框架与工具、新型技术、AI 发展、web 前端就业与职业发展、以及其他值得关注的方向的文章。
19 | 3. 从每个话题中至少选择 3 篇,最多五篇最具影响力或最具信息价值的文章。
20 | 4. 为每篇选定的文章提供一个超链接形式的出处。
21 | 5. 对每篇文章撰写不少于 200 字的总结,并展示你的专业见解和对行业动态的深刻理解。
22 |
23 | ## 约束:
24 |
25 | - 必须确保所有信息的准确性和最新性。
26 | - 每个话题下的文章数量不得超过五篇。
27 | - 文章结构要稍微轻松一点儿, 不要过于有板有眼。
28 |
29 | ## 输出格式:
30 |
31 | 输出应为一个结构化的报告,包括以下内容:
32 |
33 | - 报告标题:最新双周前端领域热点周报【双周日期】
34 | - 每个话题的标题和相关文章列表
35 | - 文章标题
36 | - 不少于 200 字的文章总结
37 | - 给出你对文章的专业见解,锐评, 风趣幽默型
38 | - 文章和评论应采用专业且信息丰富的文风。
39 |
--------------------------------------------------------------------------------
/src/ChatGPT/community/index.ts:
--------------------------------------------------------------------------------
1 | // To use ESM in CommonJS, you can use a dynamic import
2 | const importDynamic = new Function("modulePath", "return import(modulePath)");
3 | const config = require("@utils/configToken.json");
4 |
5 | const main = async () => {
6 | const { ChatGPTUnofficialProxyAPI } = await importDynamic("chatgpt");
7 | const api = new ChatGPTUnofficialProxyAPI({
8 | accessToken: config.chatGpt_access_token,
9 | apiReverseProxyUrl: "https://gpt.pawan.krd/backend-api/conversation",
10 | debug: true,
11 | });
12 |
13 | api
14 | .sendMessage("JS 实现 Promise", {
15 | timeoutMs: 6 * 60 * 1000,
16 | debug: true,
17 | })
18 | .then((res: any) => {
19 | console.log(res.text);
20 | });
21 | };
22 |
23 | main();
24 |
25 | export {};
26 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo5.ts:
--------------------------------------------------------------------------------
1 | import { Dataset } from "crawlee";
2 |
3 | const runner = async () => {
4 | // Write a single row to the default dataset
5 | await Dataset.pushData({ col1: 123, col2: "val2" });
6 |
7 | // Open a named dataset
8 | const dataset = await Dataset.open("default");
9 |
10 | // Write a single row
11 | await dataset.pushData({ foo: "bar" });
12 |
13 | // Write multiple rows
14 | await dataset.pushData([{ foo: "bar2", col2: "val2" }, { col3: 123 }]);
15 |
16 | // Export the entirety of the dataset to one file in the key-value store
17 | // await dataset.exportToCSV("MY-DATA");
18 |
19 | const res = await dataset.getData({
20 | fields: ["col2", "col1"],
21 | });
22 |
23 | console.log(`[yanle] - res`, res);
24 |
25 | dataset.exportToJSON("data_source_demo");
26 |
27 | // await dataset.forEach(async (item, index) => {
28 | // console.log(`Item at ${index}: ${JSON.stringify(item)}`);
29 | // });
30 | };
31 |
32 | runner();
33 |
--------------------------------------------------------------------------------
/src/githubApi/issue/index.test.ts:
--------------------------------------------------------------------------------
1 | // 获取对应的 tag
2 | import { getDataIssue, getTag } from "@src/githubApi/releaseNote/request";
3 | import { filter, get } from "lodash";
4 | import dayjs from "dayjs";
5 |
6 | /**
7 | * 过滤时间问题
8 | */
9 | const main = async () => {
10 | const preTagRes = await getTag("0.0.21");
11 | // console.log("yanle - logger: preTagRes", preTagRes);
12 |
13 | // 获取上一次时间戳
14 | // 上一次创建的时间
15 | const createDate = get(preTagRes, "data.created_at", "");
16 |
17 | const issueRes = await getDataIssue(createDate);
18 |
19 | // console.log("yanle - logger: issueRes", issueRes.data);
20 |
21 | const filterData = filter(issueRes.data, item => {
22 | // 必须要在上一次创建时间之后
23 | return dayjs(item.created_at).isAfter(createDate);
24 | });
25 |
26 | console.log("yanle - logger: filterData", {
27 | createDate,
28 | numberList: filterData.map(item => item.number),
29 | length: filterData.length,
30 | });
31 | };
32 |
33 | main();
34 |
35 | export {};
36 |
--------------------------------------------------------------------------------
/src/giteeApi/issue/writeIssue.ts:
--------------------------------------------------------------------------------
1 | import { giteeApi } from "@utils/requestKit";
2 | import { giteeApiUrl } from "@utils/apiUrl";
3 | import repoConfig from "@utils/repoConfig";
4 | import { access_token, giteeMileStone, owner, repo } from "@src/giteeApi/issue/consts";
5 | import { labels, MileStone } from "@src/githubApi/issue/consts";
6 | import { WriteRequestOptions } from "@src/giteeApi/issue/interface";
7 |
8 | export const writeRequest = (options: WriteRequestOptions) => giteeApi.post(giteeApiUrl.createIssue(owner), {
9 | access_token,
10 | owner,
11 | repo,
12 | ...options,
13 | });
14 |
15 | // const params = {
16 | // title: "测试一下",
17 | // body: `## 一下哈`,
18 | // milestone: giteeMileStone[MileStone.base],
19 | // labels: [labels.js].join(","),
20 | // };
21 |
22 | export const giteeWriteIssue = async (options: WriteRequestOptions) => {
23 | const res = await writeRequest(options);
24 | console.log(`yanle - logger: 写入 gitee - ${options.title} `, res.status);
25 | };
26 |
27 | // giteeWriteIssue(params);
28 |
--------------------------------------------------------------------------------
/src/githubApi/writeTagForLocal/index.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs";
2 | import { updateContentFile } from "./request";
3 | import { WriteContentForLocalOptions } from "@src/githubApi/writeTagForLocal/interface";
4 |
5 | /**
6 | * 读取最近的文档 然后写入本地 markdown
7 | */
8 | export const writeContentForLocal = async (options: WriteContentForLocalOptions) => {
9 | const { path, fileName, content } = options;
10 | const writePath = `${path}/${fileName}.md`;
11 | // 文件写入本地
12 | console.log("yanle - logger: 开始写入本地");
13 | fs.writeFileSync(writePath, content, { encoding: "utf-8" });
14 | console.log("yanle - logger: 写入本地完成");
15 |
16 | const base64File = fs.readFileSync(writePath, { encoding: "base64" });
17 | console.log("yanle - logger: 读取本地文件完成");
18 |
19 | // 提交到 github
20 | const updateFileRes = await updateContentFile(`books/${fileName}.md`, base64File);
21 |
22 | console.log("yanle - logger: 提交到 github 完成", updateFileRes.status);
23 |
24 | // 文件从本地删除
25 | fs.unlinkSync(writePath);
26 | };
27 |
28 | export {};
29 |
--------------------------------------------------------------------------------
/utils/repoConfig.ts:
--------------------------------------------------------------------------------
1 | const { gitee_api_token } = require("./configToken.json");
2 |
3 | const repoConfig = {
4 | interviewRepo: {
5 | owner: "pro-collection",
6 | repo: "interview-question",
7 | header: {
8 | "X-GitHub-Api-Version": "2022-11-28",
9 | },
10 | },
11 | booksWithInterviewRepo: {
12 | owner: "pro-collection",
13 | repo: "interview-question-books",
14 | header: {
15 | "X-GitHub-Api-Version": "2022-11-28",
16 | },
17 | },
18 | nodeIndex: {
19 | owner: "yanlele",
20 | repo: "node-index",
21 | header: {
22 | "X-GitHub-Api-Version": "2022-11-28",
23 | },
24 | },
25 | yanleleInfo: {
26 | owner: "yanlele",
27 | repo: "interview-question",
28 | header: {
29 | "X-GitHub-Api-Version": "2022-11-28",
30 | },
31 | },
32 | gitee: {
33 | access_token: gitee_api_token,
34 | interviewRepo: {
35 | owner: "yanleweb",
36 | repo: "interview-question",
37 | },
38 | },
39 | };
40 |
41 | export default repoConfig;
42 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo1.ts:
--------------------------------------------------------------------------------
1 | import { CheerioCrawler, Dataset } from "crawlee";
2 |
3 | // CheerioCrawler crawls the web using HTTP requests
4 | // and parses HTML using the Cheerio library.
5 | const crawler = new CheerioCrawler({
6 | // Use the requestHandler to process each of the crawled pages.
7 | async requestHandler({ request, $, enqueueLinks, log }) {
8 | const title = $("title").text();
9 | const body = $("body").text();
10 | log.info(`Title of ${request.loadedUrl} is '${title}'`);
11 | console.log(`[yanle] - title`, `Title of ${request.loadedUrl} is '${title}'`);
12 |
13 | // Save results as JSON to ./storage/datasets/default
14 | await Dataset.pushData({ title, url: request.loadedUrl });
15 |
16 | // Extract links from the current page
17 | // and add them to the crawling queue.
18 | await enqueueLinks();
19 | },
20 |
21 | // Let's limit our crawls to make our tests shorter and safer.
22 | maxRequestsPerCrawl: 50,
23 | });
24 |
25 | // Add first URL to the queue and start the crawl.
26 | crawler.run(["https://crawlee.dev"]);
27 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo4.ts:
--------------------------------------------------------------------------------
1 | // Instead of CheerioCrawler let's use Playwright
2 | // to be able to render JavaScript.
3 | import { PlaywrightCrawler } from "crawlee";
4 |
5 | const crawler = new PlaywrightCrawler({
6 | // headless: false,
7 | requestHandler: async ({ page }) => {
8 | // Wait for the actor cards to render.
9 | await page.waitForSelector(".article-item-link");
10 | // Execute a function in the browser which targets
11 | // the actor card elements and allows their manipulation.
12 | const categoryTexts = await page.$$eval(".article-item-link", (els) => {
13 | // Extract text content from the actor cards
14 | return els.map((el) => {
15 | return {
16 | url: el.getAttribute("href"),
17 | name: el.querySelector(".article-detail")?.firstChild?.textContent,
18 | };
19 | });
20 | });
21 | categoryTexts.forEach((text, i) => {
22 | console.log(`CATEGORY_${i + 1}: ${JSON.stringify(text, undefined, 2)}\n`);
23 | });
24 | },
25 | });
26 |
27 | // 前端热榜
28 | crawler.run(["https://juejin.cn/hot/articles/6809637767543259144"]);
29 |
--------------------------------------------------------------------------------
/src/spider/juejin/index.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import * as cheerio from "cheerio";
3 | import fs from "fs";
4 | import { writeToTemp } from "@src/githubApi/issue/helper";
5 | import { htmlPath, tempFilePath } from "@src/githubApi/file/consts";
6 |
7 | const url = "https://juejin.cn/post/7354940230301057033#heading-6";
8 |
9 | const main = async () => {
10 | console.log("yanle - logger: 获取文章, 链接:", url);
11 |
12 | const res = await axios.get(url);
13 |
14 | console.log("yanle - logger: 文章获取成功");
15 |
16 | const content = res?.data;
17 |
18 | const $ = cheerio.load(content);
19 |
20 | const articleHtml = $("#article-root").html() || "";
21 |
22 | if (!articleHtml) {
23 | console.log("yanle - logger: 没有获取到 html 文件, 写入失败");
24 | }
25 |
26 | // html 写入本地
27 | fs.writeFileSync(htmlPath, articleHtml, { encoding: "utf-8" });
28 |
29 | console.log("yanle - logger: 写入 html 成功, 文件路径: ", htmlPath);
30 |
31 | // 读取 html 转 markdown --> 输出文档为 temp file
32 | await writeToTemp(tempFilePath, htmlPath);
33 |
34 | console.log("yanle - logger: 写入 temp 成功, 文件路径: ", tempFilePath);
35 | };
36 |
37 | main().then();
38 |
--------------------------------------------------------------------------------
/src/spider/job_zhipin/index.ts:
--------------------------------------------------------------------------------
1 | // Import puppeteer
2 | import puppeteer from "puppeteer";
3 | import * as cheerio from "cheerio";
4 | import { includes } from "lodash";
5 |
6 | (async () => {
7 | // Launch the browser
8 | const browser = await puppeteer.launch({
9 | headless: true,
10 | defaultViewport: {
11 | width: 1460,
12 | height: 900,
13 | },
14 | });
15 |
16 | // Create a page
17 | const page = await browser.newPage();
18 |
19 | // Go to your site
20 | await page.goto("https://www.zhipin.com/web/geek/job?query=rust&city=101270100");
21 |
22 | // 等待这个请求
23 | page
24 | .waitForResponse(() => true)
25 | .then(async (res) => {
26 | // console.log(`[yanle] - res url`, res.url());
27 | console.log(`[yanle] - res`, await res?.text?.());
28 | });
29 |
30 | const queryPath =
31 | "#wrap > div.page-job-wrapper > div.page-job-inner > div > div.job-list-wrapper > div.search-job-result > ul > li:nth-child(1)";
32 | await page.waitForSelector(queryPath);
33 |
34 | const html = await page.content();
35 | // console.log(`[yanle] - html`, html);
36 |
37 | // const $ = cheerio.load(html);
38 |
39 | // Close browser.
40 | await browser.close();
41 | })();
42 |
--------------------------------------------------------------------------------
/src/githubApi/issue/htmlWriteIssue.ts:
--------------------------------------------------------------------------------
1 | import { join, isFunction } from "lodash";
2 | import { WriteIssueOptions } from "./interface";
3 | import { octokit } from "@utils/requestKit";
4 | import { apiUrl } from "@utils/apiUrl";
5 | import repoConfig from "@utils/repoConfig";
6 | import { MileStone } from "@src/githubApi/issue/consts";
7 | import { giteeWriteIssue } from "@src/giteeApi/issue/writeIssue";
8 | import { giteeMileStone } from "@src/giteeApi/issue/consts";
9 | import { commitPush, writeToTemp } from "@src/githubApi/issue/helper";
10 |
11 | const write = (options: WriteIssueOptions) => octokit.request(apiUrl.writeIssue, {
12 | ...options,
13 | ...repoConfig.interviewRepo,
14 | });
15 |
16 | export const htmlWriteIssue = async (remote: any) => {
17 | // 写入本地
18 | await writeToTemp("./demo.md");
19 |
20 | const allPromise = [
21 | write({
22 | ...remote,
23 | body: remote.body(),
24 | }),
25 | giteeWriteIssue({
26 | title: remote.title,
27 | body: remote.body(),
28 | labels: join(remote.labels, ","),
29 | milestone: giteeMileStone[remote.milestone as MileStone],
30 | }),
31 | ];
32 |
33 | const [githubRes] = await Promise.all(allPromise);
34 | console.log(`yanle - logger: 写入 github - ${remote.title}`, githubRes?.status);
35 |
36 | await commitPush(remote.title);
37 | };
38 |
39 | export {};
40 |
--------------------------------------------------------------------------------
/src/githubApi/issue/getReleaseNoteCount.ts:
--------------------------------------------------------------------------------
1 | import dayjs from "dayjs";
2 | import utc from "dayjs/plugin/utc";
3 | import timezone from "dayjs/plugin/timezone";
4 | import { base64ToString, stringToBase64 } from "@utils/helper";
5 | import { filter, findLastIndex, get, map } from "lodash";
6 | import { getDataIssue, getPackageJson, getTag } from "../releaseNote/request";
7 |
8 | dayjs.extend(utc);
9 | dayjs.extend(timezone);
10 |
11 | /**
12 | * 获取当前版本 issue 数量
13 | */
14 | export const getIssueContentWithCurrentVersion = async () => {
15 | // 获取 package.json
16 | const res = await getPackageJson();
17 | console.log("yanle - logger: 获取 package json 完成");
18 | const sha = get(res, "data.sha");
19 | let packageString = base64ToString(get(res, "data.content"));
20 | const packageJson = JSON.parse(packageString);
21 | const currentVersion = Reflect.get(packageJson, "version");
22 |
23 | // 获取对应的 tag
24 | const preTagRes = await getTag(currentVersion);
25 |
26 | // 获取上一次时间戳
27 | const createDate = get(preTagRes, "data.created_at", "");
28 |
29 | // 获取最新的 issue
30 | const issueRes = await getDataIssue(createDate);
31 |
32 | // 通过创建时间 过滤
33 | const filterData = filter(issueRes?.data, (item) => {
34 | // 必须要在上一次创建时间之后
35 | return dayjs(item.created_at).isAfter(createDate);
36 | });
37 |
38 | return {
39 | issueList: filterData,
40 | };
41 | };
42 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_06.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 |
3 | - `点赞量: 156` - [面试分享:二本靠 7 轮面试成功拿下大厂 P6](https://juejin.cn/post/7513059488418725923)
4 | - `点赞量: 139` - [面试官:怎么禁止用户复制?](https://juejin.cn/post/7513557849243762724)
5 | - `点赞量: 124` - [为什么你们的前端视野只剩下 Vue 和 React?](https://juejin.cn/post/7517567528667758628)
6 | - `点赞量: 117` - [面试官问我,后端一次性返回十万条数据,前端应该怎么处理 ?](https://juejin.cn/post/7515471025503977526)
7 | - `点赞量: 64` - [👨 面试官:你为什么用 TS,别人用你就用?](https://juejin.cn/post/7511290103962714122)
8 | - `点赞量: 43` - [面试官:你给我讲讲 async/await](https://juejin.cn/post/7512745040305913891)
9 | - `点赞量: 26` - [一个自由职业者的 2025 年中总结:主业+探索](https://juejin.cn/post/7519046309435113510)
10 | - `点赞量: 22` - [面试官:dom 更新是异步的吗?为什么还要 nextTick 才能获取到修改后的值。](https://juejin.cn/post/7512293960217247770)
11 | - `点赞量: 15` - [👨 面试官:你为什么用 Less / Scss ?别人用你就用?🤔](https://juejin.cn/post/7519121073544118307)
12 | - `点赞量: 13` - [鸽了六年的某大厂面试题:你会手写一个模板引擎吗?](https://juejin.cn/post/7519376321875279922)
13 |
14 | - `点赞量: 12` - [为什么面试问的越详细反而没有后文了?](https://juejin.cn/post/7520584067193126927)
15 |
16 | ### 后端
17 |
18 | - `点赞量: 48` - [支付宝开放平台,这谁写的,要扣绩效吧](https://juejin.cn/post/7515965961809690675)
19 | - `点赞量: 47` - [面试官:千万级订单表新增字段怎么弄?](https://juejin.cn/post/7513560069276876834)
20 | - `点赞量: 45` - [面试官问:MySQL 为什么不能用 Docker 部署吗?答错直接挂!](https://juejin.cn/post/7519723338892361737)
21 | - `点赞量: 36` - [ 京东二面:分库分表后翻页 100 万条,怎么设计?答对这题直接给 P7!](https://juejin.cn/post/7517116929376043059)
22 | - `点赞量: 32` - [MySQL 8.0 SQL 优化黑科技,面试官都不一定知道!](https://juejin.cn/post/7512744868957323279)
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "interview-question",
3 | "version": "0.0.78",
4 | "description": "想做一个很全的面试题库工程",
5 | "main": "index.js",
6 | "scripts": {
7 | "write": "ts-node src/githubApi/issue/index.ts",
8 | "release": "ts-node src/githubApi/releaseNote/index.ts",
9 | "juejin_spider": "ts-node src/spider/juejin/getRecentQuection.ts",
10 | "juejin_crawl_articles": "ts-node src/spider/juejin/batchCrawlArticles.ts",
11 | "test": "jest"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/yanlele/interview-question.git"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/yanlele/interview-question/issues"
21 | },
22 | "homepage": "https://github.com/yanlele/interview-question#readme",
23 | "devDependencies": {
24 | "@types/jest": "^29.5.14",
25 | "@types/lodash": "^4.14.191",
26 | "@types/node": "^18.14.6",
27 | "jest": "^29.7.0",
28 | "ts-jest": "^29.2.5",
29 | "ts-node": "^10.9.1",
30 | "tsconfig-paths": "^4.1.2",
31 | "typescript": "^4.9.5"
32 | },
33 | "dependencies": {
34 | "@inquirer/prompts": "^3.3.0",
35 | "axios": "^1.3.4",
36 | "chatgpt": "^5.0.6",
37 | "cheerio": "1.0.0-rc.12",
38 | "crawlee": "^3.11.5",
39 | "dayjs": "^1.11.7",
40 | "html-to-md": "^0.8.3",
41 | "lodash": "^4.17.21",
42 | "md-to-pdf": "^5.2.1",
43 | "octokit": "^2.0.14",
44 | "openai": "^3.2.1",
45 | "playwright": "^1.48.0",
46 | "puppeteer": "^19.9.1"
47 | }
48 | }
--------------------------------------------------------------------------------
/src/githubApi/issue/search.ts:
--------------------------------------------------------------------------------
1 | import { apiUrl } from "@utils/apiUrl";
2 | import { get, sum } from "lodash";
3 | import dayjs from "dayjs";
4 | import axios from "axios";
5 | import repoConfig from "@utils/repoConfig";
6 |
7 | const request = (q: string, created: string) => {
8 | const url = apiUrl.searchIssue(q, created);
9 | console.log("yanle - logger: 获取热度 URL", url);
10 | return axios.request({
11 | url,
12 | method: "get",
13 | });
14 | };
15 |
16 | /**
17 | * 搜索 issue repo
18 | * @returns
19 | */
20 | const searchWithRepo = () => {
21 | const url = apiUrl.searchIssueWithRepo(repoConfig.interviewRepo.owner, repoConfig.interviewRepo.repo, "react", "1");
22 | console.log(`[yanle] - url: `, url);
23 | return axios.request({
24 | url,
25 | method: "get",
26 | });
27 | };
28 |
29 | export const search = async (search: string[]) => {
30 | const created = dayjs().subtract(1, "year").format("YYYY-MM-DD");
31 |
32 | const promiseList = [];
33 | for (let i = 0; i < search.length; i++) {
34 | promiseList.push(request(search[i], created).then((res) => get(res, "data.total_count", 0)));
35 | }
36 | const res = await Promise.all(promiseList);
37 | for (let i = 0; i < res.length; i++) {
38 | console.log(`yanle - logger: 关键词: ${search[i]}, 对应搜索热度: ${res[i]}`);
39 | }
40 | return sum(res);
41 | };
42 |
43 | // todo 测试
44 | // searchWithRepo().then((res) => {
45 | // console.log(`[yanle] - res`, res.data.items);
46 | // console.log(
47 | // `[yanle] - title`,
48 | // map(res.data, (item) => item.title)
49 | // );
50 | // });
51 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_05.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 |
3 | - `点赞量: 200` - [小红书一面:长达一个小时的拷打 😭](https://juejin.cn/post/7504973778944032808)
4 | - `点赞量: 120` - [面试官:前端批量请求失败 Toast 重复弹窗怎么解决?](https://juejin.cn/post/7504247651577479180)
5 | - `点赞量: 69` - [🔥 面试官:Teleport 是怎么实现的?为啥它能把组件“传送”走?](https://juejin.cn/post/7509033290054631476)
6 | - `点赞量: 61` - [为什么我会执着于使用 NextJs 开发项目 🫠🫠🫠](https://juejin.cn/post/7501657041606492200)
7 | - `点赞量: 60` - [2025 前端面试题-React 进阶篇](https://juejin.cn/post/7504545616841965583)
8 | - `点赞量: 30` - [前端最新面试题及答案 (2025) ](https://juejin.cn/post/7503857922466234403)
9 | - `点赞量: 25` - [都 2025 年了,面试官说你不会双向绑定就不要来面试!](https://juejin.cn/post/7501783144440037426)
10 | - `点赞量: 24` - [2025 前端面试题-Vue3 基础篇](https://juejin.cn/post/7503111373468893193)
11 | - `点赞量: 15` - [「👨 面试官:谁跟你说最常见的状态码是 200?」](https://juejin.cn/post/7501966297333792778)
12 |
13 | ### 后端
14 |
15 | - `点赞量: 256` - [字节一面:20 亿手机号存储选 int 还是 string?varchar 还是 char?为什么?](https://juejin.cn/post/7501105891158310966)
16 | - `点赞量: 166` - [同志们,我去外包了](https://juejin.cn/post/7510055871465308212)
17 | - `点赞量: 89` - [阿里面试:千万级大表如何快速删除大量数据](https://juejin.cn/post/7499021253459656742)
18 | - `点赞量: 86` - [靠谱!2025 年 8 大程序员接单、软件外包平台推荐](https://juejin.cn/post/7506436235511545867)
19 | - `点赞量: 68` - [打印高质量日志的 10 条军规](https://juejin.cn/post/7504572792357486631)
20 | - `点赞量: 60` - [腾讯二面:王者荣耀亿级排行榜,如何设计?](https://juejin.cn/post/7509787391440535552)
21 | - `点赞量: 36` - [Redis 8.0 正式版发布,新特性很强!](https://juejin.cn/post/7501264245376581671)
22 | - `点赞量: 8` - [一天一道 Java 面试题,坚持三个月,菜鸟变大佬(并发篇)](https://juejin.cn/post/7502108606729420826)
23 | - `点赞量: 5` - [gozero 限流、熔断、降级如何实现?面试的时候怎么回答?](https://juejin.cn/post/7503437639691386916)
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 面试题库
2 |
3 | 想做一个很全的面试题库工程
4 |
5 | 1. 需要去全网收集面试题
6 | 2. 需要对面试题进行分类归类归档
7 | 3. 需要持续更新
8 |
9 | ----------
10 |
11 |
12 | ## 如何使用?
13 | 1. 面试题采用 issue 方式来进行记录和作答, 直接访问本项目链接即可:https://github.com/pro-collection/interview-question/issues
14 |
15 | 2. 题目难度分级:初级、中级、高级、资深, 可以通过 milestone 来进行筛选:
16 |
17 |
18 | 3. 题目的类型分类:使用 labels 方式管理
19 |
20 |
21 | 4. 关于题目序号, 直接使用 issue 自增 id 即可, 便于收藏记忆记录等:
22 |
23 |
24 | 5. 关于问题讨论:开通 discussions 社区, 可以直接在 discussions 区进行讨论即可。
25 |
26 |
27 | 6. 使用技巧:本项目所有 open 的 issue 是作者进行整理了的问题。如何精确筛选呢?
28 | - 搜索 title : `is:open in:title [txt]`
29 | - 搜索 内容: `is:open in:body [txt]`
30 |
31 |
32 |
33 | ## 更新周报
34 | 1. 每隔一段时间, 总结会以 release 的方式总结: https://github.com/pro-collection/interview-question/releases
35 | 2. 具体面试问答内容, 会落地在 https://github.com/pro-collection/interview-question/tree/master/books 目录下面
36 | gitee 可以访问这个链接: https://gitee.com/yanleweb/interview-question/tree/master/books
37 |
38 |
39 | ## 待整理的文档
40 | - [待整理文档](./doc.md)
41 |
--------------------------------------------------------------------------------
/src/githubApi/issue/writeIssue.ts:
--------------------------------------------------------------------------------
1 | import { WriteIssueOptions } from "./interface";
2 | import { octokit } from "@utils/requestKit";
3 | import { apiUrl } from "@utils/apiUrl";
4 | import repoConfig from "@utils/repoConfig";
5 | import { MileStone } from "@src/githubApi/issue/consts";
6 | import { giteeWriteIssue } from "@src/giteeApi/issue/writeIssue";
7 | import { giteeMileStone } from "@src/giteeApi/issue/consts";
8 | import { join, map } from "lodash";
9 | import { commitPush } from "@src/githubApi/issue/helper";
10 | import { getIssueContentWithCurrentVersion } from "./getReleaseNoteCount";
11 |
12 | // 写入 github
13 | const write = (options: WriteIssueOptions) =>
14 | octokit.request(apiUrl.writeIssue, {
15 | ...options,
16 | ...repoConfig.interviewRepo,
17 | });
18 |
19 | export const writeIssue = async (remote: any) => {
20 | const allPromise = [
21 | write({
22 | ...remote,
23 | body: remote.body(),
24 | }),
25 | giteeWriteIssue({
26 | title: remote.title,
27 | body: remote.body(),
28 | labels: join(remote.labels, ","),
29 | milestone: giteeMileStone[remote.milestone as MileStone],
30 | }),
31 | ];
32 |
33 | const [res1, res2] = await Promise.all(allPromise);
34 |
35 | // 写入 github
36 | console.log(`yanle - logger: 写入 github - ${remote.title}`, res1?.status);
37 |
38 | await commitPush(remote.title);
39 |
40 | // 当前版本一共有的题目数量
41 | const { issueList } = await getIssueContentWithCurrentVersion();
42 |
43 | console.log(
44 | `[yanle] - logger: 当前待归档的 issue 文章列表: \n`,
45 | map(issueList, (item) => item.title)
46 | );
47 | console.log(`[yanle] - logger: 当前待归档的 issue 文章数量: `, issueList?.length);
48 | };
49 |
50 | export {};
51 |
--------------------------------------------------------------------------------
/src/spider/juejin/__tests__/getFrontendArticles.integration.test.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import { getFrontendArticles } from "../utils";
3 | import jsonData from "../../../../temp/juejin_interview/2025_02_03_10_29_51.json";
4 |
5 | describe("getFrontendArticles 集成测试", () => {
6 | it("应该能正确读取并解析实际的JSON文件数据", () => {
7 | // 从文件名中提取日期
8 | const fileName = "2025_01";
9 | const [year, month] = fileName.split("_");
10 | const targetDate = `${year}-${month}`;
11 |
12 | // 获取前端文章
13 | const frontendArticles = getFrontendArticles(jsonData, targetDate);
14 |
15 | // 输出调试信息
16 |
17 | console.log(
18 | `[getFrontendArticles 集成测试 - 应该能正确读取并解析实际的JSON文件数据] | 获取到的前端文章数量: ${frontendArticles.length}`
19 | );
20 |
21 | // 基本验证
22 | expect(Array.isArray(frontendArticles)).toBe(true);
23 | expect(frontendArticles.length).toBeGreaterThan(0);
24 |
25 | // 验证数据结构
26 | frontendArticles.forEach((article) => {
27 | expect(article).toHaveProperty("title");
28 | expect(article).toHaveProperty("url");
29 | expect(article).toHaveProperty("diggCount");
30 | expect(typeof article.title).toBe("string");
31 | expect(typeof article.url).toBe("string");
32 | expect(typeof article.diggCount).toBe("number");
33 | expect(article.url).toMatch(/^https:\/\/juejin\.cn\/post\//);
34 | });
35 |
36 | // 验证排序(点赞数降序)
37 | for (let i = 0; i < frontendArticles.length - 1; i++) {
38 | expect(frontendArticles[i].diggCount).toBeGreaterThanOrEqual(frontendArticles[i + 1].diggCount);
39 | }
40 | });
41 |
42 | it("应该能处理文件不存在的情况", () => {
43 | expect(() => {
44 | require("../../../../temp/juejin_interview/non_existent_file.json");
45 | }).toThrow();
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/src/githubApi/otherRepo/nodeIndex/index.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import { UpdateIssueOptions, WriteIssueOptions } from "@src/githubApi/issue/interface";
3 | import { octokit } from "@utils/requestKit";
4 | import { apiUrl } from "@utils/apiUrl";
5 | import repoConfig from "@utils/repoConfig";
6 | import { labels } from "@src/githubApi/otherRepo/nodeIndex/consts";
7 |
8 | // 写入 github
9 | const write = (options: WriteIssueOptions) =>
10 | octokit.request(apiUrl.writeIssue, {
11 | ...options,
12 | ...repoConfig.nodeIndex,
13 | });
14 |
15 | const update = (options: UpdateIssueOptions) =>
16 | octokit.request(apiUrl.updateIssue, {
17 | ...options,
18 | ...repoConfig.nodeIndex,
19 | });
20 |
21 | const remote = {
22 | title: "【实践】【01】实现一键复制掘金文章为Markdown文档",
23 | labels: [labels.chromeExtensions],
24 | body: () =>
25 | fs.readFileSync(
26 | "/Users/yanle/code/self/node-index/books/专题知识库/22、chorme extensions/【实践】【01】实现一键复制掘金文章为Markdown文档.md",
27 | { encoding: "utf8" }
28 | ),
29 | };
30 |
31 | // 创建 issue
32 | const createIssue = async () => {
33 | // 输出 title
34 | console.log("yanle - logger: title", remote.title);
35 |
36 | // 写入远端
37 | const res = await write({
38 | ...remote,
39 | body: remote.body(),
40 | });
41 |
42 | // 写入 github 完成
43 | console.log(`yanle - logger: 写入 github - ${remote.title}`, res?.status);
44 | };
45 |
46 | // 修改 issue
47 | const updateIssue = async () => {
48 | // 输出 title
49 | console.log("yanle - logger: title", remote.title);
50 |
51 | // 写入远端
52 | const res = await update({
53 | ...remote,
54 | issue_number: -1,
55 | body: remote.body(),
56 | });
57 |
58 | // 写入 github
59 | console.log(`yanle - logger: 写入 github - ${remote.title}`, res?.status);
60 | };
61 |
62 | createIssue();
63 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_01.md:
--------------------------------------------------------------------------------
1 | ### 代码人生
2 | - `点赞量: 94` - [如何优雅的回复面试官问:“你能接受加班吗?”](https://juejin.cn/post/7457211584709066792)
3 | - `点赞量: 3` - [一道题解读公务员面试](https://juejin.cn/post/7455663519674695714)
4 | - `点赞量: 0` - [字节跳动丨日常实习面试记录](https://juejin.cn/post/7463005171514327081)
5 |
6 | ### 前端
7 | - `点赞量: 63` - [为什么面试官在面试中都爱问 HTTPS ❓❓❓](https://juejin.cn/post/7459561147580235795)
8 | - `点赞量: 25` - [手写 AJAX,面试常考点!从 `fetch` 到手动实现它,你准备好了吗?👨💻🚀](https://juejin.cn/post/7455214521310232576)
9 | - `点赞量: 20` - [JS面试题-JSONP解决跨域问题](https://juejin.cn/post/7458189925714034723)
10 | - `点赞量: 13` - [腾讯前端开发校招一面面试题(被吊打版已老实)](https://juejin.cn/post/7463871170015019023)
11 | - `点赞量: 13` - [面试官:请手写一个发布订阅模式](https://juejin.cn/post/7462026065899012107)
12 | - `点赞量: 7` - [面试官问:了解哪些最新的 ES 新特性?——这样回答更好!](https://juejin.cn/post/7459351912133132351)
13 | - `点赞量: 7` - [学习正则表达式后🤔直接开始面试😱](https://juejin.cn/post/7464808720020340736)
14 | - `点赞量: 5` - [2025真实面试题](https://juejin.cn/post/7460364572341665819)
15 | - `点赞量: 5` - [React面试题合集(自用,持续更新...)](https://juejin.cn/post/7462806649754337290)
16 | - `点赞量: 3` - [【100%面试题】总有一天在JS 精度问题上你会踩坑](https://juejin.cn/post/7459279902133010466)
17 |
18 | ### 后端
19 | - `点赞量: 54` - [如何辨别面试是在刷KPI还是真招人?](https://juejin.cn/post/7454780575087067148)
20 | - `点赞量: 10` - [腾讯面试:大厂必问消息队列场景面试题](https://juejin.cn/post/7463083554295349285)
21 | - `点赞量: 6` - [腾讯面试:怎么解决缓存穿透、击穿和雪崩问题?](https://juejin.cn/post/7459783326834065442)
22 | - `点赞量: 6` - [关于Spring的专项面试试题总结](https://juejin.cn/post/7462196912956293174)
23 | - `点赞量: 5` - [史上最全Java面试题(带全部答案)](https://juejin.cn/post/7455435303656128549)
24 | - `点赞量: 5` - [2025春招,Spring 面试题汇总](https://juejin.cn/post/7462326829266812979)
25 | - `点赞量: 3` - [面试必问!项目高频面试题解析](https://juejin.cn/post/7456441507718627382)
26 | - `点赞量: 3` - [分享一次面试经历](https://juejin.cn/post/7457470416375906356)
27 | - `点赞量: 2` - [字节的面试,感觉还挺简单的~](https://juejin.cn/post/7460500742647365682)
28 |
29 | ### Android
30 | - `点赞量: 47` - [一个常见面试问题:Kotlin 协程能够完全取代线程吗?为什么?](https://juejin.cn/post/7455576220374368282)
31 |
32 |
--------------------------------------------------------------------------------
/books/2023年/0.0.14.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## 初级开发者相关问题
4 |
5 | 41.垂直居中的方案有哪些, 简单手写一下?【CSS】
6 | 回答链接:https://github.com/pro-collection/interview-question/issues/41
7 |
8 | 42.水平居中的方案有哪些, 简单手写一下?【CSS】
9 | 回答链接:https://github.com/pro-collection/interview-question/issues/42
10 |
11 | 43.未知高度和宽度元素的水平垂直居中的方案有哪些, 简单手写一下?【CSS】
12 | 回答链接:https://github.com/pro-collection/interview-question/issues/43
13 |
14 |
15 |
16 | ## 中级开发者相关问题
17 |
18 | 37.关于 JS 闭包了解多少【JavaScript】
19 | 回答链接:https://github.com/pro-collection/interview-question/issues/37
20 |
21 | 38.手写实现一下 lodash.get?【JavaScript】
22 | 回答链接:https://github.com/pro-collection/interview-question/issues/38
23 |
24 | 39.JS 中 this 指向问题了解多少?【JavaScript】
25 | 回答链接:https://github.com/pro-collection/interview-question/issues/39
26 |
27 | 40.JS 深拷贝有哪些方式, 手写实现一下?【JavaScript】
28 | 回答链接:https://github.com/pro-collection/interview-question/issues/40
29 |
30 | 44.数组去重方式有哪些,简单手写一下?【JavaScript】
31 | 回答链接:https://github.com/pro-collection/interview-question/issues/44
32 |
33 | 45.cookie 和 session 有什么区别?【网络】
34 | 回答链接:https://github.com/pro-collection/interview-question/issues/45
35 |
36 | 46.银行卡号四位空一位, 例如:6222023100014763381 -->6222 0231 0001 4763 381【JavaScript】
37 | 回答链接:https://github.com/pro-collection/interview-question/issues/46
38 |
39 | 47.js 宏任务与微任务都是指什么, 优先级如何?【JavaScript】
40 | 回答链接:https://github.com/pro-collection/interview-question/issues/47
41 |
42 | 48.commonjs 模块引用规范有哪些?【JavaScript】
43 | 回答链接:https://github.com/pro-collection/interview-question/issues/48
44 |
45 | 49.fetch 了解多少?【网络】
46 | 回答链接:https://github.com/pro-collection/interview-question/issues/49
47 |
48 | 50.数字字符串千分位处理(正则与非正则)?【JavaScript】
49 | 回答链接:https://github.com/pro-collection/interview-question/issues/50
50 |
51 | 51.手写防抖函数【JavaScript】
52 | 回答链接:https://github.com/pro-collection/interview-question/issues/51
53 |
54 | 52.process.nextTick, setTimeout 以及 setImmediate 三者的执行顺序?【JavaScript】
55 | 回答链接:https://github.com/pro-collection/interview-question/issues/52
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/utils/apiUrl.ts:
--------------------------------------------------------------------------------
1 | export const apiUrl = {
2 | getIssue: "GET /repos/{owner}/{repo}/issues",
3 |
4 | writeIssue: "POST /repos/{owner}/{repo}/issues",
5 |
6 | updateIssue: "PATCH /repos/{owner}/{repo}/issues/{issue_number}",
7 |
8 | getContent: "GET /repos/{owner}/{repo}/contents/{path}",
9 |
10 | // api 文档 https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#create-or-update-file-contents
11 | updateContent: "PUT /repos/{owner}/{repo}/contents/{path}",
12 |
13 | createTagObj: "POST /repos/{owner}/{repo}/git/tags",
14 |
15 | // 关联 tag 和 commit
16 | createRef: "POST /repos/{owner}/{repo}/git/refs",
17 |
18 | // 创建 release
19 | createRelease: "POST /repos/{owner}/{repo}/releases",
20 |
21 | // 获取一个 release
22 | getRelease: "GET /repos/{owner}/{repo}/releases/{release_id}",
23 |
24 | // 获取一个 tag
25 | getTag: "GET /repos/{owner}/{repo}/releases/tags/{tag}",
26 |
27 | // 更新一个 tag
28 | // api https://docs.github.com/en/rest/issues/issues?apiVersion=2022-11-28#update-an-issue
29 | updateTag: "PATCH /repos/{owner}/{repo}/issues/{issue_number}",
30 |
31 | // https://docs.github.com/en/rest/search?apiVersion=2022-11-28#search-issues-and-pull-requests
32 | searchIssue: (queryString: string, created: string) =>
33 | `https://api.github.com/search/issues?q=${queryString}+state:open+created:>${created}&per_page=1`,
34 |
35 | // https://api.github.com/search/issues?q=repo:pro-collection/interview-question+in%3Atitle+react&per_page=1&page=1&labels=web%E6%A1%86%E6%9E%B6
36 | searchIssueWithRepo: (owner: string, repo: string, queryString: string, per_page = "100", page = "1") =>
37 | `https://api.github.com/search/issues?q=repo:${owner}/${repo}+${queryString}&per_page=${per_page}&page=${page}`,
38 | };
39 |
40 | /**
41 | * api 文档: https://gitee.com/api/v5/swagger#/getV5ReposOwnerRepoStargazers?ex=no
42 | */
43 | export const giteeApiUrl = {
44 | // post 请求
45 | // 文档 https://gitee.com/api/v5/swagger#/postV5ReposOwnerIssues
46 | createIssue: (owner: string) => `https://gitee.com/api/v5/repos/${owner}/issues`,
47 |
48 | // get 请求
49 | // https://gitee.com/api/v5/swagger#/getV5ReposOwnerRepoIssues
50 | getIssue: (owner: string, repo: string) => `https://gitee.com/api/v5/repos/${owner}/${repo}/issues`,
51 | };
52 |
--------------------------------------------------------------------------------
/src/spider/crawlee_demo/demo6.ts:
--------------------------------------------------------------------------------
1 | import { load } from "cheerio";
2 | import { PlaywrightCrawler, Dataset } from "crawlee";
3 | import h2md from "html-to-md";
4 | import fs from "fs";
5 |
6 | // 设置要爬取的目标域名和起始URL
7 | const domain = "www.lodashjs.com/";
8 | const startUrl = `https://${domain}`;
9 |
10 | const copyHtml = (html: string, title: string) => {
11 | if (!html) {
12 | return "";
13 | }
14 |
15 | const content = h2md(html);
16 |
17 | return `## ${title}
18 |
19 | ${content}`;
20 | };
21 |
22 | // 创建一个新的爬虫实例
23 | const crawler = new PlaywrightCrawler({
24 | // 处理每个页面的回调函数
25 | async requestHandler({ request, page, enqueueLinks, log }) {
26 | // 提取页面的HTML内容
27 | const html = await page.content();
28 |
29 | const $ = load(html);
30 | const title = $(".breadcrumbs__link").text();
31 |
32 | // 移除导航
33 | $("nav.theme-doc-breadcrumbs").remove();
34 |
35 | const article =
36 | $(
37 | "#__docusaurus_skipToContent_fallback > div > main > div > div > div.col.docItemCol_z5aJ > div > article"
38 | ).html() || "";
39 |
40 | const htmlWithMD = copyHtml(article, title);
41 |
42 | // 保存HTML内容到数据集
43 | await Dataset.pushData({
44 | url: request.url,
45 | html: htmlWithMD,
46 | });
47 |
48 | // 将 htmlWithMD 写入 demo6.md 文件
49 | const filePath = "/Users/yanle/code/self/interview-question/src/spider/crawlee_demo/demo6.md";
50 | fs.appendFile(filePath, htmlWithMD + "\n", (err) => {
51 | if (err) {
52 | log.error(`写入文件失败: ${err}`);
53 | } else {
54 | log.info(`已将内容写入文件: ${title}`);
55 | }
56 | });
57 |
58 | log.info(`已抓取: ${request.url}`);
59 |
60 | // 递归地抓取相同域名下的所有链接
61 | await enqueueLinks({
62 | strategy: "same-domain",
63 | // 可以在这里添加链接过滤器
64 | transformRequestFunction: (req) => {
65 | // 排除非HTML资源
66 | if (!req.url.match(/\.(jpg|jpeg|png|gif|pdf|docx|xlsx|css|js|svg|ico|woff|woff2|ttf|eot)$/i)) {
67 | return req;
68 | }
69 | return null; // 过滤掉不符合条件的链接
70 | },
71 | });
72 | },
73 |
74 | // 处理请求失败的回调函数
75 | failedRequestHandler({ request, log }) {
76 | log.error(`请求失败: ${request.url}`);
77 | },
78 |
79 | // 爬虫配置
80 | maxRequestsPerCrawl: 1000, // 限制最大请求数,防止无限爬取
81 | maxConcurrency: 10, // 最大并发请求数
82 | navigationTimeoutSecs: 60, // 页面加载超时时间
83 | });
84 |
85 | const main = async () => {
86 | // 启动爬虫
87 | await crawler.run([startUrl]);
88 | console.log("yanle log 爬取完成!HTML内容已保存到数据集。");
89 | };
90 |
91 | main();
92 |
--------------------------------------------------------------------------------
/src/githubApi/issue/index.ts:
--------------------------------------------------------------------------------
1 | import { htmlWriteIssue } from "@src/githubApi/issue/htmlWriteIssue";
2 | import { calculateY, writeToTemp } from "@src/githubApi/issue/helper";
3 | import { company, labels, MileStone } from "@src/githubApi/issue/consts";
4 | import fs from "fs";
5 | import { writeIssue } from "@src/githubApi/issue/writeIssue";
6 | import { search } from "@src/githubApi/issue/search";
7 | import { omit, toNumber } from "lodash";
8 | import { filePath } from "@src/githubApi/file/consts";
9 | import { input, confirm } from "@inquirer/prompts";
10 |
11 | const remote = {
12 | title: "Nginx 如何为不同前端资源配置缓存策略?如何强制刷新特定资源?",
13 | key_world: [
14 | //
15 | "nginx 加载特定资源",
16 | ],
17 | labels: [
18 | labels.application,
19 | // labels.node,
20 | // company.alibaba,
21 | // xx
22 | ],
23 | milestone: MileStone.senior,
24 | body: () => fs.readFileSync(filePath, { encoding: "utf8" }),
25 | };
26 |
27 | const main = async () => {
28 | console.log(`yanle - logger: 使用关键词: `, remote.key_world.join("、"));
29 |
30 | if (remote.key_world.length) {
31 | let count = await search(remote.key_world);
32 |
33 | // 线性回归的结果
34 | count = calculateY(count);
35 |
36 | console.log("yanle - logger: 获取热度结果: ", count);
37 |
38 | const isConfirm = await confirm({
39 | message: `获取到热度为:${count}, 请确认。(为「no」则可以重新修改热度, 为 「yes」则无需修改热度)`,
40 | });
41 |
42 | if (!isConfirm) {
43 | const answer = await input({ message: "请输入复写热度评分: " });
44 | count = !!toNumber(answer) ? toNumber(answer) : count;
45 | }
46 |
47 | remote.title =
48 | count && remote.key_world ? `${remote.title}【热度: ${count?.toLocaleString() || count}】` : remote.title;
49 |
50 | // 关键词
51 | const keyWordContent = `**关键词**:${remote.key_world.join("、")}\n\n`;
52 | const oldFile = fs.readFileSync(filePath, { encoding: "utf8" });
53 | fs.writeFileSync(filePath, keyWordContent + oldFile);
54 | console.log("yanle - logger: 关键词写入文档完成");
55 | } else {
56 | const isConfirm = await confirm({
57 | message: `是否自定义热度, 请确认。(为「yes」需要自定义热度, 为「no」则无需自定义热度)`,
58 | });
59 |
60 | if (isConfirm) {
61 | const answer = await input({ message: "请输入复写热度评分: " });
62 | const count = !!toNumber(answer) ? toNumber(answer) : 0;
63 |
64 | if (count) {
65 | remote.title =
66 | count && remote.key_world ? `${remote.title}【热度: ${count?.toLocaleString() || count}】` : remote.title;
67 | }
68 | }
69 | }
70 |
71 | // 输出 title
72 | console.log("yanle - logger: title", remote.title);
73 |
74 | // md 写入远端
75 | writeIssue(omit(remote, "key_world"));
76 | };
77 |
78 | // 将 demo.html 写入本地 temp.md
79 | // writeToTemp();
80 |
81 | // html 写入远端
82 | // htmlWriteIssue(remote);
83 |
84 | // 直接写入远端
85 | main();
86 |
--------------------------------------------------------------------------------
/src/githubApi/releaseNote/request.ts:
--------------------------------------------------------------------------------
1 | import dayjs from "dayjs";
2 | import { CreateReleaseParams } from "./interface";
3 | import { apiUrl } from "@utils/apiUrl";
4 | import { octokit } from "@utils/requestKit";
5 | import repoConfig from "@utils/repoConfig";
6 |
7 | const path = "package.json";
8 |
9 | /**
10 | * 获取 package.json
11 | */
12 | export const getPackageJson = () => octokit.request(apiUrl.getContent, {
13 | ...repoConfig.interviewRepo,
14 | path,
15 | });
16 |
17 | /**
18 | * update package
19 | * @param content
20 | * @param extend
21 | */
22 | export const updatePackageJson = (content: string, extend: object) => octokit.request(apiUrl.updateContent, {
23 | ...repoConfig.interviewRepo,
24 | path,
25 | message: `update - package.json: ${dayjs().format("YYYY-MM-DDTHH:mm:ssZ")}`,
26 | committer: {
27 | name: "yanlele",
28 | email: "331393627@qq.com",
29 | },
30 | content,
31 | ...extend,
32 | });
33 |
34 | /**
35 | * create tag obj
36 | * @param tag
37 | * @param sha
38 | */
39 | export const createTagObjectRequest = (tag: string, sha: string) => {
40 | return octokit.request(apiUrl.createTagObj, {
41 | ...repoConfig.interviewRepo,
42 | tag,
43 | message: dayjs().format("YYYY-MM-DDTHH:mm:ssZ"),
44 | object: sha, // commit sha
45 | type: "commit",
46 | });
47 | };
48 |
49 | /**
50 | * create tag
51 | * @param tag
52 | * @param sha
53 | */
54 | export const createTagRequest = (tag: string, sha: string) => {
55 | return octokit.request(apiUrl.createRef, {
56 | ...repoConfig.interviewRepo,
57 | sha,
58 | ref: `refs/tags/${tag}`,
59 | });
60 | };
61 |
62 | /**
63 | * 获取要求时间范围的 issue
64 | */
65 | export const getDataIssue = (preDate: string) => octokit.request(apiUrl.getIssue, {
66 | ...repoConfig.interviewRepo,
67 | per_page: 100,
68 | page: 1,
69 | since: dayjs(preDate).format("YYYY-MM-DDTHH:mm:ssZ"),
70 | creator: "yanlele",
71 | });
72 |
73 | /**
74 | * createRelease
75 | * @param params
76 | */
77 | export const createRelease = (params: CreateReleaseParams) => octokit.request(apiUrl.createRelease, {
78 | ...repoConfig.interviewRepo,
79 | ...params,
80 | });
81 |
82 |
83 | /**
84 | * 获取一个 tag
85 | */
86 | export const getTag = (tag: string) => octokit.request(apiUrl.getTag, {
87 | ...repoConfig.interviewRepo,
88 | tag,
89 | });
90 | //
91 | // getTag("0.0.13").then((res: any) => {
92 | // // console.log('yanle - logger: res', res);
93 | // const createDate = get(res, "data.created_at", "");
94 | // console.log('yanle - logger: createDate', createDate);
95 | // let preDate = dayjs(createDate).format("YYYY.MM.DD");
96 | // console.log("yanle - logger: preDate", preDate);
97 | //
98 | // // @ts-ignore
99 | // const currentTZ = dayjs.tz.guess();
100 | //
101 | // // @ts-ignore
102 | // preDate = dayjs.tz(createDate, currentTZ).format('YYYY.MM.DD');
103 | // console.log('yanle - logger: next preDate', preDate);
104 | // });
105 |
--------------------------------------------------------------------------------
/src/githubApi/issue/getIssue.ts:
--------------------------------------------------------------------------------
1 | import { find, map, get, sortBy } from "lodash";
2 | import dayjs from "dayjs";
3 | import { octokit } from "@utils/requestKit";
4 | import { apiUrl } from "@utils/apiUrl";
5 | import repoConfig from "@utils/repoConfig";
6 | import { giteeMileStone } from "@src/giteeApi/issue/consts";
7 | import { WriteRequestOptions } from "@src/giteeApi/issue/interface";
8 |
9 | import { giteeWriteIssue } from "@src/giteeApi/issue/writeIssue";
10 | import { getDataIssue, getTag } from "@src/githubApi/releaseNote/request";
11 | import { getReleaseContent } from "@src/githubApi/releaseNote/helper";
12 | import { writeContentForLocal } from "@src/githubApi/writeTagForLocal";
13 | // import * as fs from "fs";
14 | import * as path from "path";
15 |
16 | const req = () => octokit.request(apiUrl.getIssue, {
17 | ...repoConfig.interviewRepo,
18 | per_page: 100,
19 | since: dayjs("2023-03-01").format("YYYY-MM-DDTHH:mm:ssZ"),
20 | });
21 |
22 | const getIssueByDate = (preDate: string, page: number = 1, per_page = 100) => octokit.request(apiUrl.getIssue, {
23 | ...repoConfig.interviewRepo,
24 | per_page,
25 | page,
26 | since: dayjs(preDate).format("YYYY-MM-DDTHH:mm:ssZ"),
27 | });
28 |
29 | const main = async () => {
30 | // const res = await req();
31 |
32 | // const titleList = map(sortBy(res.data, sortItem => sortItem.number), item => {
33 | // const milestoneNumber = get(giteeMileStone, item.milestone?.number);
34 | // const labels = map(item.labels, label => label.name).join(",");
35 | // const returnData: WriteRequestOptions = {
36 | // title: item.title,
37 | // body: item.body,
38 | // // number: item.number,
39 | // };
40 | //
41 | // if (milestoneNumber) returnData.milestone = milestoneNumber;
42 | // if (labels) returnData.labels = labels;
43 | //
44 | // return returnData;
45 | // });
46 | //
47 | // console.log("yanle - logger: titleList", titleList);
48 |
49 | // console.log("yanle - logger: title", titleList);
50 | //
51 | // const content = find(res.data, item => item.number === 3);
52 | // console.log("yanle - logger: content", content);
53 |
54 | // 写入 title
55 | // for (const item of titleList) {
56 | // console.log('yanle - logger: 开始写入 - ', item.title);
57 | // await giteeWriteIssue(item);
58 | // }
59 |
60 |
61 | // 获取对应的 tag
62 | const preTagRes = await getTag("0.0.14");
63 |
64 | // 获取上一次时间戳
65 | const createDate = get(preTagRes, "data.created_at", "");
66 |
67 | // @ts-ignore
68 | // const currentTZ = dayjs.tz.guess();
69 |
70 | // @ts-ignore
71 | // const preDate = dayjs.tz(createDate, currentTZ).format("YYYY.MM.DD");
72 |
73 | // 获取最新的 issue
74 | const issueRes = await getIssueByDate(createDate, 3, 15);
75 | const releaseName = `2023.03.09 - 2023.03.15 更新收集面试问题(45道题)【第5部分】`;
76 | const releaseBody = getReleaseContent(issueRes.data, releaseName, true);
77 | const filePath = path.resolve(__dirname, "../../../books");
78 | const fileName = "0.0.15_5";
79 |
80 | await writeContentForLocal({ path: filePath, fileName, content: releaseBody });
81 | };
82 |
83 | main();
84 |
85 | export {};
86 |
--------------------------------------------------------------------------------
/src/spider/juejin/__tests__/getFrontendArticles.test.ts:
--------------------------------------------------------------------------------
1 | import { getFrontendArticles } from "../utils";
2 |
3 | describe("getFrontendArticles 获取前端文章函数", () => {
4 | it("应该正确获取前端分类的文章并按点赞数排序", () => {
5 | const mockJsonData = [
6 | {
7 | article_info: {
8 | title: "前端文章1",
9 | article_id: "1234567890",
10 | digg_count: 100,
11 | ctime: "1706745600", // 2024-02-01
12 | },
13 | category_name: "前端",
14 | },
15 | {
16 | article_info: {
17 | title: "前端文章2",
18 | article_id: "1234567891",
19 | digg_count: 200,
20 | ctime: "1706745600", // 2024-02-01
21 | },
22 | category_name: "前端",
23 | },
24 | {
25 | article_info: {
26 | title: "后端文章1",
27 | article_id: "1234567892",
28 | digg_count: 150,
29 | ctime: "1706745600", // 2024-02-01
30 | },
31 | category_name: "后端",
32 | },
33 | ];
34 |
35 | const targetDate = "2024-02";
36 | const result = getFrontendArticles(mockJsonData, targetDate);
37 |
38 | const expectedOutput = [
39 | {
40 | title: "前端文章2",
41 | url: "https://juejin.cn/post/1234567891",
42 | diggCount: 200,
43 | },
44 | {
45 | title: "前端文章1",
46 | url: "https://juejin.cn/post/1234567890",
47 | diggCount: 100,
48 | },
49 | ];
50 |
51 | // 断言测试
52 | expect(result).toEqual(expectedOutput);
53 | expect(result).toHaveLength(2);
54 | expect(result[0].diggCount).toBeGreaterThan(result[1].diggCount);
55 | });
56 |
57 | it("应该正确处理没有前端文章的情况", () => {
58 | const mockJsonData = [
59 | {
60 | article_info: {
61 | title: "后端文章1",
62 | article_id: "1234567892",
63 | digg_count: 150,
64 | ctime: "1706745600", // 2024-02-01
65 | },
66 | category_name: "后端",
67 | },
68 | ];
69 |
70 | const result = getFrontendArticles(mockJsonData, "2024-02");
71 | expect(result).toEqual([]);
72 | });
73 |
74 | it("应该正确处理空数组输入", () => {
75 | const result = getFrontendArticles([], "2024-02");
76 | expect(result).toEqual([]);
77 | });
78 |
79 | it("应该过滤掉不属于目标月份的前端文章", () => {
80 | const mockJsonData = [
81 | {
82 | article_info: {
83 | title: "过期前端文章",
84 | article_id: "1234567890",
85 | digg_count: 100,
86 | ctime: "1704067200", // 2024-01-01
87 | },
88 | category_name: "前端",
89 | },
90 | {
91 | article_info: {
92 | title: "当月前端文章",
93 | article_id: "1234567891",
94 | digg_count: 200,
95 | ctime: "1706745600", // 2024-02-01
96 | },
97 | category_name: "前端",
98 | },
99 | ];
100 |
101 | const result = getFrontendArticles(mockJsonData, "2024-02");
102 |
103 | const expectedOutput = [
104 | {
105 | title: "当月前端文章",
106 | url: "https://juejin.cn/post/1234567891",
107 | diggCount: 200,
108 | },
109 | ];
110 |
111 | expect(result).toEqual(expectedOutput);
112 | expect(result).toHaveLength(1);
113 | });
114 | });
115 |
--------------------------------------------------------------------------------
/src/githubApi/issue/helper.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import h2m from "html-to-md";
3 | import { flow } from "lodash";
4 | import * as child_process from "child_process";
5 | import util from "node:util";
6 | import axios from "axios";
7 | import * as path from "path";
8 | import { tempFilePath, htmlPath as htmlPathStatic } from "../file/consts";
9 |
10 | const execPromise = util.promisify(child_process.exec);
11 |
12 | /**
13 | * 处理markdown内容,清理无用的文本
14 | * @param html HTML格式的字符串
15 | * @returns 处理后的markdown文本,主要做了以下处理:
16 | * 1. 移除各种语言的"Copy code"文本
17 | * 2. 修正代码块语言标记
18 | * 3. 修复转义字符
19 | * 4. 移除"复制代码"文本
20 | * 5. 调整标题层级
21 | */
22 | export const formatMarkdown = (html: string): string => {
23 | let markdown = h2m(html);
24 | return flow(
25 | (value) => value.replace(/javascriptCopy code/gi, ""),
26 | (value) => value.replace(/htmlCopy code/gi, ""),
27 | (value) => value.replace(/cssCopy code/gi, ""),
28 | (value) => value.replace(/jsCopy code/gi, ""),
29 | (value) => value.replace(/jsonCopy code/gi, ""),
30 | (value) => value.replace(/shellCopy code/gi, ""),
31 | (value) => value.replace(/jsxCopy code/gi, ""),
32 | (value) => value.replace(/```js\njs/gi, "```js\n"),
33 | (value) => value.replace(/```javascript\njs/gi, "```javascript\n"),
34 | (value) => value.replace(/```typescript\ntypescript/gi, "```typescript\n"),
35 | (value) => value.replace(/\\. /gi, ". "),
36 | (value) => value.replace(/\\- /gi, "- "),
37 | (value) => value.replace(/复制代码/gi, ""),
38 | // value => value.replace(/\n### /gi, "\n#### "),
39 | (value) => value.replace(/\n## /gi, "\n### ")
40 | )(markdown);
41 | };
42 |
43 | /**
44 | * 将 html 文件转为 markdown 文件, 写入本地
45 | * @param path 写入文件的路径
46 | * @param htmlPath html 文件的路径
47 | * @returns null
48 | */
49 | export const writeToTemp = async (path = tempFilePath, htmlPath = htmlPathStatic) => {
50 | const html = fs.readFileSync(htmlPath, { encoding: "utf-8" });
51 |
52 | // 使用新的cleanMarkdown函数处理markdown
53 | const markdown = formatMarkdown(html);
54 |
55 | if (markdown) fs.writeFileSync(path, markdown, { encoding: "utf-8" });
56 |
57 | return;
58 | };
59 |
60 | /**
61 | * 提交commit
62 | * @param title
63 | */
64 | export const commitPush = async (title: string) => {
65 | // 提交 git commit
66 | const commandList = [`git commit -am "${title}"`, "git push"];
67 |
68 | // 遍历执行
69 | for (let i = 0; i < commandList.length; i++) {
70 | console.log("yanle - logger: 执行command", commandList[i]);
71 | await execPromise(commandList[i]);
72 | }
73 |
74 | // 输出结果
75 | console.log("yanle - logger: 完成提交到 github");
76 | };
77 |
78 | /**
79 | * 获取请求结果保存到本地
80 | * @param url
81 | */
82 | export const getIssueByUrlWriteLocal = async (url: string) => {
83 | axios
84 | .request({
85 | url,
86 | method: "get",
87 | })
88 | .then((res: any) => {
89 | const body = res?.data?.body;
90 | fs.writeFileSync(path.resolve(__dirname, "./temp.md"), body, { encoding: "utf-8" });
91 | });
92 | };
93 |
94 | /**
95 | * 线性回归到 500
96 | * @param x
97 | * @returns
98 | */
99 | export const calculateY = (x: number) => {
100 | return Math.ceil(x === 0 ? 0 : (1000 * x) / (x + 500));
101 | };
102 |
--------------------------------------------------------------------------------
/src/spider/juejin/batchCrawlArticles.ts:
--------------------------------------------------------------------------------
1 | import { PlaywrightCrawler } from "crawlee";
2 | import fs from "fs";
3 | import path from "path";
4 | import { formatMarkdown } from "@src/githubApi/issue/helper";
5 | import dayjs from "dayjs";
6 | import jsonData from "../../../temp/juejin_interview/2025_01_11_21_36_38.json";
7 | import { getFrontendArticles } from "./utils";
8 |
9 | interface ArticleResult {
10 | url: string;
11 | success: boolean;
12 | error?: string;
13 | title?: string;
14 | }
15 |
16 | // 修改 appendToFile 函数
17 | const appendToFile = (filePath: string, content: string) => {
18 | // 如果文件不存在,先创建一个空文件
19 | if (!fs.existsSync(filePath)) {
20 | // 创建一个文件头
21 | const fileHeader = `# 掘金文章合集\n创建时间: ${dayjs().format("YYYY-MM-DD HH:mm:ss")}\n`;
22 | fs.writeFileSync(filePath, fileHeader, { encoding: "utf-8" });
23 | }
24 | // 追加内容
25 | fs.appendFileSync(filePath, content, { encoding: "utf-8" });
26 | };
27 |
28 | const crawlArticles = async (urls: string[], outputFilePath: string) => {
29 | const results: ArticleResult[] = [];
30 |
31 | // 确保输出目录存在
32 | const outputDir = path.dirname(outputFilePath);
33 | if (!fs.existsSync(outputDir)) {
34 | fs.mkdirSync(outputDir, { recursive: true });
35 | }
36 |
37 | const crawler = new PlaywrightCrawler({
38 | headless: true,
39 | requestHandlerTimeoutSecs: 60,
40 | maxRequestsPerCrawl: urls.length,
41 |
42 | async requestHandler({ request, page, log }) {
43 | const url = request.url;
44 | try {
45 | log.info(`开始爬取文章: ${url}`);
46 |
47 | await page.waitForSelector("#article-root", { timeout: 10000 });
48 | const title = await page.title();
49 | log.info(`文章标题: ${title}`);
50 |
51 | const articleHtml = await page.$eval("#article-root", (el) => el.innerHTML);
52 |
53 | if (!articleHtml) {
54 | throw new Error("未找到文章内容");
55 | }
56 |
57 | const md = formatMarkdown(articleHtml);
58 |
59 | // 构建要追加的内容,包含分隔符和元数据
60 | const contentToAppend = `\n\n---\n# ${title}\n原文链接: ${url}\n爬取时间: ${dayjs().format(
61 | "YYYY-MM-DD HH:mm:ss"
62 | )}\n\n${md}\n`;
63 |
64 | // 追加到指定文件
65 | appendToFile(outputFilePath, contentToAppend);
66 |
67 | log.info(`文章爬取成功: ${url}`);
68 | results.push({ url, success: true, title });
69 | } catch (error) {
70 | log.error(`文章爬取失败: ${url}`, { error });
71 | results.push({
72 | url,
73 | success: false,
74 | error: error instanceof Error ? error.message : "未知错误",
75 | });
76 | }
77 | },
78 | });
79 |
80 | await crawler.run(urls);
81 | return results;
82 | };
83 |
84 | /**
85 | * 获取前端分类的文章数据并按点赞数排序
86 | * 并获取文章的url
87 | */
88 | const articleUrls = getFrontendArticles(jsonData, "2025-01").map((article) => article.url);
89 |
90 | // 指定输出文件路径
91 | const outputFilePath = path.join(process.cwd(), "temp/material/2025.01.md");
92 |
93 | crawlArticles(articleUrls, outputFilePath)
94 | .then((results) => {
95 | console.log("爬取完成!");
96 | console.log(`成功: ${results.filter((r) => r.success).length}`);
97 | console.log(`失败: ${results.filter((r) => !r.success).length}`);
98 |
99 | // 打印成功爬取的文章标题
100 | results
101 | .filter((r) => r.success)
102 | .forEach((r) => {
103 | console.log(`- ${r.title}`);
104 | });
105 | })
106 | .catch((error) => {
107 | console.error("爬取过程出错:", error);
108 | });
109 |
--------------------------------------------------------------------------------
/src/githubApi/releaseNote/index.ts:
--------------------------------------------------------------------------------
1 | import { getReleaseContent } from "./helper";
2 | import { split, toNumber, join, replace, get, filter } from "lodash";
3 | import {
4 | createRelease,
5 | createTagObjectRequest,
6 | createTagRequest,
7 | getDataIssue,
8 | getPackageJson,
9 | getTag,
10 | updatePackageJson,
11 | } from "./request";
12 | import dayjs from "dayjs";
13 | import utc from "dayjs/plugin/utc";
14 | import timezone from "dayjs/plugin/timezone";
15 | import { base64ToString, stringToBase64 } from "@utils/helper";
16 | import path from "path";
17 | import { writeContentForLocal } from "@src/githubApi/writeTagForLocal";
18 |
19 | dayjs.extend(utc);
20 | dayjs.extend(timezone);
21 |
22 | const main = async () => {
23 | // 获取 package.json
24 | const res = await getPackageJson();
25 | console.log("yanle - logger: 获取 package json 完成");
26 | const sha = get(res, "data.sha");
27 | let packageString = base64ToString(get(res, "data.content"));
28 | const packageJson = JSON.parse(packageString);
29 | const currentVersion = Reflect.get(packageJson, "version");
30 |
31 | // 获取对应的 tag
32 | const preTagRes = await getTag(currentVersion);
33 |
34 | // 获取上一次时间戳
35 | const createDate = get(preTagRes, "data.created_at", "");
36 |
37 | // @ts-ignore
38 | const currentTZ = dayjs.tz.guess();
39 |
40 | // @ts-ignore
41 | const preDate = dayjs.tz(createDate, currentTZ).format("YYYY.MM.DD");
42 |
43 | // package.json 版本自增
44 | const [a, b, c] = split(currentVersion, ".");
45 | // 新的版本期号
46 | const patch = toNumber(c) + 1;
47 | const newVersion = join([a, b, patch], ".");
48 |
49 | // 替换旧 version
50 | packageString = replace(packageString, `"version": "${currentVersion}"`, `"version": "${newVersion}"`);
51 |
52 | // 提交更新版本
53 | const updateRes = await updatePackageJson(stringToBase64(packageString), { sha });
54 | console.log("yanle - logger: 更新 package.json version 完成");
55 | const commitSHA = get(updateRes, "data.commit.sha");
56 |
57 | // 创建 tag obj
58 | await createTagObjectRequest(newVersion, commitSHA);
59 | console.log("yanle - logger: 创建 tag object 完成");
60 |
61 | // create tag
62 | await createTagRequest(newVersion, commitSHA);
63 |
64 | // 获取最新的 issue
65 | const issueRes = await getDataIssue(createDate);
66 | console.log("yanle - logger: 获取历史 issue 完成");
67 |
68 | const currentDate = dayjs().format("YYYY.MM.DD");
69 |
70 | const date = preDate !== currentDate ? `${preDate} - ${currentDate}` : currentDate;
71 | const tag_name = newVersion;
72 |
73 | // 通过创建时间 过滤
74 | const filterData = filter(issueRes.data, (item) => {
75 | // 必须要在上一次创建时间之后
76 | return dayjs(item.created_at).isAfter(createDate);
77 | });
78 |
79 | // 获取一共有多少个题目
80 | const issueLength = get(filterData, "length");
81 |
82 | const issueLenDesc = issueLength ? `(${issueLength}道题)` : "";
83 | const releaseName = `${date} 更新前端面试问题总结${issueLenDesc}`;
84 | const releaseBody = getReleaseContent(filterData, releaseName);
85 |
86 | await createRelease({ tag_name, name: releaseName, body: releaseBody });
87 | console.log("yanle - logger: 创建 Release 完成");
88 |
89 | /* ============================== 写入本地 - Start ============================== */
90 | // 写入本地
91 | const contentHasBody = getReleaseContent(filterData, releaseName, true);
92 | const bookPath = path.resolve(__dirname, "../../../books");
93 |
94 | const fileName = `[第${patch}期].${dayjs().format("YYYY-MM-DD")} 更新`;
95 |
96 | await writeContentForLocal({ path: bookPath, fileName, content: contentHasBody });
97 | /* ============================== 写入本地 - End ============================== */
98 | };
99 |
100 | main();
101 |
102 | export {};
103 |
--------------------------------------------------------------------------------
/src/githubApi/file/temp.md:
--------------------------------------------------------------------------------
1 | > 作者备注
2 | >
3 | > 新版本已经废弃使用 cancelToken ,改为使用 signal
4 |
5 | ### 取消请求
6 |
7 | `timeout`在 axios 调用中设置属性**可处理响应**相关的超时。
8 |
9 | 在某些情况下(例如网络连接不可用),提前取消连接对 axios**调用**大有裨益。如果不取消连接,axios 调用可能会挂起,直到父代码/堆栈超时(在服务器端应用程序中可能需要几分钟)。
10 |
11 | 要终止 axios 调用,您可以使用以下方法:
12 |
13 | - `signal`
14 | - `cancelToken`(已弃用)
15 |
16 | 组合`timeout`和取消方法(例如`signal`)应该涵盖**响应**相关的超时和**连接**相关的超时。
17 |
18 | ### `signal`:中止控制器
19 |
20 | 从`v0.22.0`Axios 开始支持[`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)以 fetch API 方式取消请求:
21 |
22 | ```js
23 | const controller = new AbortController();
24 |
25 | axios
26 | .get("/foo/bar", {
27 | signal: controller.signal,
28 | })
29 | .then(function (response) {
30 | //...
31 | });
32 | // cancel the request
33 | controller.abort();
34 | ```
35 |
36 | 使用最新 API `nodejs 17.3+`. 的超时示例[`AbortSignal.timeout()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout):
37 |
38 | ```js
39 | axios
40 | .get("/foo/bar", {
41 | signal: AbortSignal.timeout(5000), //Aborts request after 5 seconds
42 | })
43 | .then(function (response) {
44 | //...
45 | });
46 | ```
47 |
48 | 具有超时辅助函数的示例:
49 |
50 | ```js
51 | function newAbortSignal(timeoutMs) {
52 | const abortController = new AbortController();
53 | setTimeout(() => abortController.abort(), timeoutMs || 0);
54 |
55 | return abortController.signal;
56 | }
57 |
58 | axios
59 | .get("/foo/bar", {
60 | signal: newAbortSignal(5000), //Aborts request after 5 seconds
61 | })
62 | .then(function (response) {
63 | //...
64 | });
65 | ```
66 |
67 | ### 取消令牌`deprecated`
68 |
69 | 还可以使用 CancelToken\_取消请求。
70 |
71 | > Axios 取消令牌 API 基于已撤回的[可取消承诺提案](https://github.com/tc39/proposal-cancelable-promises)。
72 |
73 | > 此 API 已弃用`v0.22.0`,不应在新项目中使用
74 |
75 | 您可以使用工厂创建取消令牌`CancelToken.source`,如下所示:
76 |
77 | ```js
78 | const CancelToken = axios.CancelToken;
79 | const source = CancelToken.source();
80 |
81 | axios
82 | .get("/user/12345", {
83 | cancelToken: source.token,
84 | })
85 | .catch(function (thrown) {
86 | if (axios.isCancel(thrown)) {
87 | console.log("Request canceled", thrown.message);
88 | } else {
89 | // handle error
90 | }
91 | });
92 |
93 | axios.post(
94 | "/user/12345",
95 | {
96 | name: "new name",
97 | },
98 | {
99 | cancelToken: source.token,
100 | }
101 | );
102 |
103 | // cancel the request (the message parameter is optional)
104 | source.cancel("Operation canceled by the user.");
105 | ```
106 |
107 | 您还可以通过将执行器函数传递给构造函数来创建取消令牌`CancelToken`:
108 |
109 | ```js
110 | const CancelToken = axios.CancelToken;
111 | let cancel;
112 |
113 | axios.get("/user/12345", {
114 | cancelToken: new CancelToken(function executor(c) {
115 | // An executor function receives a cancel function as a parameter
116 | cancel = c;
117 | }),
118 | });
119 |
120 | // cancel the request
121 | cancel();
122 | ```
123 |
124 | > 注意:您可以使用相同的取消令牌/信号取消多个请求。
125 |
126 | 在过渡期间,你可以使用这两个取消 API,即使对于同一个请求也是如此:
127 |
128 | ```js
129 | const controller = new AbortController();
130 |
131 | const CancelToken = axios.CancelToken;
132 | const source = CancelToken.source();
133 |
134 | axios
135 | .get("/user/12345", {
136 | cancelToken: source.token,
137 | signal: controller.signal,
138 | })
139 | .catch(function (thrown) {
140 | if (axios.isCancel(thrown)) {
141 | console.log("Request canceled", thrown.message);
142 | } else {
143 | // handle error
144 | }
145 | });
146 |
147 | axios.post(
148 | "/user/12345",
149 | {
150 | name: "new name",
151 | },
152 | {
153 | cancelToken: source.token,
154 | }
155 | );
156 |
157 | // cancel the request (the message parameter is optional)
158 | source.cancel("Operation canceled by the user.");
159 | // OR
160 | controller.abort(); // the message parameter is not supported
161 | ```
162 |
--------------------------------------------------------------------------------
/doc.md:
--------------------------------------------------------------------------------
1 | ## 问题收集
2 |
3 | - https://juejin.cn/post/7399983901806854179
4 |
5 | 发现题库羊毛
6 |
7 | - https://fe.ecool.fun/topic-list
8 | - https://github.com/linwu-hi/code-interview/issues
9 | - https://q.shanyue.tech/interview
10 | - https://github.com/wangtunan/blog
11 | - https://github.com/Advanced-Frontend/Daily-Interview-Question/issues
12 |
13 | ## 待整理
14 |
15 | - 同一页面三个组件请求同一个 API 发送了三次请求,如何优化
16 | - 简述 koa 的中间件原理,手写 koa-compose 代码
17 | - 如何压缩前端项目中 JS 的体积
18 | - 如何优化 React 项目的性能
19 | - 实现一个函数 maxBy,根据给定条件找到最大的数组项
20 | - 实现一个函数 max,找到数组中最大的一个值/两个值/N 个值
21 | - 什么是安全整数,如何判断一个整数是安全整数
22 | - 在 Node 中如何读写文件
23 | - 在 Node 中如何发送请求
24 | - Node 中服务端框架如何解析 http 的请求体 body
25 | - 统计字符串中出现次数最多的字符及次数
26 | - 请输出 100 以内的菲波那切数列
27 | - 你们项目中使用了哪些依赖/第三方库
28 | - 如何使用正则匹配一个汉字
29 | - 如何把字符串全部转化为小写格式
30 | - HTTP 与 TCP 中的 keep-alive 各是什么
31 | - 如何实现数组函数 reduce
32 | - 在 Node 中流 (stream) 分为几类,有哪些应用场景
33 | - 如何实现 chunk 函数,数组进行分组
34 | - 实现一个异步的 sum/add
35 | - 随机生成六位数的手机验证码(重复/不可重复)
36 | - 如何禁止打开浏览器控制台
37 | - Array 中那些 API 可改变自身
38 | - 如何把一个数组 Array 转化为迭代器 Iterable
39 | - 如何去除字符串首尾空白字符
40 | - http 各个版本间各有什么改进
41 | - 简述 http3,http3 解决了什么问题
42 | - http2 中 Stream 与 Frame 是什么关系
43 | - useLayoutEffect 和 useEffect 有什么区别
44 | - css 加载会阻塞 DOM 树的解析和渲染吗
45 | - 实现 intersection,取数组交集
46 | - JS 中如何实现 call/apply
47 | - 实现一个 composeLeft/flow(从左向右) 函数,进行函数合成
48 | - 什么是点击劫持(ClickJacking),如何预防
49 | - 在 React Hooks 中实现 usePreviouseValue 取上次渲染的值
50 | - 实现一个 render/template 函数,可以用以渲染模板
51 | - Number 中最大数、最大安全整数、EPSILON 都是多少,原理是什么
52 | - 给定一个数值,给出它在 IEEE754 的表示,如符号位、指数位与分数位
53 | - 请简述下 Node 与浏览器环境中的事件循环
54 | - JS 如何检测到对象中有循环引用
55 | - 实现二进制与十进制的互相转化的两个函数
56 | - 简述下 WebWorker,它如何进行通信
57 | - JS 中异步任务为何分为微任务与宏任务
58 | - 在 CSS 中,使用 rem 作为单位有何缺点
59 | - 如何提高首屏渲染时间?
60 | - 浏览器中监听事件函数 addEventListener 第三个参数有那些值
61 | - 什么是原码、补码与反码
62 | - 求给定数组中 N 个数相加之和为 sum 所有可能集合
63 | - 在 Node 中如何读取可读流的内容
64 | - 浏览器中 Frame 与 Event Loop 的关系是什么
65 | - 在 Typescript 中如何实现类型标记 Pick 与 Omit
66 | - 如何实现一个 sampleSize 函数,从数组中随机取 N 个元素
67 | - 实现一个函数 keyBy
68 | - 实现一个函数 groupBy
69 | - 在 Node 中如何读取大文件的内容
70 | - 求正序增长的正整数数组中,其和为 N 的两个数
71 | - FizzBuzz,是否能被 3 或 5 整除
72 | - 实现一个函数 camelCase,对变量转化为驼峰命名
73 | - 如何遍历一个对象
74 | - 网站性能优化中,如何对小图片进行优化
75 | - https 如何被抓包,原理是什么
76 | - setTimeout 为什么最小只能设置 4ms,如何实现一个 0ms 的 setTimeout?
77 | - JS 中如何原生实现 instanceOf
78 | - 如何根据 random5 随机生成 [0, 5],生成一个函数 random7?
79 | - 如何实现一个 ORM 类似的 find 链式调用
80 | - 什么是协变与逆变
81 | - 在 ts 中如何实现 Partial
82 | - 在 ts 中什么是 infer,并实现 Parameters 与 ReturnType
83 | - Flex 布局中的 flex-basis 与 width 有何区别
84 | - OSCP Stapling 是什么
85 | - npm 执行命令传递参数时,为何需要双横线
86 | - 有没有使用过 Node 的 inspect 这个核心模块
87 | - 在虚拟 DOM 中进行 diff 算法时,介绍当根据 key 对数组进行重用时的算法
88 | - http client 中如何得知已接收完所有响应数据
89 | - 实现函数 promisify,把回调函数改成 promise 形式
90 | - return promise 与 return await promise 有何区别
91 | - 在 ES6 Class 中,super 的过程中做了什么
92 | - 关于 Promise,判断以下代码的输出
93 | - webpack 的 runtime 做了什么事情
94 | - typescript 中 interface 与 type 有何区别
95 | - 请简述 typescript 中的 infer
96 | - webpack 中的 code spliting 是如何动态加载 chunk 的?
97 | - core-js 是做什么用的?
98 | - 打包器(webpack/rollup) 如何将打包后的 js 资源注入 html 中
99 | - 打包器(webpack/rollup) 如何加载 json、image 等非 Javascript 资源
100 | - 打包器(webpack/rollup) 如何加载 style 样式资源
101 | - 如何提升 webpack 构建资源的速度
102 | - 如何处理白屏错误页的监控的?
103 | - 简述 npm script 的生命周期
104 | - git hooks 原理是什么
105 | - 如何检测出你们安装的依赖是否安全
106 | - 请简述下 eslint 的作用
107 | - 在项目中,如何平滑升级 npm 包
108 | - 请描述 node_modules 的目录结构(拓扑结构)
109 | - npm 第三方库需要提交 lockfile 吗
110 | - 请问什么是 CICD
111 | - 如何使用 docker 部署前端
112 | - pnpm 有什么优势
113 | - 浏览器中如何使用原生的 ESM
114 | - 如何将 CommonJS 转化为 ESM
115 | - 如何对 npm package 进行发包
116 | - 如何分析前端打包体积
117 | - 什么是 AST,及其应用
118 | - 简述 browserslist 的意义
119 | - 简述 bundless 的优势与不足
120 | - 简述 npm cache
121 | - 如何修复某个 npm 包的紧急 bug
122 | - 前端如何进行高效的分包
123 | - 前端如何对分支环境进行部署
124 | - 如何取得一个数字的小数部分与整数部分
125 | - websocket 和短轮询有什么区别
126 | - webpack 中是如何处理 new URL 资源的
127 | - vite 中是如何处理 new URL 资源的
128 | - 我们上传图片为 Blob/File 对象时,是如何向服务器端传送数据的
129 | - 如何实现一个 omit/omitBy 函数
130 | - 在 babel 编译为低版本 ES 时,为何能够编译可选链之类语法,但无法编译 API
131 | - 实现 batchFn 函数,可以批量执行函数
132 | - 在 react 中,以下父子组件的 useEffect/useLayoutEffect 顺序如何
133 | - webpack 的打包流程是什么样的
134 | - React18 有哪些新特性
135 | - React19 有哪些新特性
136 |
--------------------------------------------------------------------------------
/src/githubApi/releaseNote/helper.ts:
--------------------------------------------------------------------------------
1 | import { forEach, isEmpty, join, map, reduce, sortBy, filter, includes } from "lodash";
2 | import { company } from "@src/githubApi/issue/consts";
3 |
4 | /**
5 | * 获取 创建 release note 的 文本 body
6 | * @param issueList
7 | * @param releaseName
8 | * @param isBody
9 | */
10 | export const getReleaseContent = (issueList: any[], releaseName: string, isBody: boolean = false) => {
11 | const companyList = Object.values(company);
12 |
13 | const list = map(issueList, (item) => {
14 | return {
15 | title: item.title,
16 | url: item.html_url,
17 | labels: map(item.labels, (label) => label.name),
18 | level: item.milestone.title,
19 | number: item.number,
20 | body: item.body,
21 | };
22 | });
23 |
24 | const base: any[] = [];
25 | const inProgress: any[] = [];
26 | const senior: any[] = [];
27 | const master: any[] = [];
28 |
29 | forEach(list, (item) => {
30 | switch (item.level) {
31 | case "初":
32 | base.push(item);
33 | break;
34 | case "中":
35 | inProgress.push(item);
36 | break;
37 | case "高":
38 | senior.push(item);
39 | break;
40 | case "资深":
41 | master.push(item);
42 | break;
43 | default:
44 | break;
45 | }
46 | });
47 |
48 | const itemTitle = (list: any[]) =>
49 | map(list, (item) => {
50 | const bodyContent = `
51 | ${item.body}
52 | `;
53 | const questionLink = `回答链接:${item.url} `;
54 | const body = isBody ? bodyContent : questionLink;
55 |
56 | // 出现该问题的公司是谁
57 | const companyName = filter(item.labels, (labelItem) => includes(companyList, labelItem));
58 | const companyString = isEmpty(companyName) ? "" : `【出题公司: ${join(companyName, "、")}】`;
59 |
60 | // 普通的标签
61 | const commonLabels = filter(item.labels, (label) => !includes(companyList, label));
62 |
63 | const simpleTitle = `${item.number}. ${item.title}【${join(commonLabels, "、")}】${companyString}`;
64 | const title = isBody ? `## ${simpleTitle}` : simpleTitle;
65 | return `
66 | ${title}
67 | ${body}
68 | `;
69 | });
70 |
71 | const justTitle = (list: any[]) =>
72 | map(list, (item) => {
73 | // 出现该问题的公司是谁
74 | const companyName = filter(item.labels, (labelItem) => includes(companyList, labelItem));
75 | const companyString = isEmpty(companyName) ? "" : `【出题公司: ${join(companyName, "、")}】`;
76 |
77 | // 普通的标签
78 | const commonLabels = filter(item.labels, (label) => !includes(companyList, label));
79 |
80 | // title
81 | return `${item.number}. ${item.title}【${join(commonLabels, "、")}】${companyString}`;
82 | });
83 |
84 | const mapTitle = (list: any[]) =>
85 | reduce(justTitle(sortBy(list, "number")), (prev, current) => prev + current + "\n", "");
86 |
87 | // 目录文件
88 | const index = `
89 | **目录**:
90 |
91 | ${isEmpty(base) ? "" : `**初级开发者相关问题【共计 ${base.length} 道题】**`}
92 |
93 | ${mapTitle(base)}
94 |
95 | ${isEmpty(inProgress) ? "" : `**中级开发者相关问题【共计 ${inProgress.length} 道题】**`}
96 |
97 | ${mapTitle(inProgress)}
98 |
99 | ${isEmpty(senior) ? "" : `**高级开发者相关问题【共计 ${senior.length} 道题】**`}
100 |
101 | ${mapTitle(senior)}
102 |
103 | ${isEmpty(master) ? "" : `**资深开发者相关问题【共计 ${master.length} 道题】**`}
104 |
105 | ${mapTitle(master)}
106 |
107 | `;
108 |
109 | const reduceToString = (list: any[]) =>
110 | reduce(itemTitle(sortBy(list, "number")), (prev, current) => prev + current, "");
111 |
112 | // 需要将 list 写成一个 markdown
113 | const content = `> ${releaseName}
114 | > 获取更多面试相关问题可以访问
115 | > github 地址: https://github.com/pro-collection/interview-question/issues
116 | > gitee 地址: https://gitee.com/yanleweb/interview-question/issues
117 |
118 |
119 | ${isBody ? index : ""}
120 |
121 |
122 | ${isEmpty(base) ? "" : `# 初级开发者相关问题【共计 ${base.length} 道题】`}
123 | ${reduceToString(base)}
124 |
125 |
126 | ${isEmpty(inProgress) ? "" : `# 中级开发者相关问题【共计 ${inProgress.length} 道题】`}
127 | ${reduceToString(inProgress)}
128 |
129 |
130 | ${isEmpty(senior) ? "" : `# 高级开发者相关问题【共计 ${senior.length} 道题】`}
131 | ${reduceToString(senior)}
132 |
133 |
134 | ${isEmpty(master) ? "" : `# 资深开发者相关问题【共计 ${master.length} 道题】`}
135 | ${reduceToString(master)}
136 | `;
137 |
138 | return content;
139 | };
140 |
--------------------------------------------------------------------------------
/books/2023年/0.0.13.md:
--------------------------------------------------------------------------------
1 |
2 | ## 初级开发者相关问题
3 |
4 | 1.Promise 了解多少?【JavaScript】
5 | 回答链接:https://github.com/pro-collection/interview-question/issues/1
6 |
7 | 9.call、apply、bind 的区别和用法?【JavaScript】
8 | 回答链接:https://github.com/pro-collection/interview-question/issues/9
9 |
10 | 10.let 和 const 与 var 的区别?【JavaScript】
11 | 回答链接:https://github.com/pro-collection/interview-question/issues/10
12 |
13 | 19.什么是同源策略?【网络】
14 | 回答链接:https://github.com/pro-collection/interview-question/issues/19
15 |
16 | 24.JS数据类型有哪些,区别是什么?【JavaScript】
17 | 回答链接:https://github.com/pro-collection/interview-question/issues/24
18 |
19 | 29.请简述 HTTP 请求的过程【网络】
20 | 回答链接:https://github.com/pro-collection/interview-question/issues/29
21 |
22 | 31.JS 中继承方式有哪些?【JavaScript】
23 | 回答链接:https://github.com/pro-collection/interview-question/issues/31
24 |
25 | 32.解释一下 原型、构造函、实例、原型链 之间的关系?【JavaScript】
26 | 回答链接:https://github.com/pro-collection/interview-question/issues/32
27 |
28 | 34.DOM事件类相关问题【JavaScript】
29 | 回答链接:https://github.com/pro-collection/interview-question/issues/34
30 |
31 | 35.解释边距重叠【CSS】
32 | 回答链接:https://github.com/pro-collection/interview-question/issues/35
33 |
34 | 36.水平垂直居中定位【CSS】
35 | 回答链接:https://github.com/pro-collection/interview-question/issues/36
36 |
37 |
38 |
39 | ## 中级开发者相关问题
40 |
41 | 3.ES6 Generator 了解多少?【JavaScript】
42 | 回答链接:https://github.com/pro-collection/interview-question/issues/3
43 |
44 | 4.ES6 Map 数据结构了解多少?【JavaScript】
45 | 回答链接:https://github.com/pro-collection/interview-question/issues/4
46 |
47 | 5.Map 和 Object 有哪些主要的区别?【JavaScript】
48 | 回答链接:https://github.com/pro-collection/interview-question/issues/5
49 |
50 | 6.如何检测对象是否循环引用?【JavaScript】
51 | 回答链接:https://github.com/pro-collection/interview-question/issues/6
52 |
53 | 7.es6 数据结构 Set 了解多少?【JavaScript】
54 | 回答链接:https://github.com/pro-collection/interview-question/issues/7
55 |
56 | 8.Proxy 和 Reflect 了解多少?【JavaScript】
57 | 回答链接:https://github.com/pro-collection/interview-question/issues/8
58 |
59 | 11.常见数组排序算法有哪些?【JavaScript】
60 | 回答链接:https://github.com/pro-collection/interview-question/issues/11
61 |
62 | 12.WebSocket 了解多少?【网络】
63 | 回答链接:https://github.com/pro-collection/interview-question/issues/12
64 |
65 | 13.postMessage 是如何解决跨域问题的?【网络】
66 | 回答链接:https://github.com/pro-collection/interview-question/issues/13
67 |
68 | 14.CORS 是如何实现跨域的?【网络】
69 | 回答链接:https://github.com/pro-collection/interview-question/issues/14
70 |
71 | 15.JSONP 是如何实现跨域的?【网络】
72 | 回答链接:https://github.com/pro-collection/interview-question/issues/15
73 |
74 | 16.跨域通信的常见方式有哪些?【网络】
75 | 回答链接:https://github.com/pro-collection/interview-question/issues/16
76 |
77 | 17.ajax如何获取下载进度?【JavaScript】
78 | 回答链接:https://github.com/pro-collection/interview-question/issues/17
79 |
80 | 18.手写创建一个 ajax 请求【JavaScript】
81 | 回答链接:https://github.com/pro-collection/interview-question/issues/18
82 |
83 | 20.JS 有哪些迭代器,该如何使用?【JavaScript】
84 | 回答链接:https://github.com/pro-collection/interview-question/issues/20
85 |
86 | 21.如何使对象 iterable 化, 以其可以支持 for...of 迭代【JavaScript】
87 | 回答链接:https://github.com/pro-collection/interview-question/issues/21
88 |
89 | 22.js 对象可以使用 for...of 迭代吗?【JavaScript】
90 | 回答链接:https://github.com/pro-collection/interview-question/issues/22
91 |
92 | 23.详细讲一下 Symbol 数据类型特征与实际使用案例?【JavaScript】
93 | 回答链接:https://github.com/pro-collection/interview-question/issues/23
94 |
95 | 25.网络模型分层大概有哪些层级?【网络】
96 | 回答链接:https://github.com/pro-collection/interview-question/issues/25
97 |
98 | 26.TCP 传输过程?【网络】
99 | 回答链接:https://github.com/pro-collection/interview-question/issues/26
100 |
101 | 27.HTTP建立连接的过程?【网络】
102 | 回答链接:https://github.com/pro-collection/interview-question/issues/27
103 |
104 | 30.实现一个双向链表, 具备添加节点、删除节点、在特定位置插入节点、查找节点、遍历等功能【JavaScript】
105 | 回答链接:https://github.com/pro-collection/interview-question/issues/30
106 |
107 | 33.Http协议基础【网络】
108 | 回答链接:https://github.com/pro-collection/interview-question/issues/33
109 |
110 |
111 |
112 | ## 高级开发者相关问题
113 |
114 | 2.手写 async 函数?【JavaScript】
115 | 回答链接:https://github.com/pro-collection/interview-question/issues/2
116 |
117 | 28.HTTP 缓存策略有哪些?【网络】
118 | 回答链接:https://github.com/pro-collection/interview-question/issues/28
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/src/spider/juejin/utils.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import fs from "fs";
3 |
4 | /**
5 | * 从文件名解析年月
6 | * @param fileName - 格式为 "YYYY_MM" 的文件名,如 "2024_12"
7 | * @returns 格式为 "YYYY-MM" 的日期字符串,如 "2024-12"
8 | * @example
9 | * parseYearMonthFromFileName("2024_12") // returns "2024-12"
10 | */
11 | const parseYearMonthFromFileName = (fileName: string) => {
12 | // 将文件名按下划线分割成年和月
13 | const [year, month] = fileName.split("_");
14 | // 返回格式化的年月字符串
15 | return `${year}-${month}`;
16 | };
17 |
18 | /**
19 | * 将Unix时间戳转换为 YYYY-MM 格式的日期字符串
20 | * @param timestamp - Unix时间戳字符串
21 | * @returns 格式为 "YYYY-MM" 的日期字符串
22 | * @example
23 | * timestampToYearMonth("1703980800") // returns "2024-01"
24 | */
25 | const timestampToYearMonth = (timestamp: string) => {
26 | // 将时间戳转换为Date对象
27 | const date = new Date(parseInt(timestamp) * 1000);
28 | // 返回格式化的年月字符串,月份补零
29 | return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
30 | };
31 |
32 | /**
33 | * 格式化文章数据,按分类整理并排序
34 | * @param jsonData - 原始文章数据数组
35 | * @param targetDate - 目标日期,格式为 "YYYY-MM"
36 | * @returns 按分类整理的文章数据对象
37 | */
38 | export const formatArticleData = (jsonData: any[], targetDate: string) => {
39 | // 创建一个对象来存储不同分类的文章
40 | const categoryArticles: Record<
41 | string,
42 | Array<{
43 | title: string; // 文章标题
44 | url: string; // 文章链接
45 | diggCount: number; // 点赞数
46 | }>
47 | > = {};
48 |
49 | console.log("formatArticleData: jsonData.length", jsonData.length);
50 |
51 | // 遍历并处理每篇文章
52 | jsonData.forEach((item) => {
53 | const article = item.article_info;
54 | const categoryName = item.category_name;
55 |
56 | // 检查文章创建时间是否匹配目标月份
57 | const createTime = timestampToYearMonth(article.ctime);
58 | if (createTime !== targetDate) {
59 | return;
60 | }
61 |
62 | // 构建文章数据对象
63 | const articleData = {
64 | title: article.title,
65 | url: `https://juejin.cn/post/${article.article_id}`,
66 | diggCount: article.digg_count,
67 | };
68 |
69 | // 将文章添加到对应分类中
70 | if (!categoryArticles[categoryName]) {
71 | categoryArticles[categoryName] = [];
72 | }
73 | categoryArticles[categoryName].push(articleData);
74 | });
75 |
76 | // 对每个分类中的文章按点赞数降序排序
77 | Object.keys(categoryArticles).forEach((category) => {
78 | categoryArticles[category].sort((a, b) => b.diggCount - a.diggCount);
79 | });
80 |
81 | return categoryArticles;
82 | };
83 |
84 | /**
85 | * 生成Markdown格式的内容
86 | * @param categoryArticles - 按分类整理的文章数据对象
87 | * @returns Markdown格式的字符串
88 | */
89 | const generateMarkdown = (categoryArticles: Record>) => {
90 | let markdown = "";
91 |
92 | // 遍历每个分类
93 | Object.entries(categoryArticles).forEach(([category, articles]) => {
94 | if (articles.length > 0) {
95 | // 添加分类标题
96 | markdown += `### ${category}\n`;
97 | // 添加该分类下的所有文章
98 | articles.forEach((article) => {
99 | markdown += `- \`点赞量: ${article.diggCount}\` - [${article.title}](${article.url})\n`;
100 | });
101 | markdown += "\n";
102 | }
103 | });
104 |
105 | return markdown;
106 | };
107 |
108 | /**
109 | * 主函数:处理数据并生成Markdown文件
110 | * @param jsonData - 原始文章数据数组
111 | * @param fileName - 输出文件名(不含扩展名),格式为 "YYYY_MM"
112 | */
113 | export const handleDataParseMD = (jsonData: any[], fileName: string) => {
114 | // 从文件名解析目标日期
115 | const targetDate = parseYearMonthFromFileName(fileName);
116 |
117 | // 格式化文章数据
118 | const categoryArticles = formatArticleData(jsonData, targetDate);
119 |
120 | // 生成Markdown内容
121 | const markdownContent = generateMarkdown(categoryArticles);
122 |
123 | // 构建输出文件路径
124 | const filePath = path.join(process.cwd(), `temp/juejin_interview/${fileName}.md`);
125 |
126 | // 将内容写入文件
127 | fs.writeFile(filePath, markdownContent, (err) => {
128 | if (err) {
129 | console.error("Error writing to file:", err);
130 | } else {
131 | console.log("Data written to file successfully.");
132 | }
133 | });
134 | };
135 |
136 | /**
137 | * 获取前端分类的文章数据并按点赞数排序
138 | * @param jsonData - 原始文章数据数组
139 | * @param targetDate - 目标日期,格式为 "YYYY-MM"
140 | * @returns 前端分类的文章数据数组
141 | */
142 | export const getFrontendArticles = (
143 | jsonData: any[],
144 | targetDate: string
145 | ): Array<{
146 | title: string;
147 | url: string;
148 | diggCount: number;
149 | }> => {
150 | // 使用 formatArticleData 获取所有分类的文章
151 | const categoryArticles = formatArticleData(jsonData, targetDate);
152 |
153 | // 返回前端分类的文章,如果不存在则返回空数组
154 | return categoryArticles["前端"] || [];
155 | };
156 |
157 | // 使用示例
158 | // handleDataParseMD(jsonData, "2024_12");
159 |
--------------------------------------------------------------------------------
/src/githubApi/file/demo.md:
--------------------------------------------------------------------------------
1 | **关键词**:nginx 加载特定资源
2 |
3 | Nginx 为不同前端资源配置缓存策略的核心是**根据资源特性(是否常变、是否带版本标识)差异化设置缓存规则**,同时通过特定机制实现特定资源的强制刷新。以下是详细方案:
4 |
5 | ### 一、按资源类型配置差异化缓存策略
6 |
7 | 前端资源可分为**静态资源**(JS、CSS、图片等)和**入口文件**(如 `index.html`),需根据其更新频率和版本管理方式设置不同缓存策略:
8 |
9 | #### 1. 带哈希/版本号的静态资源(永久强缓存)
10 |
11 | **特征**:文件名含唯一哈希(如 `app.8f3b.js`)或版本号(如 `v2/style.css`),内容变化时文件名必变。
12 | **策略**:设置长期强缓存,减少重复请求。
13 |
14 | ```nginx
15 | # 匹配带哈希的 JS/CSS/图片(假设哈希为 8-16 位字符)
16 | location ~* \.\w{8,16}\.(js|css|png|jpg|jpeg|webp|svg)$ {
17 | # 缓存 1 年(31536000 秒)
18 | expires 365d;
19 | # 强缓存标识:浏览器直接使用本地缓存,不发送请求
20 | add_header Cache-Control "public, max-age=31536000, immutable";
21 | }
22 | ```
23 |
24 | - **关键参数**:`immutable`(H5 新特性)告知浏览器资源不会变化,避免发送无效的条件请求(如 `If-Modified-Since`)。
25 |
26 | #### 2. 无哈希的静态资源(短期强缓存 + 协商缓存)
27 |
28 | **特征**:文件名固定(如 `favicon.ico`、`common.js`),可能不定期更新但无版本标识。
29 | **策略**:短期强缓存减少请求,过期后通过协商缓存验证是否更新。
30 |
31 | ```nginx
32 | # 匹配无哈希的图片、字体等
33 | location ~* \.(png|jpg|jpeg|ico|woff2?)$ {
34 | # 短期强缓存 7 天
35 | expires 7d;
36 | # 过期后必须验证是否更新
37 | add_header Cache-Control "public, max-age=604800, must-revalidate";
38 | }
39 | ```
40 |
41 | #### 3. 入口文件与动态页面(协商缓存)
42 |
43 | **特征**:如 `index.html`、`page.html`,作为路由入口或动态内容载体,需确保用户获取最新版本。
44 | **策略**:禁用强缓存,每次请求通过协商缓存验证。
45 |
46 | ```nginx
47 | # 入口文件(如 index.html)
48 | location = /index.html {
49 | # 禁用强缓存(立即过期)
50 | expires -1;
51 | # 协商缓存:必须向服务器验证
52 | add_header Cache-Control "no-cache, must-revalidate";
53 | }
54 |
55 | # 其他 HTML 页面
56 | location ~* \.html$ {
57 | expires -1;
58 | add_header Cache-Control "no-cache, must-revalidate";
59 | }
60 | ```
61 |
62 | - **协商缓存原理**:Nginx 自动返回 `Last-Modified`(文件修改时间),浏览器下次请求携带 `If-Modified-Since`,服务器比对后返回 `304`(未修改)或 `200`(新内容)。
63 |
64 | #### 4. API 接口与动态数据(无缓存或短时缓存)
65 |
66 | **特征**:如 `/api/user`,返回动态数据,需实时性。
67 | **策略**:禁用缓存或设置极短缓存时间。
68 |
69 | ```nginx
70 | # API 接口
71 | location /api {
72 | # 完全禁用缓存
73 | add_header Cache-Control "no-store, no-cache, must-revalidate";
74 | expires -1;
75 | # 转发到后端服务
76 | proxy_pass http://backend;
77 | }
78 | ```
79 |
80 | ### 二、强制刷新特定资源的方法
81 |
82 | 当资源更新但因缓存未生效时,需强制用户获取最新版本,核心思路是**破坏缓存标识**或**主动清理缓存**:
83 |
84 | #### 1. 前端主动更新资源标识(推荐)
85 |
86 | 利用“哈希/版本号与内容绑定”的特性,资源更新时修改文件名,浏览器会视为新资源自动请求:
87 |
88 | - 例:`app.8f3b.js` → 更新后变为 `app.9c4d.js`,无需 Nginx 配置,彻底避免缓存问题。
89 |
90 | #### 2. 通过 URL 参数强制刷新(临时方案)
91 |
92 | 对无哈希的资源,可在请求 URL 后添加随机参数(如 `?v=2`),使浏览器认为是新资源:
93 |
94 | - 例:`common.js` → `common.js?v=2`
95 | - **Nginx 无需额外配置**,但需前端手动更新参数,适合临时紧急更新。
96 |
97 | #### 3. 清理 CDN 缓存(若使用 CDN)
98 |
99 | 若资源通过 CDN 分发,需在 CDN 控制台手动清理特定资源缓存:
100 |
101 | - 例:阿里云 CDN 支持按路径(如 `/*/*.js`)或具体 URL 清理缓存,生效后用户请求会回源获取最新资源。
102 |
103 | #### 4. 动态修改资源的 `Last-Modified`(不推荐)
104 |
105 | 通过 Nginx 指令强制修改资源的 `Last-Modified` 头,触发协商缓存更新:
106 |
107 | ```nginx
108 | # 强制刷新某个资源(如 common.js)
109 | location = /static/js/common.js {
110 | # 手动设置一个较新的修改时间(比实际文件新)
111 | add_header Last-Modified "Wed, 20 Sep 2025 08:00:00 GMT";
112 | # 协商缓存配置
113 | expires -1;
114 | add_header Cache-Control "no-cache, must-revalidate";
115 | }
116 | ```
117 |
118 | - **缺点**:需手动修改 Nginx 配置并 reload,仅适合紧急情况,不建议长期使用。
119 |
120 | ### 三、完整缓存配置示例
121 |
122 | ```nginx
123 | server {
124 | listen 80;
125 | server_name example.com;
126 | root /path/to/frontend;
127 |
128 | # 1. 带哈希的静态资源(永久缓存)
129 | location ~* \.\w{8,16}\.(js|css|png|jpg|jpeg|webp|svg)$ {
130 | expires 365d;
131 | add_header Cache-Control "public, max-age=31536000, immutable";
132 | }
133 |
134 | # 2. 无哈希的静态资源(短期+协商)
135 | location ~* \.(png|jpg|jpeg|ico|woff2?)$ {
136 | expires 7d;
137 | add_header Cache-Control "public, max-age=604800, must-revalidate";
138 | }
139 |
140 | # 3. 入口文件与 HTML(协商缓存)
141 | location = /index.html {
142 | expires -1;
143 | add_header Cache-Control "no-cache, must-revalidate";
144 | }
145 |
146 | # 4. API 接口(无缓存)
147 | location /api {
148 | add_header Cache-Control "no-store, no-cache";
149 | expires -1;
150 | proxy_pass http://backend;
151 | }
152 |
153 | # SPA 路由支持(配合 History 模式)
154 | location / {
155 | try_files $uri $uri/ /index.html;
156 | }
157 | }
158 | ```
159 |
160 | ### 四、关键注意事项
161 |
162 | 1. **缓存与版本管理协同**:前端打包工具(Webpack/Vite)需确保“内容变则哈希变”,与 Nginx 强缓存配合,这是最可靠的刷新方式。
163 | 2. **避免缓存 `index.html`**:入口文件必须用协商缓存,否则用户可能无法获取新的哈希资源列表。
164 | 3. **HTTPS 环境下的缓存**:若启用 HTTPS,需确保 `Cache-Control` 头正确传递(Nginx 默认不拦截),避免 CDN 或代理服务器篡改缓存策略。
165 |
166 | ### 总结
167 |
168 | - **差异化缓存**:带哈希资源用永久强缓存,无哈希资源用短期+协商缓存,入口文件和 API 禁用强缓存。
169 | - **强制刷新**:优先通过修改资源哈希/版本号实现,临时场景可用 URL 参数,CDN 资源需手动清理 CDN 缓存。
170 |
171 | 这种策略既能最大化利用缓存提升性能,又能确保资源更新及时生效。
172 |
--------------------------------------------------------------------------------
/src/spider/juejin/__tests__/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { formatArticleData, getFrontendArticles } from "../utils";
2 |
3 | describe("formatArticleData 文章数据格式化函数", () => {
4 | it("应该正确格式化文章数据并按分类和点赞数排序", () => {
5 | // 模拟输入数据
6 | const mockJsonData = [
7 | {
8 | article_info: {
9 | title: "前端文章1",
10 | article_id: "1234567890",
11 | digg_count: 100,
12 | ctime: "1706745600", // 2024-02-01
13 | },
14 | category_name: "前端",
15 | },
16 | {
17 | article_info: {
18 | title: "前端文章2",
19 | article_id: "1234567891",
20 | digg_count: 200,
21 | ctime: "1706745600", // 2024-02-01
22 | },
23 | category_name: "前端",
24 | },
25 | {
26 | article_info: {
27 | title: "后端文章1",
28 | article_id: "1234567892",
29 | digg_count: 150,
30 | ctime: "1706745600", // 2024-02-01
31 | },
32 | category_name: "后端",
33 | },
34 | {
35 | article_info: {
36 | title: "过期文章",
37 | article_id: "1234567893",
38 | digg_count: 300,
39 | ctime: "1704067200", // 2024-01-01
40 | },
41 | category_name: "前端",
42 | },
43 | ];
44 |
45 | const targetDate = "2024-02";
46 | const result = formatArticleData(mockJsonData, targetDate);
47 |
48 | // 预期输出
49 | const expectedOutput = {
50 | 前端: [
51 | {
52 | title: "前端文章2",
53 | url: "https://juejin.cn/post/1234567891",
54 | diggCount: 200,
55 | },
56 | {
57 | title: "前端文章1",
58 | url: "https://juejin.cn/post/1234567890",
59 | diggCount: 100,
60 | },
61 | ],
62 | 后端: [
63 | {
64 | title: "后端文章1",
65 | url: "https://juejin.cn/post/1234567892",
66 | diggCount: 150,
67 | },
68 | ],
69 | };
70 |
71 | // 断言测试
72 | expect(result).toEqual(expectedOutput);
73 |
74 | // 额外的具体断言
75 | expect(Object.keys(result)).toHaveLength(2); // 应该有两个分类
76 | expect(result["前端"]).toHaveLength(2); // 前端分类应该有2篇文章
77 | expect(result["后端"]).toHaveLength(1); // 后端分类应该有1篇文章
78 |
79 | // 验证排序是否正确(点赞数降序)
80 | expect(result["前端"][0].diggCount).toBeGreaterThan(result["前端"][1].diggCount);
81 | });
82 |
83 | it("应该正确处理空数组输入", () => {
84 | const result = formatArticleData([], "2024-02");
85 | expect(result).toEqual({});
86 | });
87 |
88 | it("应该过滤掉不属于目标月份的文章", () => {
89 | const mockJsonData = [
90 | {
91 | article_info: {
92 | title: "上个月的文章",
93 | article_id: "1234567890",
94 | digg_count: 100,
95 | ctime: "1704067200", // 2024-01-01
96 | },
97 | category_name: "前端",
98 | },
99 | ];
100 |
101 | const result = formatArticleData(mockJsonData, "2024-02");
102 | expect(result).toEqual({});
103 | });
104 | });
105 |
106 | describe("getFrontendArticles 获取前端文章函数", () => {
107 | it("应该正确获取前端分类的文章并按点赞数排序", () => {
108 | const mockJsonData = [
109 | {
110 | article_info: {
111 | title: "前端文章1",
112 | article_id: "1234567890",
113 | digg_count: 100,
114 | ctime: "1706745600", // 2024-02-01
115 | },
116 | category_name: "前端",
117 | },
118 | {
119 | article_info: {
120 | title: "前端文章2",
121 | article_id: "1234567891",
122 | digg_count: 200,
123 | ctime: "1706745600", // 2024-02-01
124 | },
125 | category_name: "前端",
126 | },
127 | {
128 | article_info: {
129 | title: "后端文章1",
130 | article_id: "1234567892",
131 | digg_count: 150,
132 | ctime: "1706745600", // 2024-02-01
133 | },
134 | category_name: "后端",
135 | },
136 | ];
137 |
138 | const targetDate = "2024-02";
139 | const result = getFrontendArticles(mockJsonData, targetDate);
140 |
141 | const expectedOutput = [
142 | {
143 | title: "前端文章2",
144 | url: "https://juejin.cn/post/1234567891",
145 | diggCount: 200,
146 | },
147 | {
148 | title: "前端文章1",
149 | url: "https://juejin.cn/post/1234567890",
150 | diggCount: 100,
151 | },
152 | ];
153 |
154 | // 断言测试
155 | expect(result).toEqual(expectedOutput);
156 | expect(result).toHaveLength(2);
157 | expect(result[0].diggCount).toBeGreaterThan(result[1].diggCount);
158 | });
159 |
160 | it("应该正确处理没有前端文章的情况", () => {
161 | const mockJsonData = [
162 | {
163 | article_info: {
164 | title: "后端文章1",
165 | article_id: "1234567892",
166 | digg_count: 150,
167 | ctime: "1706745600", // 2024-02-01
168 | },
169 | category_name: "后端",
170 | },
171 | ];
172 |
173 | const result = getFrontendArticles(mockJsonData, "2024-02");
174 | expect(result).toEqual([]);
175 | });
176 |
177 | it("应该正确处理空数组输入", () => {
178 | const result = getFrontendArticles([], "2024-02");
179 | expect(result).toEqual([]);
180 | });
181 | });
182 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_04.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 | - `点赞量: 262` - [面试官:如何解决按钮重复点击?这个问题挂了80%的人!](https://juejin.cn/post/7494944356534714406)
3 | - `点赞量: 163` - [面试一问就给我整不会了😭如何跨标签页通信](https://juejin.cn/post/7490769323969167394)
4 | - `点赞量: 95` - [【前端面试必杀技】前端面试中如何完美回答项目难点与亮点](https://juejin.cn/post/7492967922677366819)
5 | - `点赞量: 72` - [字节面试题之如何取消一个正在发送的请求](https://juejin.cn/post/7490783352841601051)
6 | - `点赞量: 54` - [前端远程面试全记录:项目、思维、管理一个不落 😔😔😔](https://juejin.cn/post/7495699805676470323)
7 | - `点赞量: 44` - [2025前端社招最新面试题汇总- 场景题篇](https://juejin.cn/post/7493912833992589323)
8 | - `点赞量: 34` - [前端面试之页面渲染规则📖](https://juejin.cn/post/7491670661544083456)
9 | - `点赞量: 33` - [面试八股文——vue篇📑](https://juejin.cn/post/7493840743367344168)
10 | - `点赞量: 29` - [vue面试高频考题----computed和watch的区别❓](https://juejin.cn/post/7491493216508772389)
11 | - `点赞量: 29` - [面试场景题:性能的检测](https://juejin.cn/post/7492969116610330675)
12 | - `点赞量: 26` - [【前端面试必杀技】一文吃透前端截图实现原理,让面试官对你刮目相看!](https://juejin.cn/post/7492346703103115304)
13 | - `点赞量: 25` - [前端面试手撕代码(字节)](https://juejin.cn/post/7488235095884464140)
14 | - `点赞量: 24` - [一份没有项目展示的简历,是怎样在面试里输掉的?开源项目或许是你的救命稻草 😭😭😭](https://juejin.cn/post/7488170507294457883)
15 | - `点赞量: 24` - [ 深度前端面试知识体系总结](https://juejin.cn/post/7493721453536968713)
16 | - `点赞量: 22` - [面试常考 | 深入理解 JavaScript 中手写 new 操作符](https://juejin.cn/post/7498307965226303498)
17 | - `点赞量: 18` - [今日面试实录:四年经验前端在Vue3修罗场的求生指南](https://juejin.cn/post/7496047972301733900)
18 | - `点赞量: 17` - [面试官问我useEffect和useLayoutEffect的区别,我掏出了外卖订单…](https://juejin.cn/post/7490506373899894838)
19 | - `点赞量: 15` - [字节前端面试提问:微应用的实现方式有哪些?](https://juejin.cn/post/7491231734974988325)
20 | - `点赞量: 14` - [小厂面试常考算法题整合(一)✍🏻](https://juejin.cn/post/7495604219110981684)
21 | - `点赞量: 14` - [一分钟解决 | 高频面试算法题——最大子数组之和](https://juejin.cn/post/7496003321518948386)
22 | - `点赞量: 14` - [一分钟解决 | 高频面试算法题——最小覆盖子串](https://juejin.cn/post/7495776682138320936)
23 | - `点赞量: 13` - [一分钟解决 | 高频面试算法题——最长连续序列(哈希表)](https://juejin.cn/post/7494187108421943336)
24 | - `点赞量: 13` - [高频面试算法题 | 轮转数组(JavaScript最优解)](https://juejin.cn/post/7496021617349918772)
25 | - `点赞量: 13` - [面试算法题 | 合并区间(Javascript版)](https://juejin.cn/post/7496003321519292450)
26 | - `点赞量: 12` - [一分钟吃透一道面试算法题——字母异位词分组(最优解)](https://juejin.cn/post/7494192861269999656)
27 | - `点赞量: 12` - [ 前端进阶 | 面试必考—— JavaScript手写定时器](https://juejin.cn/post/7495683387437989942)
28 | - `点赞量: 11` - [大厂面试题分享(纯干货)](https://juejin.cn/post/7495672179204882472)
29 | - `点赞量: 10` - [【前端面试必杀技】站点一键换肤的如何实现?](https://juejin.cn/post/7493359957130051593)
30 | - `点赞量: 9` - [面试官又问我为什么要出现pnpm?](https://juejin.cn/post/7492792484659494927)
31 | - `点赞量: 8` - [前端面试知识点总结(一)](https://juejin.cn/post/7488519033957974050)
32 | - `点赞量: 8` - [面试之道(二)](https://juejin.cn/post/7488916399555362842)
33 | - `点赞量: 7` - [面试官:“你说你会计网?那你说说那些网络协议?”](https://juejin.cn/post/7492987953250779174)
34 | - `点赞量: 7` - [JavaScript面试之道](https://juejin.cn/post/7488897639011942440)
35 | - `点赞量: 6` - [面试管问我大文件上传](https://juejin.cn/post/7492077594118668328)
36 | - `点赞量: 6` - [【前端面试必杀技】中级前端简历如何得到面试官青睐(全面指导版)](https://juejin.cn/post/7494584750214168614)
37 | - `点赞量: 5` - [面试看这一篇webpack](https://juejin.cn/post/7488266942898307113)
38 | - `点赞量: 5` - [东田数码科技前端面试](https://juejin.cn/post/7497813937670242343)
39 | - `点赞量: 4` - [前端性能优化面试回答技巧(一)](https://juejin.cn/post/7497507130386464777)
40 | - `点赞量: 4` - [JavaScript优选面试题](https://juejin.cn/post/7496528481850277923)
41 | - `点赞量: 4` - [其实25年前端面试很水的,说一下现在面试强度...](https://juejin.cn/post/7494295779848306723)
42 | - `点赞量: 4` - [九方前端面试](https://juejin.cn/post/7494531085428359222)
43 | - `点赞量: 3` - [一文搞懂HTTP缓存,面试再也不怕了](https://juejin.cn/post/7494943288123736101)
44 | - `点赞量: 3` - [前端最新面试题](https://juejin.cn/post/7494231193862520868)
45 | - `点赞量: 2` - [2025最新前端面试题](https://juejin.cn/post/7495358649565773859)
46 | - `点赞量: 2` - [记一次京东前端面试](https://juejin.cn/post/7489112905175105588)
47 | - `点赞量: 2` - [面试官又问我vite为什么快?](https://juejin.cn/post/7493346464921403427)
48 | - `点赞量: 1` - [2025Web前端八股面试(含答案,万字总结,精心打磨,建议收藏)堪称2025最强](https://juejin.cn/post/7488172786692816907)
49 | - `点赞量: 1` - [2025前端社招最新面试题汇总- vue篇](https://juejin.cn/post/7493964577257619507)
50 | - `点赞量: 1` - [从腾讯面试题事件委托到撩妹](https://juejin.cn/post/7489007995646017563)
51 | - `点赞量: 1` - [前端面试之吊打面试官 JS篇](https://juejin.cn/post/7498634664539668514)
52 | - `点赞量: 0` - [最新初级前端面试题](https://juejin.cn/post/7494246712112234508)
53 |
54 | ### 后端
55 | - `点赞量: 33` - [面试官问我:你写代码会复用公共SQL么?](https://juejin.cn/post/7489358088379187227)
56 | - `点赞量: 12` - [java面试一定会遇到的200个面试题(程序员必备)](https://juejin.cn/post/7491493216509018149)
57 | - `点赞量: 9` - [SQL面试实战,30分钟征服美女面试官](https://juejin.cn/post/7495635442055856137)
58 | - `点赞量: 4` - [阿里最新出品Java面试核心讲(终极版),Github已星标50K!](https://juejin.cn/post/7496346291326746687)
59 | - `点赞量: 3` - [坐标上海,20K的面试难度](https://juejin.cn/post/7492545417932161060)
60 | - `点赞量: 3` - [看看坐标深圳、薪资15k的go开发岗面试强度如何](https://juejin.cn/post/7488596151995842623)
61 | - `点赞量: 3` - [感受一下『迅雷』的面试强度](https://juejin.cn/post/7488251511437885476)
62 | - `点赞量: 3` - [AI面试官来了!成都招聘会用AI筛简历,你敢试试吗?](https://juejin.cn/post/7489975789170491404)
63 | - `点赞量: 2` - [北京七猫,薪资25~35K,瞧瞧面试强度](https://juejin.cn/post/7493063891742687295)
64 | - `点赞量: 0` - [Java面试必问到的10道面试题](https://juejin.cn/post/7488013596522921993)
65 |
66 | ### Android
67 | - `点赞量: 13` - [面试官:说几个同步拿到异步操作结果的方式](https://juejin.cn/post/7495224452331323427)
68 | - `点赞量: 7` - [Android面试笔记-kotlin相关](https://juejin.cn/post/7488927722775216137)
69 | - `点赞量: 6` - [Android大厂面试通关秘籍](https://juejin.cn/post/7496778636482396214)
70 | - `点赞量: 1` - [Android大厂面试秘籍: View 相关面试题深入分析](https://juejin.cn/post/7491899914197680165)
71 | - `点赞量: 1` - [Kotlin 面试知识点](https://juejin.cn/post/7497055064617648178)
72 |
73 | ### 代码人生
74 | - `点赞量: 25` - [面试高频考题之双token机制💻](https://juejin.cn/post/7493052429229211686)
75 | - `点赞量: 0` - [再谈愚蠢的「八股文」面试](https://juejin.cn/post/7488326413519945766)
76 |
77 | ### iOS
78 | - `点赞量: 4` - [iOS面试常见问题OC](https://juejin.cn/post/7490407437074677814)
79 |
80 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2024_12.md:
--------------------------------------------------------------------------------
1 | ### 后端
2 | - `点赞量: 44` - [面试了一个实习生,他说我的问题没问到他的心趴上](https://juejin.cn/post/7443660247174873127)
3 | - `点赞量: 42` - [小红书Java岗,面试难度如何?](https://juejin.cn/post/7449173391444066358)
4 | - `点赞量: 27` - [阿里面试题:MySQL为什么要改进LRU算法?](https://juejin.cn/post/7450768635847917620)
5 | - `点赞量: 27` - [面试高频:Chrome的进程与线程过程](https://juejin.cn/post/7444834021152030770)
6 | - `点赞量: 19` - [快手后端面试,被面试官秒挂了!](https://juejin.cn/post/7451504916642267145)
7 | - `点赞量: 18` - [面试官:Java 的 SPI 都不了解?这很难让你通过啊!](https://juejin.cn/post/7445577072834445324)
8 | - `点赞量: 15` - [面试必考题 —— Promise](https://juejin.cn/post/7443347036974301199)
9 | - `点赞量: 14` - [阿里面试题:什么是BufferPool?](https://juejin.cn/post/7448266692017455143)
10 | - `点赞量: 14` - [面试必学数据结构 - 链表](https://juejin.cn/post/7451462961790730303)
11 | - `点赞量: 13` - [面试官:DNS解析都整不明白,敢说你懂网络?我:嘤嘤嘤!](https://juejin.cn/post/7449271916907167781)
12 | - `点赞量: 10` - [战斗爽!!!对线面试官(面试复盘)](https://juejin.cn/post/7445980506406027301)
13 | - `点赞量: 9` - [翻到了我2016年的面试经历,那是一个互联网的黄金时代。](https://juejin.cn/post/7444861137977540642)
14 | - `点赞量: 5` - [面试手撕代码篇:手写模拟SpringBoot核心流程](https://juejin.cn/post/7444455886154301492)
15 | - `点赞量: 4` - [面试手撕bug:@Transactional失效误区](https://juejin.cn/post/7446265337795166262)
16 | - `点赞量: 4` - [记录我的面试经历--Go开](https://juejin.cn/post/7444454304981827625)
17 | - `点赞量: 3` - [腾讯不愧是大厂,面试太难了](https://juejin.cn/post/7452177801847062580)
18 | - `点赞量: 1` - [豆包MarsCode 青训营宣传大使招募啦,模拟面试、丰厚奖品和宣传大使证书,等你来拿~](https://juejin.cn/post/7446622902801940534)
19 |
20 | ### 前端
21 | - `点赞量: 64` - [Node.js 面试必问的 stream,你能答出多少?](https://juejin.cn/post/7449185434615365682)
22 | - `点赞量: 53` - [LeetCode.50 Pow(x, n) + 面试官想让你干的三件事](https://juejin.cn/post/7443737228400279561)
23 | - `点赞量: 50` - [面试官:不会“不定高”虚拟列表,你在简历上面提他干嘛?](https://juejin.cn/post/7452720059639889920)
24 | - `点赞量: 48` - [面试秘籍:call、bind、apply的区别,面试官为什么总爱问这三位?](https://juejin.cn/post/7446784123396833318)
25 | - `点赞量: 44` - [告别迷茫:手把手教你手写 new 运算符,搞定面试中的硬核问题](https://juejin.cn/post/7447873068976128026)
26 | - `点赞量: 43` - [如果我是前端面试官-思路汇总篇](https://juejin.cn/post/7453774208235077684)
27 | - `点赞量: 39` - [【JavaScript】手撕前端面试题:手写new操作符❗❗❗](https://juejin.cn/post/7448447533070090294)
28 | - `点赞量: 39` - [前端面试高频考点——手写new](https://juejin.cn/post/7447859627940397056)
29 | - `点赞量: 36` - [面试官:你还不会手搓一个懒加载???](https://juejin.cn/post/7443747253606498358)
30 | - `点赞量: 35` - [看两道关于异步的字节面试题...](https://juejin.cn/post/7444386869578956840)
31 | - `点赞量: 35` - [大厂真题!前端面试手写代码——使用 setTimeout 实现 setInterval](https://juejin.cn/post/7445141546108092456)
32 | - `点赞量: 34` - [一条命无伤通关JS面试常考难题:类型转换!!!](https://juejin.cn/post/7449051134852907058)
33 | - `点赞量: 34` - [前端必备!面试必考!程序员必学!](https://juejin.cn/post/7446244833038090290)
34 | - `点赞量: 32` - [算法面试的重要性](https://juejin.cn/post/7443746761845571623)
35 | - `点赞量: 31` - [面试高频手写new](https://juejin.cn/post/7448488763536179212)
36 | - `点赞量: 30` - [面试中,面试官问:“请解释一下JS中的定时器机制“](https://juejin.cn/post/7444467241012232218)
37 | - `点赞量: 30` - [深入解析JavaScript定时器:面试中不可不知的setTimeout与setInterval](https://juejin.cn/post/7444467814298435635)
38 | - `点赞量: 29` - [前端面试:回流与重绘](https://juejin.cn/post/7445237334411837477)
39 | - `点赞量: 27` - [面试官问我x^n , 被我玩坏了 (爽文版) -- 一道华为od算法题从迭代->递归->快速幂 , 秒变快男 !](https://juejin.cn/post/7443806845573791763)
40 | - `点赞量: 25` - [🔥面试提问:“请解释 CSS 页面的渲染规则”🔥](https://juejin.cn/post/7453451639985422373)
41 | - `点赞量: 25` - [一篇文章带你搞懂面试常考点-Promise与事件循环](https://juejin.cn/post/7449006188125093899)
42 | - `点赞量: 25` - [面试官:喜欢react还是vue 我全都要](https://juejin.cn/post/7451153909466480680)
43 | - `点赞量: 24` - [面试经典问题:聊聊js中的深浅拷贝](https://juejin.cn/post/7444383346939052069)
44 | - `点赞量: 22` - [Bilibili经典面试题:EditInPlace就地编辑](https://juejin.cn/post/7443238238082367542)
45 | - `点赞量: 18` - [面试官:三年前端开发不知道小数精度误差,你难道没有过实际的业务开发经验?我:😭](https://juejin.cn/post/7443347036974415887)
46 | - `点赞量: 17` - [用一道面试题带你走进JS中的装箱机制和解构赋值](https://juejin.cn/post/7448507035401257000)
47 | - `点赞量: 17` - [面试八股之手写一个防抖和节流](https://juejin.cn/post/7450697556637548596)
48 | - `点赞量: 17` - [将字符串转换为数组与类数组对象的深度解析:面试中的双重挑战](https://juejin.cn/post/7443724820880211968)
49 | - `点赞量: 16` - [面试中常考的JS中简单类型数据转换❗️](https://juejin.cn/post/7448945963684954150)
50 | - `点赞量: 15` - [爆刷面试详解✊ - 百度一面😰,重视基础🕶](https://juejin.cn/post/7443296179956269092)
51 | - `点赞量: 15` - [面试考题:定时器底层逻辑](https://juejin.cn/post/7444736409069453346)
52 | - `点赞量: 14` - [一次性搞明白面试常问ES6的新特性Symbol](https://juejin.cn/post/7446330268116762676)
53 | - `点赞量: 14` - [面试编程题考什么?](https://juejin.cn/post/7443781052227551242)
54 | - `点赞量: 13` - [面试之es6](https://juejin.cn/post/7447080711457472566)
55 | - `点赞量: 11` - [【vue高频面试题—场景篇】:在vue项目中是如何封装axios的,主要封装了些什么模块 提供了哪些全局功能](https://juejin.cn/post/7451526166832218150)
56 | - `点赞量: 11` - [面试会考的手写new,看完这一篇就够了](https://juejin.cn/post/7451498663501135912)
57 | - `点赞量: 8` - [前端面试题合集 CSS篇---盒模型超详细版!!!](https://juejin.cn/post/7452991328717504563)
58 | - `点赞量: 5` - [一道比亚迪前端面试题:深拷贝和浅拷贝有什么区别?](https://juejin.cn/post/7448955277086490664)
59 | - `点赞量: 5` - [前端:2025 vue3,vue2对比面试题精华?牛](https://juejin.cn/post/7452271497541959706)
60 | - `点赞量: 5` - [前端面试题:算法篇](https://juejin.cn/post/7443063096904744994)
61 | - `点赞量: 4` - [字节面试题:请你谈谈vue的响应式原理(二)](https://juejin.cn/post/7444067625191391284)
62 | - `点赞量: 2` - [一次充满挑战的前端面试](https://juejin.cn/post/7444093399169105956)
63 | - `点赞量: 2` - [前端面试-React](https://juejin.cn/post/7454081143026761738)
64 | - `点赞量: 1` - [前端面试题记录-20241213](https://juejin.cn/post/7447776289434238985)
65 | - `点赞量: 1` - [前端面试题](https://juejin.cn/post/7447712587096686632)
66 | - `点赞量: 1` - [前端面试要求](https://juejin.cn/post/7443660247212048420)
67 | - `点赞量: 1` - [前端面试题总结](https://juejin.cn/post/7443996271155888180)
68 | - `点赞量: 1` - [react面试题](https://juejin.cn/post/7448920534107144255)
69 | - `点赞量: 0` - [前端面试题总结](https://juejin.cn/post/7448846047529287734)
70 |
71 | ### 代码人生
72 | - `点赞量: 49` - [从“码农”到“算法大师”:趣味横生的面试算法备战秘籍!](https://juejin.cn/post/7444142797350649908)
73 | - `点赞量: 46` - [算法面试解密:从易到难的方法体现不同的思想](https://juejin.cn/post/7444089298419728438)
74 | - `点赞量: 45` - [面试题——列表转树的深度解析与实战技巧](https://juejin.cn/post/7448440558270087205)
75 | - `点赞量: 29` - [算法面试:从基础到优化,掌握x的n次方计算](https://juejin.cn/post/7444450769510154266)
76 | - `点赞量: 27` - [33岁在重庆,程序员,在2024年拥有的面试经历](https://juejin.cn/post/7453829306407698482)
77 | - `点赞量: 19` - [算法面试大揭秘:从“求x的n次方”到成为算法魔法师的进阶之路](https://juejin.cn/post/7444109900878184499)
78 | - `点赞量: 15` - [面试官:还能优化吗? 还有其他解法吗?](https://juejin.cn/post/7443736271645311026)
79 |
80 | ### 阅读
81 | - `点赞量: 35` - [面试之:通过计算 x 的 n次幂 探讨高效算法设计的重要性](https://juejin.cn/post/7443736271645179954)
82 | - `点赞量: 31` - [Laymen谈面试算法题入门](https://juejin.cn/post/7443737228398805001)
83 | - `点赞量: 30` - [浅谈在面试题中用JS对二叉树的遍历](https://juejin.cn/post/7446272006972276770)
84 | - `点赞量: 23` - [面试官的算法考验:从“面试造火箭”到“进厂打螺丝”的启示](https://juejin.cn/post/7444005808846782475)
85 |
86 | ### 人工智能
87 | - `点赞量: 26` - [从零开始搭建一个专属于你的面试神器](https://juejin.cn/post/7444383531273781275)
88 |
89 | ### Android
90 | - `点赞量: 2` - [面试题:为什么Compose可以嵌套?](https://juejin.cn/post/7450710706234097714)
91 | - `点赞量: 1` - [面试题 - Android 异步任务和消息机制](https://juejin.cn/post/7454384865523269647)
92 | - `点赞量: 1` - [面试题 - Android IPC机制](https://juejin.cn/post/7452625450423681050)
93 |
94 |
--------------------------------------------------------------------------------
/src/spider/juejin/getRecentQuection.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 掘金面试相关文章爬虫脚本
3 | * 功能:爬取掘金网站上与"面试"相关的热门文章,保存为JSON数据并生成Markdown文档
4 | * 技术栈:Crawlee + Playwright (用于处理JavaScript渲染的页面)
5 | */
6 |
7 | /** 导入所需模块 */
8 | import { Dataset, Log, PlaywrightCrawler } from "crawlee"; /** 从crawlee库导入数据集、日志和Playwright爬虫类 */
9 | import { compact } from "lodash"; /** 从lodash库导入compact函数,用于过滤数组中的空值 */
10 | import path from "path"; /** 导入path模块,用于处理文件路径 */
11 | import fs from "fs"; /** 导入fs模块,用于文件系统操作 */
12 | import day from "dayjs"; /** 导入dayjs模块,用于日期时间处理 */
13 | import type { Page } from "playwright"; /** 导入Playwright的Page类型定义 */
14 | import { handleDataParseMD } from "./utils"; /** 从本地utils模块导入数据解析和Markdown生成函数 */
15 |
16 | /**
17 | * 滚动页面并获取数据的核心函数
18 | * @param {Page} page - Playwright的页面实例
19 | * @param {Log} log - Crawlee日志对象
20 | * @returns {Promise<{done: boolean, data: any[], error?: any}>} - 包含爬取结果的数据对象
21 | */
22 | const scrollAndGetData = async (page: Page, log: Log) => {
23 | /** 存储所有爬取到的数据 */
24 | let allData: any[] = [];
25 | /** 当前滚动次数 */
26 | let scrollCount = 0;
27 | /** 最大滚动次数限制,防止无限滚动 */
28 | const MAX_SCROLL_COUNT = 20;
29 |
30 | try {
31 | /** 获取初始数据 */
32 | log.info("[开始获取初始数据]");
33 | /** 等待搜索API响应 */
34 | const initialResponsePromise = page.waitForResponse(
35 | (response) => response.url().includes("/search_api/v1/search"),
36 | { timeout: 10 * 1000 } /** 10秒超时 */
37 | );
38 | const initialResponse = await initialResponsePromise;
39 | const initialJson = await initialResponse.json();
40 |
41 | /** 解析初始响应数据,提取文章信息和分类 */
42 | const initialData = compact(
43 | initialJson.data?.map?.((item: any) => {
44 | if (item?.result_model?.article_info) {
45 | return {
46 | article_info: item?.result_model?.article_info,
47 | category_name: item?.result_model?.category?.category_name,
48 | };
49 | }
50 | return null;
51 | })
52 | );
53 |
54 | allData = [...allData, ...initialData];
55 | log.info(`[获取初始数据] - ${initialData.length}条`);
56 |
57 | /**
58 | * 递归滚动函数,用于加载更多数据
59 | * @returns {Promise<{done: boolean, data: any[], error?: any}>} - 包含爬取结果的数据对象
60 | */
61 | const scrollItem = async () => {
62 | try {
63 | /** 检查滚动次数是否达到上限 */
64 | scrollCount++;
65 | if (scrollCount > MAX_SCROLL_COUNT) {
66 | log.info(`[达到最大滚动次数] - ${MAX_SCROLL_COUNT}次`);
67 | return { done: true, data: allData };
68 | }
69 | log.info(`[当前滚动次数] - ${scrollCount}/${MAX_SCROLL_COUNT}`);
70 |
71 | /** 滚动到页面底部 */
72 | const currentHeight = await page.evaluate(() => {
73 | window.scrollTo(0, document.body.scrollHeight);
74 | return document.body.scrollHeight;
75 | });
76 |
77 | try {
78 | /** 等待新的搜索API响应 */
79 | const responsePromise = page.waitForResponse((response) => response.url().includes("/search_api/v1/search"), {
80 | timeout: 10 * 1000 /** 10秒超时 */,
81 | });
82 |
83 | const response = await responsePromise;
84 | const json = await response.json();
85 |
86 | /** 解析新响应数据 */
87 | const newData = compact(
88 | json.data?.map?.((item: any) => {
89 | if (item?.result_model?.article_info) {
90 | return {
91 | article_info: item?.result_model?.article_info,
92 | category_name: item?.result_model?.category?.category_name,
93 | };
94 | }
95 | return null;
96 | })
97 | );
98 |
99 | allData = [...allData, ...newData];
100 | log.info(`[获取到新数据] - ${newData.length}条`);
101 |
102 | /** 再次滚动检查页面高度变化 */
103 | const nextHeight = await page.evaluate(() => {
104 | window.scrollTo(0, document.body.scrollHeight);
105 | return document.body.scrollHeight;
106 | });
107 |
108 | log.info(`[当前高度] - ${currentHeight}`);
109 | log.info(`[新高度] - ${nextHeight}`);
110 |
111 | /** 如果高度增加,继续滚动加载更多数据 */
112 | if (nextHeight > currentHeight) {
113 | log.info(`[继续滚动获取下一页]`);
114 | return await scrollItem();
115 | }
116 |
117 | return { done: true, data: allData };
118 | } catch (requestError: any) {
119 | log.error("[请求超时] - 等待响应超过10秒,终止循环");
120 | return { done: true, data: allData, error: requestError };
121 | }
122 | } catch (error: any) {
123 | log.error("[错误] - 爬虫获取数据失败");
124 | return { done: true, data: allData, error };
125 | }
126 | };
127 |
128 | return await scrollItem();
129 | } catch (error: any) {
130 | log.error("[初始数据获取错误]");
131 | return { done: true, data: allData, error };
132 | }
133 | };
134 |
135 | /** 创建Playwright爬虫实例 */
136 | const crawler = new PlaywrightCrawler({
137 | headless: true /** 非无头模式,可见浏览器窗口 */,
138 | requestHandlerTimeoutSecs: 60 * 100 /** 请求处理超时时间 */,
139 | requestHandler: async ({ page, log }) => {
140 | /** 获取所有数据,带重试机制 */
141 | /** 存储所有爬取到的数据 */
142 | let allData: any[] = [];
143 | /** 存储请求过程中出现的错误 */
144 | let error: any = null;
145 | /** 最大重试次数,防止无限重试 */
146 | const maxRetries = 10;
147 | /** 当前重试次数 */
148 | let currentRetry = 0;
149 |
150 | while (currentRetry < maxRetries) {
151 | const result = await scrollAndGetData(page, log);
152 | allData = result.data;
153 | error = result.error;
154 |
155 | if (!error) {
156 | break; /** 请求成功,退出重试循环 */
157 | }
158 |
159 | currentRetry++;
160 | log.warning(`[请求失败] - 将进行第${currentRetry}次重试(共${maxRetries}次)`);
161 |
162 | /** 如果已达到最大重试次数,不再重试 */
163 | if (currentRetry >= maxRetries) {
164 | log.error(`[请求失败] - 已达到最大重试次数${maxRetries}次,无法获取数据`);
165 | break;
166 | }
167 | }
168 |
169 | log.info(`[总共获取数据] - ${allData.length}条`);
170 |
171 | /** 如果最终仍有错误或数据为空,终止程序 */
172 | if (error || allData.length === 0) {
173 | if (error) {
174 | log.error("[错误信息] - scrollAndGetData 请求失败");
175 | } else {
176 | log.error("[错误信息] - 未获取到任何数据");
177 | }
178 | return;
179 | }
180 |
181 | /** 如果没有获取到数据,终止程序 */
182 | if (allData.length === 0) {
183 | log.error("[未获取到任何数据] - 终止程序");
184 | return;
185 | }
186 |
187 | /** 保存数据到数据集 */
188 | await Dataset.pushData(allData);
189 |
190 | /** 打开数据集准备导出 */
191 | const dataset = await Dataset.open("default");
192 |
193 | /** 生成文件名(使用当前日期时间) */
194 | const fileName = day().format("YYYY_MM_DD_HH_mm_ss");
195 |
196 | /** 导出数据到JSON文件 */
197 | await dataset.exportToJSON(fileName);
198 |
199 | log.info(`[yanle] - 开始移动文档`);
200 |
201 | /** 移动文件到指定目录 */
202 | fs.rename(
203 | path.join(process.cwd(), `storage/key_value_stores/default/${fileName}.json`),
204 | path.join(process.cwd(), `temp/juejin_interview/${fileName}.json`),
205 | (err) => {
206 | if (err) {
207 | log.error("移动文件时出错:", err);
208 | } else {
209 | log.info("文件移动成功!");
210 | }
211 | }
212 | );
213 |
214 | log.info(`[yanle] - 写入本地文档`);
215 |
216 | /** 生成markdown文档 */
217 | handleDataParseMD(allData, "2025_06");
218 | },
219 | });
220 |
221 | /** 启动爬虫,爬取掘金面试相关热门文章 */
222 | crawler.run([
223 | "https://juejin.cn/search?query=%E9%9D%A2%E8%AF%95&fromSeo=0&fromHistory=0&fromSuggest=0&sort=2&period=3&type=2&enterFrom=home_page",
224 | ]);
225 |
--------------------------------------------------------------------------------
/src/spider/job_zhipin/test.html:
--------------------------------------------------------------------------------
1 | \n\n\n\n\n
6 |
7 | \n
8 |
9 | \n
10 |
11 | \n
12 |
13 | \n \n
14 |
15 | \n
16 |
17 | \n
18 |
19 | \n
20 | BOSSç´è
21 | \n\n
22 |
57 | \n\n
58 |
61 | \n
62 |
63 | \n
64 |
65 | \n \n
66 |
67 | \n
68 |
77 | \n \n
78 |
101 | \n
102 |
107 | \n
108 |
113 |
118 | \n\n
124 |
125 | \n
126 |
127 | \n
128 |
129 | \n
130 |
131 | \n
\n
\n
132 |
\n
\n
133 |
å è½½ä¸ï¼è¯·ç¨å
134 | \n
135 |
136 | \n
137 |
138 | \n
139 |
140 | \n \n
141 |
142 | \n
143 |
168 | \n
169 |
178 | \n \n
179 |
180 | \n \n
181 |
182 | \n \n
183 |
184 | \n \n
185 |
189 |
193 |
197 |
201 |
202 | \n \n
203 |
204 | \n
205 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2024_10_01.md:
--------------------------------------------------------------------------------
1 | ### 后端,面试
2 |
3 | - [今日一学,5 道 Java 基础面试题(附 Java 面试题及答案整理)](https://juejin.cn/post/7420244722336595979)
4 |
5 | ### 面试
6 |
7 | - [整理程序员面试中 HR 最常问的问题](https://juejin.cn/post/7420237597802840075)
8 | - [两年前端,历时五个月面试终进大厂](https://juejin.cn/post/7419999941940641802)
9 | - [Promise then callback 面试题](https://juejin.cn/post/7419248237734166580)
10 | - [面试中的心态](https://juejin.cn/post/7419228513981415424)
11 | - [轻松应对 HR 面试](https://juejin.cn/post/7418761233157636136)
12 | - [vue 面试-自定义指令](https://juejin.cn/post/7418131622392299555)
13 | - [vue 面试-ref](https://juejin.cn/post/7418065939344474146)
14 | - [近期面试小结,HarmonyOS 鸿蒙面试真题解析火爆全网](https://juejin.cn/post/7417843279419736127)
15 | - [你了解过移动端适配吗?文末领取面试资料,开发面试流程](https://juejin.cn/post/7417843401900654646)
16 | - [完爆面试官!kafka 主题(1),HarmonyOS 鸿蒙网络面试题](https://juejin.cn/post/7417843596760039478)
17 | - [最新 Web 前端面试题精选大全及答案,物联网嵌入式开发内存优化面试](https://juejin.cn/post/7417843702015754303)
18 | - [一次关于 JVM 的面试经历,完整版开放下载\_jvm 面试视频教程,2024 年最新字节跳动前端面试题 2024](https://juejin.cn/post/7417843661465010215)
19 | - [去面 HVV 蓝队面试了\_护网行动蓝队中级面试问题(1),2024 年最新 retrofit 原理面试](https://juejin.cn/post/7417843451687403559)
20 | - [嵌入式面试题,物联网嵌入式开发面试题选择题](https://juejin.cn/post/7417843416841830463)
21 | - [某厂的红队实战靶机面试\_红队面试靶机,HarmonyOS 鸿蒙中高级面试题](https://juejin.cn/post/7417843401900605494)
22 | - [鸿蒙开发 2 年工作经验的面试题\_鸿蒙系开发 app 面试题,2024 年最新 2024 金九银十面试季](https://juejin.cn/post/7417842996178894902)
23 | - [一次哔哩哔哩面试经历,内容太过真实\_bilibili 社招 面试,春招面试视频](https://juejin.cn/post/7417843616478035979)
24 | - [一线互联网大厂面试真题系统收录!面试真题解析,字节面试官说后续 HR 会联系你的](https://juejin.cn/post/7417843596761071670)
25 | - [看完吊打面试官!大厂经典高频面试题体系化集合,最强技术实现\_vxlan 面试题(1)](https://juejin.cn/post/7417843228299788300)
26 | - [看完吊打面试官!大厂经典高频面试题体系化集合,最强技术实现\_vxlan 面试题](https://juejin.cn/post/7417843089044488246)
27 | - [面试需要注意哪些问题?这里有程序员求职面试的 66 个细节整理\_程序员面试的周期性](https://juejin.cn/post/7417843401900458038)
28 | - [字节跳动今日学习内容:靠着这份 190 页的面试资料,社招面试心得,HarmonyOS 鸿蒙面试项目经验](https://juejin.cn/post/7417843697687363647)
29 | - [某厂的红队实战靶机面试\_红队面试靶机(2),2024 年最新面试官说什么暗示你成功](https://juejin.cn/post/7417843408626057235)
30 | - [已获千赞,面试篇,面试相关书籍](https://juejin.cn/post/7417843616478527499)
31 | - [某厂的红队实战靶机面试\_红队面试靶机(1),HarmonyOS 鸿蒙音视频开发面试题](https://juejin.cn/post/7417843408626073619)
32 | - [Node,字节面试题 java](https://juejin.cn/post/7417842157414268947)
33 | - [retrofit 源码,作为一名程序员我不忘初心,面试总结\_retrofit 源码面试](https://juejin.cn/post/7417842541616201782)
34 | - [kotlin 面试题,一次关于 JVM 的面试经历,完整版开放下载,面试 3 轮](https://juejin.cn/post/7417842116506894355)
35 | - [LiveData 面试题库、解答、源码分析\_livedata 面试(1),2024 年最新鸿蒙开发项目面试描述](https://juejin.cn/post/7417842100778188841)
36 | - [LiveData 面试题库、解答、源码分析\_livedata 面试(3),面试类书籍](https://juejin.cn/post/7417842116507140115)
37 | - [带你快速通过字节跳动面试,完整 PDF\_字节跳动面试题,2024 年最新如何在线面试](https://juejin.cn/post/7417842528115245068)
38 | - [LiveData 面试题库、解答、源码分析\_livedata 面试,高级开发面试题及答案](https://juejin.cn/post/7417842195048939539)
39 | - [恶补这份“阿里面试宝典”,秀出天际!\_阿里巴巴面试宝典,鸿蒙面试宝典 2024](https://juejin.cn/post/7417842716196093993)
40 | - [retrofit 源码,作为一名程序员我不忘初心,面试总结\_retrofit 源码面试](https://juejin.cn/post/7417842541616201782)
41 | - [hashmap 遍历,最全面试考点与面试技巧,薪资翻倍,鸿蒙面试项目经验](https://juejin.cn/post/7417842225571086347)
42 | - [面试题小品](https://juejin.cn/post/7417659528336605224)
43 | - [反向面试!3 个必问面试官的问题!](https://juejin.cn/post/7416908856867684390)
44 | - [面试](https://juejin.cn/post/7414732719039987712)
45 |
46 | ### 后端
47 |
48 | - [一道大厂的算法面试题-每日股票价格](https://juejin.cn/post/7419959206273908772)
49 | - [RcoketMQ 面试题](https://juejin.cn/post/7419908145399169051)
50 | - [MySQL 面试题](https://juejin.cn/post/7419907042132951066)
51 | - [C++大厂面试真题宝典 精选 100 道](https://juejin.cn/post/7419907933255581715)
52 | - [Java 基础面试题](https://juejin.cn/post/7419309253259198474)
53 | - [Redis 面试题之大 key 问题](https://juejin.cn/post/7418449922615509001)
54 | - [面试系列-携程暑期实习一面](https://juejin.cn/post/7418342999271342106)
55 | - [RocketMQ 面试题总结\_rocketmq 面试,Golang 自学](https://juejin.cn/post/7417846878257037351)
56 | - [高性能 Kafka 及常见面试题,31 道大数据开发面试题](https://juejin.cn/post/7417847171427680295)
57 | - [师兄面试遇到面试官的 Kafka 暴击三连问,快面哭了!\_kafka 大厂面试题](https://juejin.cn/post/7417847322631864331)
58 | - [Django 必会面试题总结\_django 面试问题,2024 年最新 2024 大厂 Golang 知识点总结+面试题解析](https://juejin.cn/post/7417843767510974527)
59 | - [Java Web 基础面试题\_javaweb 基础面试题 csdn,震撼来袭](https://juejin.cn/post/7417846565631180811)
60 | - [golang—面试题大全\_golang 企业面试题,2024Golang 最新大厂面试真题](https://juejin.cn/post/7417846306976874507)
61 | - [go 面试题——defer 的知识点\_go defer 面试,2024 年最新来一份全面的面试宝典练练手](https://juejin.cn/post/7417846076101918774)
62 | - [Java 基础知识面试题(2024 最新版)\_thinkwon java 面试,2024 年最新【Golang 面试题】](https://juejin.cn/post/7417846461558603812)
63 | - [java 面试系列-JDBC 常见面试题(附答案)\_jdbc 面试题,2024 年你与字节跳动只差这份笔记](https://juejin.cn/post/7417846565631328267)
64 | - [【大数据面试题大全】大数据真实面试题(持续更新),2024 年最新美团大数据开发面试题](https://juejin.cn/post/7417843753647767591)
65 | - [【查找排序相关面试题】,面试必备知识点](https://juejin.cn/post/7417843700041596982)
66 | - [05-RabbitMQ 面试题,2024 年最新大数据开发高级面试题库](https://juejin.cn/post/7417843794328633383)
67 | - [【狂刷面试题】GO 常见面试题汇总\_go 面试题,2024 年最新 2024Golang 大厂面试真题](https://juejin.cn/post/7417843743724912659)
68 | - [【大数据】Kafka 高频面试题(三)\_kafka 高平面试题,大数据开发面试题 2024 高级](https://juejin.cn/post/7417843743724617747)
69 | - [线程面试题总结](https://juejin.cn/post/7415912404653948968)
70 |
71 | ### 前端
72 |
73 | - [面试直接让做题,被 JS 类型转换打败了](https://juejin.cn/post/7419907933256794131)
74 | - [华为面试题 ,前端路由实现原理](https://juejin.cn/post/7419482499599532042)
75 | - [经典面试题,浏览器渲染过程](https://juejin.cn/post/7419524503200661514)
76 | - [字节面试题,v-model 使用](https://juejin.cn/post/7419636298611785766)
77 | - [阿里前端面试题,ES6 继承和 ES5 继承](https://juejin.cn/post/7419532382804820018)
78 | - [前端面试题,显示小于 12px 文字](https://juejin.cn/post/7419532688972464137)
79 | - [面试题准备](https://juejin.cn/post/7418676793077956619)
80 | - [面试题记录](https://juejin.cn/post/7418474013481828387)
81 | - [面试收获](https://juejin.cn/post/7418431143017922579)
82 | - [vue 面试-父子通信](https://juejin.cn/post/7418134213654315008)
83 | - [前端面试题](https://juejin.cn/post/7418133347542777875)
84 | - [面试题总结](https://juejin.cn/post/7417498449174216738)
85 | - [【前端基础面试】](https://juejin.cn/post/7416651336362377255)
86 | - [手撕前端面试代码题,看完吊打面试官](https://juejin.cn/post/7415913002438213686)
87 | - [【面试题】2024-04,05 面试集合,搞钱要紧 【抓紧面试】,腾讯前端面试题](https://juejin.cn/post/7415804644335845417)
88 | - [【面试题】2024-04,05 面试集合,搞钱要紧 【抓紧面试】,腾讯前端面试题](https://juejin.cn/post/7415813486062288930)
89 |
90 | ### Rust,算法
91 |
92 | - [Rust 面试宝典第 10 题:绘制各种图形](https://juejin.cn/post/7419927397392367650)
93 |
94 | ### 后端,MySQL
95 |
96 | - [MySQL 三万字精华总结 + 面试 100 问,和面试官扯皮绰绰有余](https://juejin.cn/post/7419304540200517644)
97 |
98 | ### Android
99 |
100 | - [Android 面试之 APP 启动流程](https://juejin.cn/post/7419222269203136566)
101 |
102 | ### React.js
103 |
104 | - [2024,24 岁,我的面试](https://juejin.cn/post/7419211306816225306)
105 |
106 | ### Rust
107 |
108 | - [Rust 面试宝典第 7 题:单词接龙](https://juejin.cn/post/7419209528263671860)
109 |
110 | ### 前端,JavaScript
111 |
112 | - [前端面试第 67 期 - 2024.09.28 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7419209528263557172)
113 |
114 | ### JavaScript
115 |
116 | - [前端面试](https://juejin.cn/post/7418776909998653503)
117 | - [前端面试题 版本号对比](https://juejin.cn/post/7418391732163575823)
118 | - [前端面试手写题 字符串数组转数组](https://juejin.cn/post/7418397103909027880)
119 | - [前端经典面试题,数组转树](https://juejin.cn/post/7418389059289071668)
120 |
121 | ### 数据分析
122 |
123 | - [大数据技能面试题汇总](https://juejin.cn/post/7418721282063302708)
124 |
125 | ### 前端,面试
126 |
127 | - [一键获取前端面试题宝典题目](https://juejin.cn/post/7418474013482074147)
128 | - [2024 年前端小白面试](https://juejin.cn/post/7417655263417417754)
129 |
130 | ### 创业
131 |
132 | - [分享一点面试材料](https://juejin.cn/post/7418460243502415899)
133 |
134 | ### Java
135 |
136 | - [java 面试题(JVM)](https://juejin.cn/post/7417654149788254258)
137 |
138 | ### 测试
139 |
140 | - [测试实习面试准备](https://juejin.cn/post/7416723051377901604)
141 |
142 | ### 面试,Flutter
143 |
144 | - [Flutter |面试](https://juejin.cn/post/7416267311849603107)
145 |
146 | ### 后端,Redis
147 |
148 | - [Redis 相关面试题](https://juejin.cn/post/7416254630894420007)
149 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_02.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 |
3 | - `点赞量: 163` - [记录一次字节前端面试(2025.2.13)](https://juejin.cn/post/7470742512538648576)
4 | - `点赞量: 66` - [前端面试第 74 期 - 2025.02.11 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7469742809596133376)
5 | - `点赞量: 59` - [面试官的灵魂拷问:position: fixed 的基准参照对象能修改吗?](https://juejin.cn/post/7472019111939620876)
6 | - `点赞量: 57` - [2025 前端高频面试题--CSS 篇](https://juejin.cn/post/7467059176427143202)
7 | - `点赞量: 48` - [前端高级面试题及其答案](https://juejin.cn/post/7468030017604714532)
8 | - `点赞量: 46` - [面试官提问:为什么表单提交不会出现跨域](https://juejin.cn/post/7471150465453899817)
9 | - `点赞量: 41` - [从绝望到极速拿下快手:我的面试复盘与感悟分享](https://juejin.cn/post/7472009911024582719)
10 | - `点赞量: 38` - [面试官:npm install 之后发生了什么 我:什么 ❓](https://juejin.cn/post/7471175427231973391)
11 | - `点赞量: 27` - [蔚来面试题:计算白屏时间](https://juejin.cn/post/7475652009103032358)
12 | - `点赞量: 20` - [春招一血面经分享 来自面试官的心灵拷问](https://juejin.cn/post/7471262197975105587)
13 | - `点赞量: 19` - [(面试题)什么是 HTTP 缓存?(笔记)](https://juejin.cn/post/7472774384241197066)
14 | - `点赞量: 19` - [腾讯面试题:手写 Compose 函数](https://juejin.cn/post/7472664161103118371)
15 | - `点赞量: 18` - [面试高频考点——手写 promise.all](https://juejin.cn/post/7475266130786877477)
16 | - `点赞量: 17` - [面试高频考点——手写 compose](https://juejin.cn/post/7475597817009487884)
17 | - `点赞量: 16` - [面试官:手搓 promise](https://juejin.cn/post/7476142699994939407)
18 | - `点赞量: 14` - [2025 年后前端面试小结](https://juejin.cn/post/7475999357445177354)
19 | - `点赞量: 14` - [(面试)组合函数和白屏时间,笔记](https://juejin.cn/post/7472758458552533055)
20 | - `点赞量: 14` - [经典面试题:数组去重](https://juejin.cn/post/7476063570876252210)
21 | - `点赞量: 12` - [面试难点:深入解析 DNS 域名解析](https://juejin.cn/post/7475652009103015974)
22 | - `点赞量: 10` - [从零到英雄:用 Koa 征服面试官,阮一峰入门教程的 Plus 版!🚀](https://juejin.cn/post/7470635421462954019)
23 | - `点赞量: 9` - [前端面试题:浏览器两个 tab 都是同域,如何在一个 tab 向另一个 tab 发消息](https://juejin.cn/post/7474962750701322277)
24 | - `点赞量: 8` - [面试题之抽象组合函数 🤔🤔](https://juejin.cn/post/7472735368925921290)
25 | - `点赞量: 8` - [ 前端面试必刷:回溯算法解题套路与实战](https://juejin.cn/post/7469214480313630757)
26 | - `点赞量: 7` - [vue 高级面试题](https://juejin.cn/post/7468477933150781476)
27 | - `点赞量: 7` - [2025 年前端面试避坑指南-手把手教你应对大厂毒打](https://juejin.cn/post/7473531450413203507)
28 | - `点赞量: 6` - [前端高级面试题](https://juejin.cn/post/7472298216208531507)
29 | - `点赞量: 6` - [前端面试题](https://juejin.cn/post/7470799482638041125)
30 | - `点赞量: 6` - [21 道关于 Vue3 的面试题及其解析](https://juejin.cn/post/7470848139169398847)
31 | - `点赞量: 6` - [前端面试中的贪心算法:小白也能懂的“最优解”攻略](https://juejin.cn/post/7469051964225847334)
32 | - `点赞量: 6` - [📝 虚拟列表面试复盘:我是如何从被问懵到顺利解题的](https://juejin.cn/post/7472188108366610467)
33 | - `点赞量: 6` - [搞懂面试常考的 watch 和 watchEffect,看这篇文章就够了](https://juejin.cn/post/7474062103994646582)
34 | - `点赞量: 5` - [从面试题说起:深入浅出聊聊 JavaScript 的原型链](https://juejin.cn/post/7473320853107965963)
35 | - `点赞量: 4` - [软 x、中 x、城 x、翼 x、拓 x、华 xxOD2 月鸿蒙面试核心汇总](https://juejin.cn/post/7472210592539951145)
36 | - `点赞量: 3` - [JavaScript 面试题](https://juejin.cn/post/7468744749442629684)
37 | - `点赞量: 3` - [前端面试手写题](https://juejin.cn/post/7467400600985075727)
38 | - `点赞量: 3` - [前端面试中如何自我介绍](https://juejin.cn/post/7475416028312191030)
39 | - `点赞量: 2` - [前端面试手撕代码(拼多多)](https://juejin.cn/post/7475621800783233061)
40 | - `点赞量: 2` - [前端面试核心八股文](https://juejin.cn/post/7474992870417874996)
41 | - `点赞量: 2` - [2025 前端 CSS 高频面试题总结](https://juejin.cn/post/7472291570470879273)
42 | - `点赞量: 2` - [微信小程序面试总结](https://juejin.cn/post/7469634123671781385)
43 | - `点赞量: 2` - [作为一个面试者,如何解构面试官的问题?](https://juejin.cn/post/7468708001337032758)
44 | - `点赞量: 1` - [2025 最新出炉--前端面试题二](https://juejin.cn/post/7473077170761089075)
45 | - `点赞量: 1` - [前端面试题](https://juejin.cn/post/7473349857681932339)
46 | - `点赞量: 1` - [前端面试题](https://juejin.cn/post/7472678890276749338)
47 | - `点赞量: 1` - [年后前端面试,面过上百场面试的真实心态](https://juejin.cn/post/7469604409636536330)
48 | - `点赞量: 1` - [前端性能优化面试题](https://juejin.cn/post/7468874580079673379)
49 | - `点赞量: 1` - [前端综合面试题记录](https://juejin.cn/post/7470680584006189066)
50 | - `点赞量: 1` - [2025 最新面试题来啦!](https://juejin.cn/post/7475350318415544361)
51 | - `点赞量: 1` - [2025 面试大全(13)](https://juejin.cn/post/7469108478927716403)
52 | - `点赞量: 1` - [前端常见算法面试题](https://juejin.cn/post/7468564769029734427)
53 | - `点赞量: 1` - [前端面试笔记 3](https://juejin.cn/post/7467400600985124879)
54 | - `点赞量: 1` - [前端简历面试 怎么准备好简历面试 实际经验](https://juejin.cn/post/7476359034561069071)
55 | - `点赞量: 1` - [前端面试题整理](https://juejin.cn/post/7473721599248875557)
56 | - `点赞量: 1` - [前端面试笔记 1](https://juejin.cn/post/7466643300078927912)
57 | - `点赞量: 0` - [前端高级面试题](https://juejin.cn/post/7471836118110044201)
58 | - `点赞量: 0` - [2025 最新出炉--前端面试题三](https://juejin.cn/post/7474432577904132111)
59 | - `点赞量: 0` - [react 高级面试题](https://juejin.cn/post/7468855489796259876)
60 | - `点赞量: 0` - [2024 前端高频面试题-- JavaScript 篇](https://juejin.cn/post/7470807791092088841)
61 | - `点赞量: 0` - [2025 最新出炉--前端面试题一](https://juejin.cn/post/7472666704893509695)
62 | - `点赞量: 0` - [前端面试题](https://juejin.cn/post/7474124938526343206)
63 | - `点赞量: 0` - [2025 前端面试题](https://juejin.cn/post/7472946325248933922)
64 | - `点赞量: 0` - [刷刷前端面试题](https://juejin.cn/post/7470362662598410279)
65 | - `点赞量: 0` - [前端面试题之 JS 相关](https://juejin.cn/post/7473765132028756009)
66 | - `点赞量: 0` - [前端面试题](https://juejin.cn/post/7473763729047388169)
67 | - `点赞量: 0` - [面试总结之 react 篇](https://juejin.cn/post/7470487664031825961)
68 | - `点赞量: 0` - [全栈面试题](https://juejin.cn/post/7474872585412870154)
69 | - `点赞量: 0` - [React 面试题整理](https://juejin.cn/post/7470784351463030803)
70 | - `点赞量: 0` - [React 面试题整理](https://juejin.cn/post/7470784351463030803)
71 | - `点赞量: 0` - [vue 面试题](https://juejin.cn/post/7468877062825885696)
72 | - `点赞量: 0` - [css 面试题](https://juejin.cn/post/7469686784207274034)
73 |
74 | ### 后端
75 |
76 | - `点赞量: 19` - [(面试题)数组与链表的区别,队列和堆的区别](https://juejin.cn/post/7474156217079529535)
77 | - `点赞量: 10` - [面试被问“你的缺点是什么?”该怎么答?](https://juejin.cn/post/7473331107787554851)
78 | - `点赞量: 10` - [面试官:你项目是如何实现读写分离的?](https://juejin.cn/post/7475384306061213730)
79 | - `点赞量: 9` - [10 个 Redis 高阶面试题](https://juejin.cn/post/7467939423134728201)
80 | - `点赞量: 8` - [【面试必看】一遍文章搞定 Redis 相关面试](https://juejin.cn/post/7475722487733731337)
81 | - `点赞量: 6` - [可以说是一个奇形怪状的面试题:Bean 中的 CHM 要不要加 volatile?](https://juejin.cn/post/7474865421339574298)
82 | - `点赞量: 5` - [Go 框架面试突击!30 道高频题解析](https://juejin.cn/post/7470169970010996762)
83 | - `点赞量: 5` - [面试官:如何解决 Kafka 重复消费、漏消费的问题?](https://juejin.cn/post/7466016946736562213)
84 | - `点赞量: 4` - [掌握自我模拟面试,面试表现提升不止一点点](https://juejin.cn/post/7468892024847286307)
85 | - `点赞量: 4` - [你知道面试官喜欢什么样的自我介绍吗?](https://juejin.cn/post/7468136489390702642)
86 | - `点赞量: 4` - [经典面试之 每天有 1000 万笔订单查询怎么优化](https://juejin.cn/post/7474019962702888998)
87 | - `点赞量: 4` - [面试常考点:竞价系统设计思路+代码演示](https://juejin.cn/post/7476389305879937062)
88 | - `点赞量: 4` - [Java 面试题深度解析:监视器如何实现线程同步?](https://juejin.cn/post/7466381187805757452)
89 | - `点赞量: 4` - [Java 单例模式的面试题目及其答案](https://juejin.cn/post/7467941967725559820)
90 | - `点赞量: 3` - [GO 必知必会面试题汇总](https://juejin.cn/post/7470849622689742886)
91 | - `点赞量: 3` - [初中级 Java 面试指南](https://juejin.cn/post/7476014595720151075)
92 | - `点赞量: 3` - [Java 工厂模式 的面试题目及其答案](https://juejin.cn/post/7468247723189846052)
93 | - `点赞量: 3` - [2025 春招,深度思考 MyBatis 面试题](https://juejin.cn/post/7467570359191388211)
94 | - `点赞量: 3` - [Java 开发面试全解析:15 个问题深度剖析](https://juejin.cn/post/7468144197293490211)
95 | - `点赞量: 3` - [Java 抽象工厂模式的面试题目及其答案](https://juejin.cn/post/7468515399153762315)
96 | - `点赞量: 2` - [后端面试题](https://juejin.cn/post/7470432947927171123)
97 | - `点赞量: 2` - [Java 代理模式的面试题目及其答案](https://juejin.cn/post/7470334881736081420)
98 | - `点赞量: 2` - [MongoDB 面试题答案解析](https://juejin.cn/post/7471103404435603468)
99 | - `点赞量: 1` - [2025 年最全 Java 面试题,及答案汇总!](https://juejin.cn/post/7469581139557531683)
100 | - `点赞量: 1` - [java 面试题](https://juejin.cn/post/7475617896544600079)
101 | - `点赞量: 0` - [mysql 面试题](https://juejin.cn/post/7469052304009052198)
102 |
103 | ### Android
104 |
105 | - `点赞量: 5` - [面试题 - Android - Kotlin 相关内容](https://juejin.cn/post/7473891059221053480)
106 | - `点赞量: 3` - [Android Framework 面试系列(四)Activity 启动原理](https://juejin.cn/post/7476324218142752778)
107 | - `点赞量: 2` - [Android 互联网大厂,高频重点面试题集分享(二)](https://juejin.cn/post/7472400354992799759)
108 | - `点赞量: 2` - [Android Framework 面试系列(一)Zygote](https://juejin.cn/post/7475898493993041983)
109 | - `点赞量: 0` - [Android Kotlin 协程相关面试题分享](https://juejin.cn/post/7469989253792497664)
110 |
111 | ### 阅读
112 |
113 | - `点赞量: 2` - [博客记录-day097-Java 多线程面试题+JVM 面试题+操作系统面试题+MySQL,Redis 面试题](https://juejin.cn/post/7475926895026503715)
114 |
115 | ### 人工智能
116 |
117 | - `点赞量: 157` - [转头发现,为啥“面试文章”几乎都消失了](https://juejin.cn/post/7472305493501788175)
118 |
--------------------------------------------------------------------------------
/temp/juejin_interview/2024_09_01.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 | - `点赞量: 207` - [2024.08.10 更新前端面试问题总结(20道题)](https://juejin.cn/post/7401060368087728166)
3 | - `点赞量: 168` - [字节面试官:虐你如呼吸](https://juejin.cn/post/7410657936715202595)
4 | - `点赞量: 104` - [前端面试第63期 - 2024.08.31 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7409138396793110562)
5 | - `点赞量: 88` - [面试题:一次性渲染十万条数据](https://juejin.cn/post/7407763018471948325)
6 | - `点赞量: 74` - [一次 Nextjs 技术栈公司的面试分享(惨败)](https://juejin.cn/post/7410289323737792539)
7 | - `点赞量: 66` - [2024.08.25 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7406612007389200411)
8 | - `点赞量: 58` - [2024前端高频面试之 Vue篇--初、中级(持续更新30+)](https://juejin.cn/post/7405473135536291874)
9 | - `点赞量: 45` - [当前端面试被问到对K8s的了解](https://juejin.cn/post/7403533830488260648)
10 | - `点赞量: 45` - [面试鸭上线了!程序员在线面试刷题神器](https://juejin.cn/post/7402977951598821385)
11 | - `点赞量: 40` - [前端面试必考题:清除浮动?BFC秒了](https://juejin.cn/post/7400942119081377844)
12 | - `点赞量: 38` - [2024.08.21 更新前端面试问题总结(20道题)](https://juejin.cn/post/7405388594830245924)
13 | - `点赞量: 34` - [前端面试热门:观察者/发布订阅模式](https://juejin.cn/post/7403564345551241251)
14 | - `点赞量: 29` - [阿里子公司面试题都这么底层的吗?](https://juejin.cn/post/7402987272504852532)
15 | - `点赞量: 27` - [常考面试题:场景题系列(一)](https://juejin.cn/post/7408858126043185187)
16 | - `点赞量: 27` - [前端面试篇之常考的CSS(一)](https://juejin.cn/post/7401033107807731746)
17 | - `点赞量: 27` - [前端面试篇之JS数组(一)](https://juejin.cn/post/7402068646167543846)
18 | - `点赞量: 26` - [面试高频题1](https://juejin.cn/post/7402204174065385499)
19 | - `点赞量: 25` - [前端面试篇之常考的CSS(三)](https://juejin.cn/post/7401144423563149364)
20 | - `点赞量: 24` - [前端面试篇之JS字符串(二)](https://juejin.cn/post/7402204642456076338)
21 | - `点赞量: 23` - [面试官:如何减少 options 请求](https://juejin.cn/post/7403185402347159588)
22 | - `点赞量: 22` - [前端常考面试题——css篇](https://juejin.cn/post/7401144423563132980)
23 | - `点赞量: 21` - [前端面试篇之常考的CSS(二)](https://juejin.cn/post/7401112990441979938)
24 | - `点赞量: 20` - [5.JS高级-作用域链面试题和垃圾回收](https://juejin.cn/post/7407715681921826835)
25 | - `点赞量: 20` - [面试常见之手写系列](https://juejin.cn/post/7403289763484532790)
26 | - `点赞量: 20` - [前端面试篇之JS继承(三)](https://juejin.cn/post/7402873035915051058)
27 | - `点赞量: 19` - [面试必备:从输入URL到页面渲染的全过程详解](https://juejin.cn/post/7407635795614597147)
28 | - `点赞量: 18` - [字节面试题:为什么vite更快](https://juejin.cn/post/7411065073563435042)
29 | - `点赞量: 15` - [CSS 的一些面试题: 一些基础的知识](https://juejin.cn/post/7402862738816188457)
30 | - `点赞量: 14` - [字节面试题:webpack的loader和plugin有什么区别?](https://juejin.cn/post/7411046020841259043)
31 | - `点赞量: 13` - [9.JS高级-箭头函数及this面试题](https://juejin.cn/post/7411168550432309267)
32 | - `点赞量: 13` - [😎进阶面试--如何原生JS实现上传下载进度条](https://juejin.cn/post/7404780384540278836)
33 | - `点赞量: 13` - [面经:记录一下我的第一次面试](https://juejin.cn/post/7401060368087498790)
34 | - `点赞量: 12` - [ES6面试题考点(二)--数组新增扩展](https://juejin.cn/post/7410599171122069543)
35 | - `点赞量: 11` - [【前端面试】浏览器:setInterval优化方案](https://juejin.cn/post/7408072039922794548)
36 | - `点赞量: 11` - [一句话回答-近期面试题总结](https://juejin.cn/post/7401011864178622476)
37 | - `点赞量: 9` - [ES6面试题考点(一)--var,let,const](https://juejin.cn/post/7409197804680413218)
38 | - `点赞量: 8` - [面试热门考题:观察者/发布订阅模式](https://juejin.cn/post/7403267077651873832)
39 | - `点赞量: 7` - [你的努力值得被肯定,2024前端面试汇总](https://juejin.cn/post/7410992178899910682)
40 | - `点赞量: 4` - [告别面试焦虑:深入浅出解析前端手写题,助你顺利通关【EP02】(上篇)](https://juejin.cn/post/7402922513888362548)
41 | - `点赞量: 3` - [前端面试手写](https://juejin.cn/post/7406148010046652416)
42 | - `点赞量: 2` - [3个滴滴面试题](https://juejin.cn/post/7407621980574793791)
43 | - `点赞量: 2` - [前端面试题(1)](https://juejin.cn/post/7405876733338976308)
44 | - `点赞量: 2` - [前端面试--手写题](https://juejin.cn/post/7405153599644876838)
45 | - `点赞量: 1` - [关于一道简单的面试编程题我做了一个多小时这件事](https://juejin.cn/post/7410760487812022272)
46 | - `点赞量: 1` - [前端面试题之 如何实现预览 PDF 文件](https://juejin.cn/post/7408182870144466979)
47 | - `点赞量: 1` - [现在前端面试有时候问一些场景题](https://juejin.cn/post/7403192588348456970)
48 | - `点赞量: 1` - [前端项目相关面试题整理](https://juejin.cn/post/7407018346154868772)
49 | - `点赞量: 1` - [2024前端面试题总结](https://juejin.cn/post/7403231657254191155)
50 | - `点赞量: 1` - [自己整理的一份前端面试题库](https://juejin.cn/post/7402458172172419108)
51 | - `点赞量: 1` - [2024前端面试题](https://juejin.cn/post/7411355962585251891)
52 | - `点赞量: 1` - [面试积累-3](https://juejin.cn/post/7403941358757494795)
53 | - `点赞量: 1` - [前端性能优化面试题整理](https://juejin.cn/post/7409681956697784383)
54 | - `点赞量: 0` - [海云前端面试场景题](https://juejin.cn/post/7402435366647939081)
55 | - `点赞量: 0` - [vue面试](https://juejin.cn/post/7407643004491055114)
56 | - `点赞量: 0` - [React面试题](https://juejin.cn/post/7405769445028020250)
57 |
58 | ### 后端
59 | - `点赞量: 82` - [JVM面试真题总结(一)](https://juejin.cn/post/7408844429371555850)
60 | - `点赞量: 28` - [面试场景题:一次关于线程池使用场景的讨论。](https://juejin.cn/post/7404776486707609634)
61 | - `点赞量: 25` - [一篇文章吃透volatile常见面试问题,可见性、JMM、指令重排等。](https://juejin.cn/post/7405158045628432384)
62 | - `点赞量: 15` - [美团面试题:new Integer("127")和Integer.valueOf("128")有什么区别](https://juejin.cn/post/7405158412353585171)
63 | - `点赞量: 8` - [必问!通宵整理的十道经典MySQL必问面试题](https://juejin.cn/post/7408848095615680527)
64 | - `点赞量: 5` - [京东面试:说说CMS工作原理?](https://juejin.cn/post/7400751528343552000)
65 | - `点赞量: 3` - [又遇百度面试,被疯狂拷打](https://juejin.cn/post/7404778998625255463)
66 | - `点赞量: 3` - [作业帮面试,体感拉满,难度适中。](https://juejin.cn/post/7410215505350426636)
67 | - `点赞量: 3` - [5年经验社招后端面试经历分享](https://juejin.cn/post/7408631611041251368)
68 | - `点赞量: 3` - [Redis面试都卷到C语言去了。。。](https://juejin.cn/post/7406269938007654427)
69 | - `点赞量: 2` - [面试官:Leader崩溃Follower不够新怎么办?](https://juejin.cn/post/7407407711878381618)
70 | - `点赞量: 0` - [面试通:在线面试AI助手](https://juejin.cn/post/7402170596690788367)
71 |
72 | ### Android
73 | - `点赞量: 74` - [一些之前遇到过但没答上来的Android面试题](https://juejin.cn/post/7402204610978545673)
74 |
75 | ### 面试
76 | - `点赞量: 52` - [秋招面试:胡总的窗外就是字节](https://juejin.cn/post/7409196648038678569)
77 | - `点赞量: 33` - [两道大厂面试题:数组去重与快速排序](https://juejin.cn/post/7405805603178840099)
78 | - `点赞量: 32` - [面试中的js大盘点](https://juejin.cn/post/7401037851100528677)
79 | - `点赞量: 18` - [记录我秋招提前批的第一场面试。。。。](https://juejin.cn/post/7401408758343565339)
80 | - `点赞量: 17` - [记录第一次面试的过程,无感刷新Token](https://juejin.cn/post/7400683426346795049)
81 | - `点赞量: 16` - [前端为主的总监岗面试技巧](https://juejin.cn/post/7404776086819553306)
82 | - `点赞量: 12` - [小红书面试:如何解析URl?](https://juejin.cn/post/7410336132665409587)
83 | - `点赞量: 12` - [面试必考点:浮动布局和BFC,给你讲的明明白白](https://juejin.cn/post/7401053200948002831)
84 | - `点赞量: 3` - [前端面试题React篇](https://juejin.cn/post/7410710728783888435)
85 | - `点赞量: 2` - [前端面试题Vue篇](https://juejin.cn/post/7410718005221736458)
86 | - `点赞量: 1` - [针对Redis出现的面试题汇总](https://juejin.cn/post/7406347285901344808)
87 | - `点赞量: 1` - [React面试题集锦(自用)](https://juejin.cn/post/7404776086818603034)
88 | - `点赞量: 1` - [2024前端面试笔试真题](https://juejin.cn/post/7408072039922106420)
89 | - `点赞量: 0` - [2024年 Java 面试八股文(20w字)](https://juejin.cn/post/7407635795613466651)
90 | - `点赞量: 0` - [前端面试题(三)](https://juejin.cn/post/7400683426346467369)
91 | - `点赞量: 0` - [Vue面试题集锦](https://juejin.cn/post/7407763018471440421)
92 |
93 | ### CSS
94 | - `点赞量: 21` - [css的一些面试题](https://juejin.cn/post/7404776086819356698)
95 |
96 | ### JavaScript
97 | - `点赞量: 20` - [掌握 JavaScript:面试中的关键考点总结(数组)](https://juejin.cn/post/7401408756222296090)
98 | - `点赞量: 18` - [掌握 JavaScript:面试中的关键考点总结(字符串)](https://juejin.cn/post/7401417746540888073)
99 | - `点赞量: 12` - [掌握 JavaScript:面试中的关键考点总结(类型转换)](https://juejin.cn/post/7402475006737268774)
100 | - `点赞量: 10` - [面试必备知识点:同源策略与跨域解决方案](https://juejin.cn/post/7409848788447215631)
101 | - `点赞量: 9` - [js面试总结(一)](https://juejin.cn/post/7405770868506656783)
102 | - `点赞量: 5` - [我所知道的JavaScript——变量提升(面试强化版)](https://juejin.cn/post/7405260565679603721)
103 |
104 | ### 招聘
105 | - `点赞量: 10` - [百度社招前端(急)直通部门面试](https://juejin.cn/post/7400671870872174626)
106 |
107 | ### Java
108 | - `点赞量: 10` - [Java并发编程面试5:锁机制-Lock、ReentrantLock和ReadWriteLock、ReentrantReadWriteLock](https://juejin.cn/post/7400605682611765286)
109 | - `点赞量: 5` - [Java并发编程面试6:原子变量: AtomicInteger, AtomicLong和AtomicReference](https://juejin.cn/post/7402204086430089266)
110 |
111 | ### HarmonyOS
112 | - `点赞量: 6` - [2024最新鸿蒙开发面试题合集(一)-HarmonyOS NEXT Release(API 12 Release)](https://juejin.cn/post/7406173972739112987)
113 | - `点赞量: 2` - [今天面试,面试官问AskTs里的滚动组件的相关内容!!!可悲,有些许忘了,所以!!!](https://juejin.cn/post/7403186246128091170)
114 |
115 | ### 数据库
116 | - `点赞量: 5` - [面经精选:数据库高频面试十问](https://juejin.cn/post/7401412446940987404)
117 |
118 | ### 程序员
119 | - `点赞量: 4` - [第四份工作(18),那些我羞于分享却助我进步的面试经历(上)](https://juejin.cn/post/7400609489790124071)
120 |
121 | ### Vue.js
122 | - `点赞量: 3` - [Vue3 面试题整理](https://juejin.cn/post/7404748529682415679)
123 |
124 | ### iOS
125 | - `点赞量: 3` - [【2024】iOS面试知识点汇总](https://juejin.cn/post/7406347285900574760)
--------------------------------------------------------------------------------
/temp/juejin_interview/2024_11_02.md:
--------------------------------------------------------------------------------
1 | ### 面试
2 | - `点赞量: 188` - [我发现凡是给offer的公司,面试时基本不问技术细节,那些问得又多又细的公司,后面就没下文了!](https://juejin.cn/post/7419245359946760211) -
3 | - `点赞量: 138` - [2024我的前端面试准备](https://juejin.cn/post/7412504006336004111) -
4 | - `点赞量: 26` - [2024年字节跳动面试-Handler相关](https://juejin.cn/post/7423878914500083749) -
5 | - `点赞量: 10` - [面试考点复盘(一)](https://juejin.cn/post/7426298186791059467) -
6 | - `点赞量: 4` - [web前端场景题面试(二)](https://juejin.cn/post/7426195585899233292) -
7 | - `点赞量: 3` - [坑爹面试官,一个网络连通性,把我干哑火了!](https://juejin.cn/post/7425644342919053350) -
8 | - `点赞量: 2` - [两年前端,历时五个月面试终进大厂](https://juejin.cn/post/7419999941940641802) -
9 | - `点赞量: 2` - [Flutter|面试](https://juejin.cn/post/7416267311849603107) -
10 | - `点赞量: 2` - [前端技术专家面试-React](https://juejin.cn/post/7424001170274435109) -
11 | - `点赞量: 1` - [前端其他面试题集锦](https://juejin.cn/post/7428117756807807026) -
12 | - `点赞量: 0` - [Android经典面试题之组件化原理、优缺点、实现方法?](https://juejin.cn/post/7417227816162508812) -
13 | - `点赞量: 0` - [面试](https://juejin.cn/post/7414732719039987712) -
14 |
15 | ### 前端
16 | - `点赞量: 144` - [一文带你梳理Webpack面试题(2024年版)](https://juejin.cn/post/7414371017253568539) -
17 | - `点赞量: 132` - [面试被问到如何一次性渲染十万条数据,我该怎么答?](https://juejin.cn/post/7420248650607902757) -
18 | - `点赞量: 69` - [摆脱焦虑 💚 前端开发超实用的面试备考分享(内含资料 + 内推)](https://juejin.cn/post/7416902555187036211) -
19 | - `点赞量: 68` - [中年被裁,记录下这段时间的心路历程,内含前端面试题和面经](https://juejin.cn/post/7418085899719344128) -
20 | - `点赞量: 36` - [字节面试题:请你谈谈vue的响应式原理(一)](https://juejin.cn/post/7424903896802033675) -
21 | - `点赞量: 32` - [前端面试第64期 - 2024.09.17 更新前端面试问题总结(21 道题)](https://juejin.cn/post/7414732719040266240) -
22 | - `点赞量: 26` - [前端面试题,显示小于12px文字](https://juejin.cn/post/7419532688972464137) -
23 | - `点赞量: 25` - [前端面试第 70 期 - 2024.10.18 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7426886728059535395) -
24 | - `点赞量: 24` - [常考面试题:场景题系列(二)](https://juejin.cn/post/7411532842478321679) -
25 | - `点赞量: 20` - [这10个vue3的面试题,你会了吗?](https://juejin.cn/post/7425786548061241359) -
26 | - `点赞量: 20` - [带你初识前端面试官必问的promise(详解)](https://juejin.cn/post/7428890591809126426) -
27 | - `点赞量: 19` - [面试考题:我们一起来学习控制并发的实现!!!](https://juejin.cn/post/7412843559005290496) -
28 | - `点赞量: 19` - [面试常客系列之跨域](https://juejin.cn/post/7412831382957211688) -
29 | - `点赞量: 17` - [前端面试第65期 - Vue 专题 - 2024.09.17 更新前端面试问题总结(20道题)](https://juejin.cn/post/7414856908223610895) -
30 | - `点赞量: 17` - [面试场景题:如何一次性渲染十万条数据?](https://juejin.cn/post/7413196978601492507) -
31 | - `点赞量: 17` - [面试题中的大文件上传实现之前端处理](https://juejin.cn/post/7413184816404365350) -
32 | - `点赞量: 17` - [面试题中的大文件上传实现之后端处理](https://juejin.cn/post/7413699779014131739) -
33 | - `点赞量: 16` - [🚀🚀🚀衔远科技第一轮面试,全栈偏前端方向](https://juejin.cn/post/7416499669630468137) -
34 | - `点赞量: 16` - [心心念念的蔚来面试,挂的很不应该.....](https://juejin.cn/post/7411431271208321060) -
35 | - `点赞量: 16` - [面试官最爱问的"this"](https://juejin.cn/post/7423341587520520231) -
36 | - `点赞量: 15` - [前端面试第 68 期 - 2024.10.07 更新前端面试问题总结(21道题)](https://juejin.cn/post/7422848805044371471) -
37 | - `点赞量: 14` - [前端面试第 66 期 - Vue 专题第二篇 - 2024.09.22 更新前端面试问题总结(20道题)](https://juejin.cn/post/7416625240157929524) -
38 | - `点赞量: 14` - [最新出炉25秋招大厂面试题算法(一)](https://juejin.cn/post/7414734288632610855) -
39 | - `点赞量: 12` - [Promise 必考手写面试题还不会?请看这篇](https://juejin.cn/post/7424906244216324132) -
40 | - `点赞量: 12` - [前端面试总爱问的watch,你还没搞懂吗?五种情况带你彻底搞懂!](https://juejin.cn/post/7427399875237003327) -
41 | - `点赞量: 12` - [面试被问到跨域还不会答?来看看这篇文章](https://juejin.cn/post/7418085899719294976) -
42 | - `点赞量: 11` - [前端面试第 69 期 - 2024.10.13 更新前端面试问题总结(20道题)](https://juejin.cn/post/7424904499666452480) -
43 | - `点赞量: 11` - [前端面试第 67 期 - 2024.09.28 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7419209528263557172) -
44 | - `点赞量: 11` - [JavaScript 面试宝典:2024 年必备知识点](https://juejin.cn/post/7425919372282658835) -
45 | - `点赞量: 11` - [面试必备!10分钟搞懂 Webpack Loader 和 Plugin 开发,快速拿下大厂 Offer!](https://juejin.cn/post/7416177196229083151) -
46 | - `点赞量: 11` - [面试场景题手写一个发布订阅,你会吗?](https://juejin.cn/post/7414129923634413579) -
47 | - `点赞量: 10` - [我用 crawlee 抓取了 9 月掘金所有面试相关文章](https://juejin.cn/post/7425626637816954943) -
48 | - `点赞量: 8` - [面试被问状态码,我居然没说上](https://juejin.cn/post/7414295570191597594) -
49 | - `点赞量: 8` - [【前端】读者本人九月实战面试前端题目分享](https://juejin.cn/post/7412819188853489727) -
50 | - `点赞量: 8` - [常考的前端面试题(一)](https://juejin.cn/post/7412702063677489179) -
51 | - `点赞量: 7` - [前端面试第 71 期 - 2024.10.26 更新前端面试问题总结(20道题)](https://juejin.cn/post/7430510700488343603) -
52 | - `点赞量: 6` - [面试官让我手写一个虚拟列表,我只能说一百行搞定~](https://juejin.cn/post/7427703852776472614) -
53 | - `点赞量: 6` - [超详细的flex教程(面试必考)](https://juejin.cn/post/7431805657186942995) -
54 | - `点赞量: 6` - [超详细的flex教程(面试必考)](https://juejin.cn/post/7431805657186942995) -
55 | - `点赞量: 5` - [🚀🚀🚀面试官:你能简单实现一个webpack吗???我...](https://juejin.cn/post/7425834578412716082) -
56 | - `点赞量: 5` - [华为面试官:手写一个观察者模式](https://juejin.cn/post/7424176544668794920) -
57 | - `点赞量: 5` - [web前端场景题面试(三)](https://juejin.cn/post/7426258025482928191) -
58 | - `点赞量: 4` - [不管面试还是开发?你都需要知道的Promise知识点!一文搞懂](https://juejin.cn/post/7413959991584342027) -
59 | - `点赞量: 4` - [前端面试题总结](https://juejin.cn/post/7426352106033152011) -
60 | - `点赞量: 3` - [面试常考的函数柯里化 curry 到底怎么写是最优解](https://juejin.cn/post/7431449989320196137) -
61 | - `点赞量: 3` - [2024前端面试题总结](https://juejin.cn/post/7412665439501598730) -
62 | - `点赞量: 3` - [面试官:你都知道有哪些设计模式?](https://juejin.cn/post/7416382505715712039) -
63 | - `点赞量: 3` - [前端面试题刷(21-30)](https://juejin.cn/post/7416321703171358756) -
64 | - `点赞量: 2` - [面试中常问的 TS 类你都明白了吗❓](https://juejin.cn/post/7422975564456525843) -
65 | - `点赞量: 2` - [面试官:你用过keep-alive嘛](https://juejin.cn/post/7426035420729229322) -
66 | - `点赞量: 2` - [前端面试题——React题](https://juejin.cn/post/7425874213431934976) -
67 | - `点赞量: 1` - [2024-10 面试复盘(第六家)](https://juejin.cn/post/7426341343100731431) -
68 | - `点赞量: 1` - [一些前端面试题](https://juejin.cn/post/7426886728059928611) -
69 | - `点赞量: 1` - [前端面试题之手写代码](https://juejin.cn/post/7411415869149364260) -
70 | - `点赞量: 1` - [参加前端面试前 面试题和项目要怎么背](https://juejin.cn/post/7411532842477797391) -
71 | - `点赞量: 0` - [React 高频面试题](https://juejin.cn/post/7412490227551174683) -
72 |
73 | ### 后端
74 | - `点赞量: 72` - [面试官:你连防抖和节流都不知道??](https://juejin.cn/post/7427584197580488740) -
75 | - `点赞量: 54` - [java多线程编程,面试真的躲不开!](https://juejin.cn/post/7414734248604811300) -
76 | - `点赞量: 33` - [美团后端面试拷打,顶住了!](https://juejin.cn/post/7417037155075407912) -
77 | - `点赞量: 27` - [没有实际的高并发经验,面试如何吹一波牛?](https://juejin.cn/post/7418085899718098944) -
78 | - `点赞量: 10` - [哭晕,腾讯的面试太难了。。。](https://juejin.cn/post/7423058866106744884) -
79 | - `点赞量: 10` - [如何准备技术面试?](https://juejin.cn/post/7414371017252454427) -
80 | - `点赞量: 10` - [可能是最漂亮的Redis面试基础详解](https://juejin.cn/post/7423314983885226022) -
81 | - `点赞量: 9` - [为什么线下面试越来越流行了?](https://juejin.cn/post/7425136905469313050) -
82 | - `点赞量: 7` - [这或许是MySQL基础面试题总结最全的一次](https://juejin.cn/post/7429707940855676991) -
83 | - `点赞量: 5` - [面试官最反感这样的简历!](https://juejin.cn/post/7423753376301170742) -
84 | - `点赞量: 4` - [腾讯秋招面试,人麻了。。。](https://juejin.cn/post/7418397103909421096) -
85 | - `点赞量: 4` - [Redis面试题之大key问题](https://juejin.cn/post/7418449922615509001) -
86 | - `点赞量: 3` - [物联网云平台开发岗位面试经验分享](https://juejin.cn/post/7415725134638415891) -
87 | - `点赞量: 2` - [优秀的面试官!通过一个问题考察了所有网络编程知识点](https://juejin.cn/post/7424191151924281380) -
88 | - `点赞量: 1` - [Java面试之Java的SPI机制](https://juejin.cn/post/7426566685929078822) -
89 |
90 | ### JavaScript
91 | - `点赞量: 19` - [阿里经典面试题:如何用JavaScript实现一个瀑布流?](https://juejin.cn/post/7431591203995222016) -
92 |
93 | ### Java
94 | - `点赞量: 15` - [面试官:谈谈你对 IoC 和 AOP 的理解!](https://juejin.cn/post/7418393389900201984) -
95 | - `点赞量: 2` - [Java中常见面试题及其答案](https://juejin.cn/post/7424901256135458842) -
96 |
97 | ### Vue.js
98 | - `点赞量: 13` - [前端面试总爱问的computed,你还没搞懂吗?](https://juejin.cn/post/7427354018714419211) -
99 |
100 | ### Redis
101 | - `点赞量: 6` - [阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略](https://juejin.cn/post/7416970976667631642) -
102 |
103 | ### React.js
104 | - `点赞量: 3` - [2024,24岁,我的面试](https://juejin.cn/post/7419211306816225306) -
105 |
106 | ### Flutter
107 | - `点赞量: 3` - [Flutter开发者必备面试问题与答案01](https://juejin.cn/post/7430095703357669427) -
108 |
109 | ### MySQL
110 | - `点赞量: 2` - [count(*)、count(1)哪个更快?面试必问:通宵整理的十道经典MySQL必问面试题](https://juejin.cn/post/7426988056636555302) -
111 |
112 | ### GitHub
113 | - `点赞量: 2` - [前端面试套餐:Vue面试题总结+JavaScript前端经典面试题+100道 CSS 面试题](https://juejin.cn/post/7420717697762902016) -
114 | - `点赞量: 1` - [前端面试题 — — vue篇_前端vue面试题,感悟分享](https://juejin.cn/post/7420717683036258338) -
115 |
116 | ### 豆包MarsCode
117 | - `点赞量: 1` - [腾讯前端面试题:来写个五子棋。豆包MarsCode:我写好了。面试官:???](https://juejin.cn/post/7416195448056840201) -
118 |
119 | ### 架构
120 | - `点赞量: 1` - [MySQL 三万字精华总结 + 面试100 问,和面试官扯皮绰绰有余](https://juejin.cn/post/7422575000778195007) -
121 |
122 | ### iOS
123 | - `点赞量: 1` - [iOS 高级面试汇总](https://juejin.cn/post/7428168209712922639) -
--------------------------------------------------------------------------------
/temp/juejin_interview/2024_12_02.md:
--------------------------------------------------------------------------------
1 | ### 面试
2 | - `点赞量: 157` - [面试官:你连防抖和节流都不知道??](https://juejin.cn/post/7427584197580488740)
3 | - `点赞量: 19` - [整理1:面试题【1】](https://juejin.cn/post/7441500692231569447)
4 | - `点赞量: 18` - [面试通关秘籍:从基础到优化,解析编程题目的解答与优化技巧](https://juejin.cn/post/7439253123384279066)
5 | - `点赞量: 12` - [面试考点复盘(一)](https://juejin.cn/post/7426298186791059467)
6 | - `点赞量: 9` - [面试官:请你手写一下防抖节流](https://juejin.cn/post/7436218423715774499)
7 | - `点赞量: 7` - [web前端场景题面试(二)](https://juejin.cn/post/7426195585899233292)
8 | - `点赞量: 6` - [7 年 Java 后端近期面试记录感想](https://juejin.cn/post/7439225776848977947)
9 | - `点赞量: 5` - [面试:MySQL优化--索引、SQL](https://juejin.cn/post/7434400134068224011)
10 | - `点赞量: 4` - [面试深入ES6 新特性:从基础到高级,全面掌握](https://juejin.cn/post/7441611149538164751)
11 | - `点赞量: 4` - [蔚来面试的一道排序](https://juejin.cn/post/7433375007814762532)
12 | - `点赞量: 3` - [Android面试之5个Glide深度面试题](https://juejin.cn/post/7430883054057242643)
13 | - `点赞量: 1` - [Android经典面试题笔记之JVM内存管理剖析](https://juejin.cn/post/7426213075726565414)
14 | - `点赞量: 1` - [字节又一面试神器诞生了](https://juejin.cn/post/7442420706484191259)
15 | - `点赞量: 1` - [前端其他面试题集锦](https://juejin.cn/post/7428117756807807026)
16 | - `点赞量: 1` - [5个Android架构面试题](https://juejin.cn/post/7434561609786458150)
17 | - `点赞量: 1` - [iOS 面试题](https://juejin.cn/post/7437714988149735476)
18 |
19 | ### 前端
20 | - `点赞量: 59` - [大厂面试官爱深挖的作用域底层原理(看完征服面试官)](https://juejin.cn/post/7435280188706242572)
21 | - `点赞量: 55` - [带你初识前端面试官必问的promise(详解)](https://juejin.cn/post/7428890591809126426)
22 | - `点赞量: 48` - [面试官(4):请你讲讲你对“提升”的理解](https://juejin.cn/post/7435851189080588329)
23 | - `点赞量: 46` - [前端面试总爱问的watch,你还没搞懂吗?五种情况带你彻底搞懂!](https://juejin.cn/post/7427399875237003327)
24 | - `点赞量: 39` - [前端面试第 70 期 - 2024.10.18 更新前端面试问题总结(20 道题)](https://juejin.cn/post/7426886728059535395)
25 | - `点赞量: 38` - [闭包是什么?大厂面试必考题](https://juejin.cn/post/7436217936564568090)
26 | - `点赞量: 35` - [面试官:你说你开发过组件库,那你怎么会不知道受控组件?面试就到这里吧。我:😭](https://juejin.cn/post/7435658216656863242)
27 | - `点赞量: 34` - [百度面试题之文档流](https://juejin.cn/post/7438853361082548274)
28 | - `点赞量: 28` - [面试官:你跟我说 setState 是同步的,它不是异步的吗?背错面试题了吧你!我:😭](https://juejin.cn/post/7434716832313589769)
29 | - `点赞量: 25` - [百度面试题之CSS定位](https://juejin.cn/post/7438655509899280411)
30 | - `点赞量: 20` - [10个让你大吃一惊的JavaScript面试题](https://juejin.cn/post/7435854379231477812)
31 | - `点赞量: 18` - [百度面试题之绝对定位(position属性原理)](https://juejin.cn/post/7439701619874971685)
32 | - `点赞量: 18` - [面试怎么回答:JS中的构造函数、原型和实例对象!](https://juejin.cn/post/7441570808500731923)
33 | - `点赞量: 16` - [百度面试题 : 你从这张图片看到什么 ? 只有两个硬汉吗](https://juejin.cn/post/7439646884589551628)
34 | - `点赞量: 15` - [八股文卷出了新高度,这道阿里的连续赋值面试题确实有点东西~](https://juejin.cn/post/7440840299759812617)
35 | - `点赞量: 15` - [一道简单题带你通过面试第一关](https://juejin.cn/post/7439177362648711180)
36 | - `点赞量: 14` - [🚀面试时被问过首屏性能优化吗?我们都能做些啥?](https://juejin.cn/post/7438268954932903975)
37 | - `点赞量: 13` - [前端面试第 71 期 - 2024.10.26 更新前端面试问题总结(20道题)](https://juejin.cn/post/7430510700488343603)
38 | - `点赞量: 13` - [鸿蒙面试题-某迈-2024年11月22日](https://juejin.cn/post/7440468971201691698)
39 | - `点赞量: 13` - [面试题:事件循环、宏任务与微任务](https://juejin.cn/post/7434133942993354752)
40 | - `点赞量: 13` - [百度面试之定位,不得不聊的文档流和position](https://juejin.cn/post/7438849833489039401)
41 | - `点赞量: 12` - [前端面试第 72 期 - 2024.11.07 更新前端面试问题总结(20道题)](https://juejin.cn/post/7434305887462998068)
42 | - `点赞量: 10` - [面试官让我手写一个虚拟列表,我只能说一百行搞定~](https://juejin.cn/post/7427703852776472614)
43 | - `点赞量: 9` - [挑战ChatGPT提供的全网最复杂“事件循环”面试题](https://juejin.cn/post/7441819826274009127)
44 | - `点赞量: 8` - [面试通关指南:前端工程化中的 Webpack、Vite 与 Git 技巧](https://juejin.cn/post/7436410166515449856)
45 | - `点赞量: 8` - [先拿百度的面试题开开胃](https://juejin.cn/post/7437717351448346659)
46 | - `点赞量: 8` - [从基础到进阶:前端面试必会的 JavaScript 手写代码集合](https://juejin.cn/post/7436037034038706176)
47 | - `点赞量: 7` - [web前端场景题面试(一)](https://juejin.cn/post/7426258025482911807)
48 | - `点赞量: 7` - [web前端场景题面试(三)](https://juejin.cn/post/7426258025482928191)
49 | - `点赞量: 6` - [超详细的flex教程(面试必考)](https://juejin.cn/post/7431805657186942995)
50 | - `点赞量: 6` - [VUE的一些面试题及知识点梳理](https://juejin.cn/post/7435586169315164212)
51 | - `点赞量: 5` - [前端面试第 73 期 - 2024.11.23 更新前端面试问题总结(20道题)](https://juejin.cn/post/7440856939348000819)
52 | - `点赞量: 5` - [面试常考的函数柯里化 curry 到底怎么写是最优解](https://juejin.cn/post/7431449989320196137)
53 | - `点赞量: 5` - [B站面试今天考的排序题](https://juejin.cn/post/7433758646775169036)
54 | - `点赞量: 4` - [字节面试题:没有koa的cors你怎么处理跨域?](https://juejin.cn/post/7441974406301401140)
55 | - `点赞量: 4` - [前端面试题汇总:React 篇](https://juejin.cn/post/7439938405917786139)
56 | - `点赞量: 4` - [在求职面试时,如何准备你的 GitHub](https://juejin.cn/post/7433796131858006026)
57 | - `点赞量: 4` - [一周通过前端面试,2024最新前端八股文题库分享](https://juejin.cn/post/7428154082222817306)
58 | - `点赞量: 4` - [前端面试题总结](https://juejin.cn/post/7426352106033152011)
59 | - `点赞量: 4` - [Vue 面试必备:让面试官刮目相看的技能清单](https://juejin.cn/post/7436412441599082531)
60 | - `点赞量: 3` - [2024年前端面试高频题(二)](https://juejin.cn/post/7433288965941919798)
61 | - `点赞量: 3` - [React常见面试题梳理](https://juejin.cn/post/7434868516652597283)
62 | - `点赞量: 3` - [React 面试精粹:这些高频知识点你掌握了吗?](https://juejin.cn/post/7437081152397525042)
63 | - `点赞量: 3` - [JavaScript 面试基础知识(上篇)](https://juejin.cn/post/7435275591515570228)
64 | - `点赞量: 3` - [Flutter求职、面试20+面试官总结:Dart篇](https://juejin.cn/post/7441435383688232994)
65 | - `点赞量: 3` - [前端大厂手写题面试真题,面试通过率90%](https://juejin.cn/post/7435851146979000329)
66 | - `点赞量: 3` - [2024前端面试怎么样,八股文怎么选择](https://juejin.cn/post/7428881929615671333)
67 | - `点赞量: 2` - [2024最新前端面试题](https://juejin.cn/post/7441042910034509839)
68 | - `点赞量: 1` - [[图文并茂] 面试官:说一下Vite依赖预构建的原理](https://juejin.cn/post/7430859505993187355)
69 | - `点赞量: 1` - [2024-10 面试复盘(第六家)](https://juejin.cn/post/7426341343100731431)
70 | - `点赞量: 1` - [一些前端面试题](https://juejin.cn/post/7426886728059928611)
71 | - `点赞量: 1` - [开放性技术面试:面试题](https://juejin.cn/post/7441247125067448361)
72 | - `点赞量: 1` - [前端面试你需要了解的技术面试流程](https://juejin.cn/post/7426352106032857099)
73 | - `点赞量: 1` - [面试准备](https://juejin.cn/post/7437861119798231080)
74 | - `点赞量: 1` - [面试记录](https://juejin.cn/post/7431562650486145076)
75 | - `点赞量: 0` - [Vue3 精选面试题](https://juejin.cn/post/7440334843055439906)
76 |
77 | ### 青训营笔记
78 | - `点赞量: 57` - [大厂面试官超爱问的CSS问题之Flexbox(弹性布局)| 豆包MarsCode AI刷题](https://juejin.cn/post/7434934809249808411)
79 | - `点赞量: 25` - [百度经典面试题:CSS中的position | 豆包MarsCode AI刷题](https://juejin.cn/post/7438913516168511526)
80 |
81 | ### JavaScript
82 | - `点赞量: 55` - [阿里经典面试题:如何用JavaScript实现一个瀑布流?](https://juejin.cn/post/7431591203995222016)
83 | - `点赞量: 18` - [大厂面试官忍不住问的JS底层执行机制](https://juejin.cn/post/7435461326560739355)
84 | - `点赞量: 17` - [轻松应对面试官对于JavaScript数据结构与内存管理的灵魂拷问](https://juejin.cn/post/7440854187937775651)
85 | - `点赞量: 17` - [面试拷问之“JS数据类型”](https://juejin.cn/post/7439785794917007360)
86 | - `点赞量: 15` - [大厂面试时算法的细节](https://juejin.cn/post/7436272415436095540)
87 | - `点赞量: 12` - [一分钟轻松了解大厂面试语法基础题](https://juejin.cn/post/7434023837880270885)
88 | - `点赞量: 5` - [【js面试题】面试官问你new 操作符具体干了什么?你就这样回答](https://juejin.cn/post/7439927036652978188)
89 | - `点赞量: 2` - [2024前端JS面试题总汇](https://juejin.cn/post/7433664281366069260)
90 | - `点赞量: 2` - [react面试宝典](https://juejin.cn/post/7439250654903042088)
91 |
92 | ### Vue.js
93 | - `点赞量: 46` - [前端面试总爱问的computed,你还没搞懂吗?](https://juejin.cn/post/7427354018714419211)
94 | - `点赞量: 2` - [Vue 3 面试进阶挑战:10 连问高难度版](https://juejin.cn/post/7435825844183957567)
95 |
96 | ### 后端
97 | - `点赞量: 26` - [7 年 Java 后端,面试过程踩过的坑,我就不藏着了](https://juejin.cn/post/7440369562858553371)
98 | - `点赞量: 15` - [关于准备面试,分享容易踩的三个坑](https://juejin.cn/post/7439590002508759075)
99 | - `点赞量: 9` - [这或许是MySQL基础面试题总结最全的一次](https://juejin.cn/post/7429707940855676991)
100 | - `点赞量: 4` - [一个连面试官都没听说过的 CRUD 秘诀,吊打一切后端面试官。](https://juejin.cn/post/7437023118151450639)
101 | - `点赞量: 4` - [Java I/O流面试之道](https://juejin.cn/post/7434744226988245030)
102 | - `点赞量: 3` - [面试中高级golang开发工程师岗位,会问到什么?](https://juejin.cn/post/7438436008977088550)
103 | - `点赞量: 1` - [Java面试之Java的SPI机制](https://juejin.cn/post/7426566685929078822)
104 |
105 | ### Flutter
106 | - `点赞量: 20` - [Flutter求职、面试20+面试官总结:Flutter篇](https://juejin.cn/post/7441457433257541667)
107 | - `点赞量: 8` - [Flutter dart 面试总结](https://juejin.cn/post/7433972344219320358)
108 | - `点赞量: 5` - [Flutter开发者必备面试问题与答案01](https://juejin.cn/post/7430095703357669427)
109 | - `点赞量: 1` - [Flutter开发者必备面试问题与答案04](https://juejin.cn/post/7431845673165307954)
110 | - `点赞量: 0` - [Flutter开发者必备面试问题与答案05](https://juejin.cn/post/7433790649398919206)
111 | - `点赞量: 0` - [Flutter 面试题02](https://juejin.cn/post/7434721740976160808)
112 |
113 | ### CSS
114 | - `点赞量: 16` - [百度面试CSS问什么?文档流+定位?](https://juejin.cn/post/7438808773222776842)
115 | - `点赞量: 10` - [面试的时候,不要再说不会unocss了,读完这篇文章你基本就差不多会了。](https://juejin.cn/post/7441761305432686618)
116 |
117 | ### 算法
118 | - `点赞量: 14` - [面试官:可以再优化这道编程题吗](https://juejin.cn/post/7439246649879003199)
119 |
120 | ### 人工智能
121 | - `点赞量: 7` - [马斯克招人策略曝光:9 轮面试,底薪低于同行,只招 “铁杆特斯拉人”](https://juejin.cn/post/7436286873523421238)
122 |
123 | ### MySQL
124 | - `点赞量: 7` - [count(*)、count(1)哪个更快?面试必问:通宵整理的十道经典MySQL必问面试题](https://juejin.cn/post/7426988056636555302)
125 |
126 | ### Android
127 | - `点赞量: 5` - [Android面试:Handler机制全面详解](https://juejin.cn/post/7434790512554475532)
128 |
129 | ### 音视频开发
130 | - `点赞量: 2` - [音视频面试题集锦第 7 期](https://juejin.cn/post/7434085722750648355)
131 |
132 | ### iOS
133 | - `点赞量: 1` - [iOS 高级面试汇总](https://juejin.cn/post/7428168209712922639)
134 |
135 | ### Go
136 | - `点赞量: 1` - [golang高频面试真题](https://juejin.cn/post/7439543263696568359)
--------------------------------------------------------------------------------
/temp/juejin_interview/2025_03.md:
--------------------------------------------------------------------------------
1 | ### 前端
2 | - `点赞量: 249` - [一天三场面试,口干舌燥要晕倒(一)](https://juejin.cn/post/7478504338379620415)
3 | - `点赞量: 112` - [🧑🏻💻前端面试高频考题(万字长文📖)](https://juejin.cn/post/7483709254849445929)
4 | - `点赞量: 79` - [🔥金三银四 500+ 前端面试题全部开源,欢迎 star 和贡献](https://juejin.cn/post/7482024859303378978)
5 | - `点赞量: 67` - [《面试必问:为什么Promise比setTimeout先执行?事件循环的魔鬼细节》](https://juejin.cn/post/7486780447448383523)
6 | - `点赞量: 66` - [关于vue的面试考点总结🤯](https://juejin.cn/post/7481604667590737959)
7 | - `点赞量: 64` - [2025最新Vue面试题:从基础到源码,面试官最爱问的都在这!](https://juejin.cn/post/7477530907542585382)
8 | - `点赞量: 53` - [一天三场面试,口干舌燥要晕倒(二)](https://juejin.cn/post/7479345270699982860)
9 | - `点赞量: 52` - [春招面试万字整理,全程拷打,干货满满(1)](https://juejin.cn/post/7479345270699196428)
10 | - `点赞量: 46` - [前端面试题汇总及深度解析(2025最新版)](https://juejin.cn/post/7478567147221876788)
11 | - `点赞量: 46` - [第一次面试,总结一下吧😀](https://juejin.cn/post/7476410894354464822)
12 | - `点赞量: 37` - [「面试必问!Proxy对比defineProperty的六大核心差异与底层原理」](https://juejin.cn/post/7479452347714928703)
13 | - `点赞量: 36` - [webpack全方位面试大全](https://juejin.cn/post/7481485414861602826)
14 | - `点赞量: 36` - [春招面试万字整理,全程拷打,干货满满(3)](https://juejin.cn/post/7484589584719233063)
15 | - `点赞量: 35` - [面试必看:深入浅出 JavaScript 事件循环与异步编程技巧](https://juejin.cn/post/7484521465200132122)
16 | - `点赞量: 34` - [春招面试万字整理,全程拷打,干货满满(2)](https://juejin.cn/post/7483145055239176226)
17 | - `点赞量: 33` - [面试题大杂烩😘😘](https://juejin.cn/post/7484292626260328489)
18 | - `点赞量: 32` - [面试官直击:防抖与节流,你真的搞懂了吗?😱](https://juejin.cn/post/7480925394184536098)
19 | - `点赞量: 32` - [面试中 Promise 如何处理 event loop 🤩🤩](https://juejin.cn/post/7481909735869546559)
20 | - `点赞量: 31` - [记录一下第一次面试💩](https://juejin.cn/post/7477540557780828214)
21 | - `点赞量: 31` - [面试中常见的手写题汇总](https://juejin.cn/post/7487542928133603391)
22 | - `点赞量: 31` - [春招面试拷打实录(一):揭秘高频难题与应对策略🧐](https://juejin.cn/post/7480841665681162275)
23 | - `点赞量: 30` - [面试官:想把你问趴下 => 面题整理[3] 😮💨初心未变🚀](https://juejin.cn/post/7479227702600990770)
24 | - `点赞量: 28` - [AI 时代如何准备前端面试](https://juejin.cn/post/7484626841592987683)
25 | - `点赞量: 28` - [春招面试拷打实录(二):揭秘高频难题与应对策略🧐](https://juejin.cn/post/7484468071991083035)
26 | - `点赞量: 27` - [面试官😏: 讲一下事件循环 ,顺便做道题🤪](https://juejin.cn/post/7479387138509914124)
27 | - `点赞量: 27` - [前端面试考题合集---js篇✅✅✅](https://juejin.cn/post/7486789190673809471)
28 | - `点赞量: 27` - [面试八股:手写防抖与节流](https://juejin.cn/post/7476408690577621011)
29 | - `点赞量: 26` - [面试中的网络协议](https://juejin.cn/post/7479036294875480100)
30 | - `点赞量: 26` - [春招面试拷打实录(三):面试血泪史,面经干货分享!!!](https://juejin.cn/post/7485936146070470694)
31 | - `点赞量: 26` - [(面试回答手把手教学)你知道哪些数据类型的判断方法?😋](https://juejin.cn/post/7478994020611162127)
32 | - `点赞量: 25` - [面试官:防抖节流都不会吗 ?回去等通知吧😡](https://juejin.cn/post/7480161953954807845)
33 | - `点赞量: 24` - [vue高频面试题🆘--1🎯](https://juejin.cn/post/7479227702601613362)
34 | - `点赞量: 24` - [前端面试常考:字符串反转多种实现方案(reverse,reduce,递归,for of)](https://juejin.cn/post/7477570196665073674)
35 | - `点赞量: 23` - [🧠前端面试高频考题---promise,从五个方面搞定它🛠️ ](https://juejin.cn/post/7482950748927803429)
36 | - `点赞量: 23` - [🌟面试官让我手撕this,结果我当场表演了段"指鹿为马"...](https://juejin.cn/post/7481106110972477492)
37 | - `点赞量: 21` - [迭代器在字节面试中的取巧使用](https://juejin.cn/post/7477143794343018534)
38 | - `点赞量: 20` - [面试官:不同刷新操作方式,对强制缓存和协商缓存的影响](https://juejin.cn/post/7480782489658720282)
39 | - `点赞量: 20` - [2025前端高频面试题之--js篇(一)](https://juejin.cn/post/7485182165978955813)
40 | - `点赞量: 20` - [2025前端高频面试题之--js篇(二)](https://juejin.cn/post/7486322280860319798)
41 | - `点赞量: 19` - [刷刷题30(vue3常规面试题)](https://juejin.cn/post/7480740672536559643)
42 | - `点赞量: 19` - [JavaScript面试必杀技:电话号码格式化从入门到精通](https://juejin.cn/post/7484127823176187938)
43 | - `点赞量: 19` - [一道b站经典面试带你搞懂事件循环机制](https://juejin.cn/post/7479245589928788020)
44 | - `点赞量: 19` - [面试小题:写一个函数实现将输入的数组按指定类型过滤](https://juejin.cn/post/7480794879975833641)
45 | - `点赞量: 18` - [面试必问的八股:如何解决跨域问题](https://juejin.cn/post/7484164591040921636)
46 | - `点赞量: 18` - [面试精讲 - vue3组件之间的通信](https://juejin.cn/post/7479275119238152230)
47 | - `点赞量: 17` - [面试中CSS的常考考点(笔记)](https://juejin.cn/post/7477533760726515752)
48 | - `点赞量: 17` - [面试得知道的编程题 | 系列1:扁平化处理、过滤对象等👍](https://juejin.cn/post/7486363775707676682)
49 | - `点赞量: 17` - [前端计网面试常考点:从Http版本到大文件上传](https://juejin.cn/post/7482327404867256330)
50 | - `点赞量: 16` - [让你快速拿捏大厂面试中关于eventloop执行顺序问题](https://juejin.cn/post/7479227702600745010)
51 | - `点赞量: 16` - [前端面试必备:JS 基础知识点大揭秘](https://juejin.cn/post/7486832959694372899)
52 | - `点赞量: 15` - [面试必看:css 的那些事(上)](https://juejin.cn/post/7478232629936668710)
53 | - `点赞量: 15` - [经典面试题:控制并发](https://juejin.cn/post/7478665093384323098)
54 | - `点赞量: 14` - [应届生必看:8家互联网公司前端校招面试题汇总](https://juejin.cn/post/7482312211622477864)
55 | - `点赞量: 14` - [前端面试第 75 期 - 前端质量问题专题(11 道题)](https://juejin.cn/post/7485629173061173299)
56 | - `点赞量: 14` - [面试题整合——html篇](https://juejin.cn/post/7483349447029391395)
57 | - `点赞量: 14` - [手撕Hash路由:从面试翻车到源码王者之路 🚀](https://juejin.cn/post/7479350849056571444)
58 | - `点赞量: 14` - [面试必看:css 的那些事(下)](https://juejin.cn/post/7478567147221336116)
59 | - `点赞量: 13` - [💯 铜三铁四,我收集整理了这些大厂面试场景题 (一)](https://juejin.cn/post/7482968613865029672)
60 | - `点赞量: 13` - [面试精讲-同源策略](https://juejin.cn/post/7481467343572156443)
61 | - `点赞量: 13` - [面试题知多少?--失败重传](https://juejin.cn/post/7483359516857401396)
62 | - `点赞量: 12` - [React面试题精选:从原理到实践全方位解析](https://juejin.cn/post/7478258747274674186)
63 | - `点赞量: 12` - [前端面试中的浏览器知识总结(一)](https://juejin.cn/post/7485267544780079156)
64 | - `点赞量: 11` - [2025前端面试场景题大全:抛弃八股文,这些“灵魂拷问”才是通关密码](https://juejin.cn/post/7478869678807678987)
65 | - `点赞量: 11` - [前端面试之各大厂真题算法解析](https://juejin.cn/post/7480401080741281818)
66 | - `点赞量: 11` - [面试之:WebSocket协议](https://juejin.cn/post/7478969754158956554)
67 | - `点赞量: 11` - [一文攻克Event Loop难题:让你在面试中脱颖而出的秘密武器](https://juejin.cn/post/7478933510684508197)
68 | - `点赞量: 10` - [this 面试一网打尽](https://juejin.cn/post/7486363775706398730)
69 | - `点赞量: 9` - [LocalStorage、SessionStorage与Cookie面试题?看这一篇就够了!](https://juejin.cn/post/7476755577193300007)
70 | - `点赞量: 9` - [不可忽视的面试技巧:性能优化秘籍](https://juejin.cn/post/7479434217940631589)
71 | - `点赞量: 9` - [常见鸿蒙应用开发面试题](https://juejin.cn/post/7485746992594173952)
72 | - `点赞量: 8` - [面试题之虚拟DOM](https://juejin.cn/post/7481158624623493157)
73 | - `点赞量: 7` - [36道我命由我不由天的JavaScript 基础面试题详解](https://juejin.cn/post/7479995740031664191)
74 | - `点赞量: 7` - [前端工程化面试题大全也许总有你遇到的一题~](https://juejin.cn/post/7480734875723268096)
75 | - `点赞量: 7` - [JavaScript面试宝典](https://juejin.cn/post/7479818027484676146)
76 | - `点赞量: 7` - [面试题之vue组件通信](https://juejin.cn/post/7478182398410489908)
77 | - `点赞量: 6` - [字节面试感悟之路由](https://juejin.cn/post/7479051555149398053)
78 | - `点赞量: 4` - [2025年上海前端面试总结](https://juejin.cn/post/7481476461200408610)
79 | - `点赞量: 4` - [📌面试答不上的问题-HTTP缓存](https://juejin.cn/post/7480524478713167884)
80 | - `点赞量: 3` - [一网打尽!全面解析 Vue 面试题:从小白到大牛的进阶宝典](https://juejin.cn/post/7478228124859432972)
81 | - `点赞量: 3` - [react常规面试题1](https://juejin.cn/post/7487118743086022682)
82 | - `点赞量: 3` - [高级前端篇 —前端自动化测试全攻略(面试逆袭版)](https://juejin.cn/post/7482588815722184739)
83 | - `点赞量: 3` - [web前端优化精选面试题](https://juejin.cn/post/7486873200824369178)
84 | - `点赞量: 3` - [面试官:请你介绍一下BFC](https://juejin.cn/post/7486405211810103350)
85 | - `点赞量: 3` - [前端非技术性场景面试题](https://juejin.cn/post/7478863365017665570)
86 | - `点赞量: 2` - [UniApp 高频面试题](https://juejin.cn/post/7480441780119765055)
87 | - `点赞量: 2` - [前端面试题:vue2和vue3的区别(超详细)](https://juejin.cn/post/7479819361848999999)
88 | - `点赞量: 2` - [鸿蒙面试题一](https://juejin.cn/post/7477604621491601448)
89 | - `点赞量: 2` - [前端面试题](https://juejin.cn/post/7478504338378506303)
90 | - `点赞量: 2` - [vue原理面试题](https://juejin.cn/post/7477530907530182683)
91 | - `点赞量: 1` - [📌 面试答不上的问题 - WebSocket通信](https://juejin.cn/post/7480761334360457228)
92 | - `点赞量: 1` - [react原理面试题](https://juejin.cn/post/7476342714683998259)
93 | - `点赞量: 1` - [Vue3面试知识点](https://juejin.cn/post/7482327669649571849)
94 | - `点赞量: 0` - [刷刷题21(常见面试题)](https://juejin.cn/post/7476410894354923574)
95 | - `点赞量: 0` - [WebSocket详解(常见的 WebSocket 面试题及其解答)](https://juejin.cn/post/7479774712006443020)
96 | - `点赞量: 0` - [刷刷题47(react常规面试题2)](https://juejin.cn/post/7487787377924046874)
97 | - `点赞量: 0` - [【前端面试】2025热门面试题 ](https://juejin.cn/post/7478130871448895523)
98 | - `点赞量: 0` - [面试题-前端如何实现截图?](https://juejin.cn/post/7478979149374210098)
99 | - `点赞量: 0` - [前端面试手撕代码(4399二面)](https://juejin.cn/post/7483705110460170291)
100 | - `点赞量: 0` - [2025前端面试及答案](https://juejin.cn/post/7480782489658540058)
101 | - `点赞量: 0` - [前端面试笔试题](https://juejin.cn/post/7485276123255324706)
102 | - `点赞量: 0` - [面试汇总](https://juejin.cn/post/7482984370468945960)
103 | - `点赞量: 0` - [vue3.0面试题](https://juejin.cn/post/7485571704959451174)
104 |
105 | ### 后端
106 | - `点赞量: 40` - [程序员面试要怎么描述项目经历?](https://juejin.cn/post/7477921837684195364)
107 | - `点赞量: 40` - [Java 高级面试题:Lock 到底比 synchronized 强在哪?](https://juejin.cn/post/7479625267028344859)
108 | - `点赞量: 37` - [面试问题分析:为什么Java能实现反射机制,其他语言不行?](https://juejin.cn/post/7483709254848823337)
109 | - `点赞量: 20` - [java面试一定会遇到的100个面试题](https://juejin.cn/post/7481261964306481193)
110 | - `点赞量: 17` - [面试复盘:Java为什么有这么多“O”?——从请求链路看清楚](https://juejin.cn/post/7486659696062267442)
111 | - `点赞量: 11` - [ 面试官问我怎么做分库分表?这是一份全面的实战解答](https://juejin.cn/post/7485200685782057000)
112 | - `点赞量: 7` - [来看看现在go开发岗10k的面试强度](https://juejin.cn/post/7485647396866293779)
113 | - `点赞量: 6` - [面试官:“volatile 你用过吗?” 我一紧张,说错了!](https://juejin.cn/post/7478199362243379250)
114 | - `点赞量: 4` - [三五年前面试java都问的是什么问题](https://juejin.cn/post/7482801903589589033)
115 | - `点赞量: 4` - [java面试一定会遇到的300个面试题(程序员必备)](https://juejin.cn/post/7483449728394264588)
116 | - `点赞量: 3` - [社招 Java 中厂面试记录,难度有点大!](https://juejin.cn/post/7486842883061923878)
117 | - `点赞量: 3` - [【面试篇】五 万字详解 HashMap 的底层原理,吊打面试官](https://juejin.cn/post/7478216994492760105)
118 | - `点赞量: 3` - [腾讯三轮面试面经分享](https://juejin.cn/post/7480430771573899276)
119 | - `点赞量: 2` - [字节一面,面试官说自我介绍的时间太长了。。](https://juejin.cn/post/7482949461564833803)
120 | - `点赞量: 1` - [Java并发编程入门与高并发面试(完结)](https://juejin.cn/post/7478544395294785574)
121 |
122 | ### Android
123 | - `点赞量: 28` - [金三银四,面试真经应该准备什么,可能适用绝大部分人](https://juejin.cn/post/7480464724096057381)
124 | - `点赞量: 12` - [超详细!Android 面试题大汇总与深度解析](https://juejin.cn/post/7486685739498815514)
125 | - `点赞量: 9` - [Android 面试知识点](https://juejin.cn/post/7479051555149348901)
126 | - `点赞量: 2` - [Android Framework 面试系列(五)Window](https://juejin.cn/post/7476850354795118629)
127 | - `点赞量: 1` - [Flutter最新经典面试题(含答案)](https://juejin.cn/post/7485964427621335049)
128 | - `点赞量: 1` - [ Android面试超级攻略,全面攻破技术疑难及面试痛点(完结)](https://juejin.cn/post/7486702437475319862)
129 |
130 | ### 代码人生
131 | - `点赞量: 6` - [记一个让我懵圈的面试题 → 不用额外的变量,如何交换两个变量的值](https://juejin.cn/post/7477005348169023499)
132 |
133 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "ts-node": {
3 | "transpileOnly": true,
4 | "require": [
5 | "tsconfig-paths/register"
6 | ],
7 | },
8 | "compilerOptions": {
9 | /* Visit https://aka.ms/tsconfig to read more about this file */
10 | /* Projects */
11 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
12 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
13 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
14 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
15 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
16 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
17 | /* Language and Environment */
18 | "target": "es2016",
19 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
20 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
21 | // "jsx": "preserve", /* Specify what JSX code is generated. */
22 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
23 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
24 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
25 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
26 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
27 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
28 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
29 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
30 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
31 | /* Modules */
32 | "module": "commonjs",
33 | /* Specify what module code is generated. */
34 | // "rootDir": "./", /* Specify the root folder within your source files. */
35 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
36 | "baseUrl": "./",
37 | /* Specify the base directory to resolve non-relative module names. */
38 | "paths": {
39 | "@utils/*": [
40 | "utils/*"
41 | ],
42 | "@src/*": [
43 | "src/*"
44 | ]
45 | },
46 | /* Specify a set of entries that re-map imports to additional lookup locations. */
47 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
48 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
49 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
50 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
51 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
52 | "resolveJsonModule": true,
53 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
54 | /* JavaScript Support */
55 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
56 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
57 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
58 | /* Emit */
59 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
60 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
61 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
62 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
63 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
64 | // "outDir": "./", /* Specify an output folder for all emitted files. */
65 | // "removeComments": true, /* Disable emitting comments. */
66 | // "noEmit": true, /* Disable emitting files from a compilation. */
67 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
68 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
69 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
70 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
71 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
72 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
73 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
74 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
75 | // "newLine": "crlf", /* Set the newline character for emitting files. */
76 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
77 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
78 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
79 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
80 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
81 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
82 | /* Interop Constraints */
83 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
84 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
85 | "esModuleInterop": true,
86 | /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
87 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
88 | "forceConsistentCasingInFileNames": true,
89 | /* Ensure that casing is correct in imports. */
90 | /* Type Checking */
91 | "strict": true,
92 | /* Enable all strict type-checking options. */
93 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
94 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
95 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
96 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
97 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
98 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
99 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
100 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
101 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
102 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
103 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
104 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
105 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
106 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
107 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
108 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
109 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
110 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
111 | /* Completeness */
112 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
113 | "skipLibCheck": true
114 | /* Skip type checking all .d.ts files. */
115 | },
116 | }
--------------------------------------------------------------------------------
/books/2023年/2023-03-28 更新.md:
--------------------------------------------------------------------------------
1 | > 2023.03.27 - 2023.03.28 更新前端面试问题总结(14道题)
2 | > 获取更多面试问题可以访问
3 | > github 地址: https://github.com/pro-collection/interview-question/issues
4 | > gitee 地址: https://gitee.com/yanleweb/interview-question/issues
5 |
6 |
7 |
8 | 目录:
9 | - 初级开发者相关问题【共计 1 道题】
10 | - 224.对象取值中 a.b.c.d 和 a['b']['c']['d'] 有何区别?【JavaScript】【出题公司: 腾讯】
11 |
12 |
13 | - 中级开发者相关问题【共计 9 道题】
14 | - 103.箭头函数和普通函数的区别?【JavaScript】
15 | - 173.为什么小程序里拿不到dom相关的api【web框架】
16 | - 215.[Vue] 双向绑定和单向数据流原则是否冲突?【web框架】
17 | - 216.实现 (5).add(3).minus(2) 功能【JavaScript】【出题公司: 百度】
18 | - 217.[Vue] 响应式原理中 Object.defineProperty 有什么缺陷【web框架】【出题公司: 腾讯】
19 | - 218.对象引用类问题:以下代码的执行结果是什么,并解释原因【JavaScript】【出题公司: 百度】
20 | - 220.`opacity: 0`、`visibility: hidden`、`display: none` 有啥区别, 主要使用场景是啥子?【CSS】
21 | - 221.箭头函数为何不能作为构造函数使用?【JavaScript】【出题公司: 腾讯】
22 | - 222.给定两个数组,写一个方法来计算它们的交集?【JavaScript】【出题公司: 腾讯】
23 |
24 |
25 | - 高级开发者相关问题【共计 4 道题】
26 | - 69.前端如何实现即时通讯?【网络】
27 | - 206.浏览器缓存中 Memory Cache 和 Disk Cache, 有啥区别?【网络】【出题公司: 字节跳动】
28 | - 223.介绍下如何实现 token 加密?【网络】
29 | - 225.ES6 代码转成 ES5 代码的实现思路是什么?【JavaScript】【出题公司: 阿里巴巴】
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | # 初级开发者相关问题【共计 1 道题】
39 |
40 | ## 224.对象取值中 a.b.c.d 和 a['b']['c']['d'] 有何区别?【JavaScript】【出题公司: 腾讯】
41 |
42 | ### 使用区别
43 |
44 | 在 JavaScript 中,对象的取值可以使用两种方式,即使用点号(.)和使用方括号(\[\])。对于对象的多层嵌套属性,可以使用两种方式分别取值,例如:
45 |
46 | ```css
47 | var obj = {a: {b: {c: {d: 123}}}};
48 | var d1 = obj.a.b.c.d;
49 | var d2 = obj['a']['b']['c']['d'];
50 | ```
51 |
52 | 这两种方式获取的结果是相同的,都是 123。其中,使用点号取值的方式称为“点操作符”,使用方括号取值的方式称为“方括号操作符”。
53 |
54 | 两种方式的区别在于:
55 |
56 | 1. 点操作符必须使用标识符作为属性名,而方括号操作符可以使用任何字符串作为属性名。
57 | 2. 点操作符在代码书写上更加简洁直观,而方括号操作符可以动态地构造属性名。
58 |
59 | 因此,在使用时应根据具体的情况选择合适的方式。例如,如果属性名是固定的,建议使用点操作符;如果属性名需要根据变量或其他动态条件构造,则需要使用方括号操作符。
60 |
61 | ### 性能区别
62 |
63 | 在对象属性的取值操作中,使用点号`.`和中括号`[]`两种方式都能取到相应的属性值,它们在性能上也有些许的差别。
64 |
65 | 一般情况下,使用点号`.`来获取属性的性能要高于中括号`[]`,因为在解析的过程中使用点号`.`可以直接根据属性名获取到对应的属性值,而中括号`[]`需要先进行解析里面的属性名,然后再去查找相应的属性值,因此多了一个解析的过程。
66 |
67 | 但是在以下两种情况下,只能使用中括号`[]`来获取属性值:
68 |
69 | 1. 属性名包含特殊字符或者是关键字,比如 a\['class'\]。
70 | 2. 属性名是动态生成的,比如 a\[`${name}`\]。
71 |
72 | 在这两种情况下,使用点号`.`将会出现语法错误,只能使用中括号`[]`来获取属性值。
73 |
74 |
75 |
76 |
77 | # 中级开发者相关问题【共计 9 道题】
78 |
79 | ## 103.箭头函数和普通函数的区别?【JavaScript】
80 |
81 | 箭头函数和普通函数是 JavaScript 中两种不同的函数定义方式,它们有以下的区别:
82 |
83 | - **语法不同**:箭头函数使用箭头 => 来定义函数,而普通函数使用 function 关键字来定义函数。
84 |
85 | - **箭头函数没有自己的 this**,它会继承其所在作用域的 this 值。而普通函数的 this 则由函数调用时的上下文所决定,可以通过 call、apply、bind 方法来改变。
86 |
87 | - **箭头函数没有自己的 arguments 对象**,它可以通过 rest 参数语法来接收不定数量的参数。而普通函数则有自己的 arguments 对象,它可以接收任意数量的参数。
88 |
89 | - **箭头函数不能作为构造函数使用**,不能使用 new 来实例化,因为它没有自己的 this,而普通函数可以用 new 来创建新的对象。
90 |
91 | - **箭头函数不能使用 yield 关键字**来定义生成器函数,而普通函数可以。
92 |
93 | - **箭头函数不支持call()/apply()函数特性**
94 |
95 | - **箭头函数没有prototype属性**
96 |
97 | - **原型函数不能定义成箭头函数**
98 | 比如下面这个例子:
99 | ```js
100 | function Person(name){
101 | this.name = name
102 | }
103 |
104 | // 原型函数使用箭头函数,其中的this指向全局对象,而不会指向构造函数
105 | // 因此访问不到构造函数本身,也就访问不到实例属性
106 | Person.prototype.say = ()=>{console.log(this.name)}
107 | ```
108 |
109 |
110 |
111 |
112 |
113 | ## 173.为什么小程序里拿不到dom相关的api【web框架】
114 |
115 | 小程序为了追求更高的性能和更好的安全性,采用了类Webview的渲染方案,并使用了自己的渲染引擎,与浏览器的渲染引擎不同。因此,小程序的API和浏览器的API并不完全相同。
116 |
117 | 在小程序中,开发者可以使用WXML语言构建页面,WXML是一种类似HTML的标记语言,但并不是真正的HTML。小程序中的组件是由开发者提前定义好的,而不是由开发者在运行时动态生成的,因此在小程序中无法直接访问和操作DOM。相反,开发者需要使用小程序提供的API来操作组件。
118 |
119 | 同时,小程序为了保证安全性,也限制了一些操作,如不允许使用eval函数和Function构造函数等动态生成代码的方式。
120 |
121 |
122 | ## 215.[Vue] 双向绑定和单向数据流原则是否冲突?【web框架】
123 |
124 | Vue 的双向绑定和单向数据流原则不冲突,因为它们是针对不同的场景和目的而提出的。
125 |
126 | Vue 的双向绑定是指,在模板中通过 `v-model` 指令可以实现表单元素和组件数据之间的双向绑定,当表单元素的值发生变化时,组件数据也会同步更新;反过来,当组件数据发生变化时,表单元素的值也会同步更新。这种双向绑定的机制可以减少手动编写事件监听器的工作量,提高代码的可读性和可维护性。
127 |
128 | 而单向数据流原则是指,在 Vue 应用中,数据的流动是单向的,即自上而下单向流动。父组件通过 props 把数据传递给子组件,子组件通过 $emit 事件把数据传递给父组件或者其他祖先组件。这种单向数据流的机制使得数据的变化更加可控和可预测,方便进行状态管理和调试。
129 |
130 | 双向绑定和单向数据流原则虽然在实现机制上有所不同,但它们都是为了解决不同的问题和提高代码的可维护性和可读性。在实际开发中,可以根据实际情况选择合适的机制来使用。
131 |
132 |
133 | ## 216.实现 (5).add(3).minus(2) 功能【JavaScript】【出题公司: 百度】
134 |
135 | 可以通过在 Number 原型上定义 add 和 minus 方法来实现该功能,代码如下:
136 |
137 | ```javascript
138 | Number.prototype.add = function(num) {
139 | return this + num;
140 | };
141 |
142 | Number.prototype.minus = function(num) {
143 | return this - num;
144 | };
145 |
146 | console.log((5).add(3).minus(2)); // 输出6
147 | ```
148 |
149 | 上述代码中,通过在 Number.prototype 上定义 add 和 minus 方法,实现了将数字类型的值转换为 Number 对象,并且可以链式调用这两个方法。最终返回的结果是一个数值类型的值。
150 |
151 |
152 | ## 217.[Vue] 响应式原理中 Object.defineProperty 有什么缺陷【web框架】【出题公司: 腾讯】
153 |
154 | Vue 的响应式原理中使用了 `Object.defineProperty` 方法来劫持对象的属性,从而实现数据变化时自动更新视图。但是这种方式也存在一些缺陷:
155 |
156 | 1. 对象新增属性和删除属性时无法监听:由于 `Object.defineProperty` 方法需要在对象初始化时就定义属性,因此对于后续新增和删除的属性是无法进行监听的。需要使用 Vue 提供的 `$set` 和 `$delete` 方法来进行操作。
157 |
158 | 2. 对象属性为数组时需要额外处理:对于数组,虽然可以通过 `Object.defineProperty` 来监听数组元素的变化,但是无法监听数组的 push、pop、shift、unshift 等方法的调用。Vue 中使用了重写数组原型的方式来实现这一功能。
159 |
160 | 3. 性能问题:由于 `Object.defineProperty` 每次只能劫持一个属性,因此当对象属性较多时,会带来一定的性能问题。Vue 中使用了异步更新和缓存 watcher 的方式来优化性能。
161 |
162 | 综上所述,虽然 `Object.defineProperty` 在 Vue 的响应式原理中得到了广泛的应用,但是其也存在一些缺陷。为了解决这些问题,Vue 在其内部实现中进行了一些额外的处理和优化。
163 |
164 |
165 | ## 218.对象引用类问题:以下代码的执行结果是什么,并解释原因【JavaScript】【出题公司: 百度】
166 |
167 | ### 代码如下, 请问执行结果
168 | ```js
169 | var a = {n: 1};
170 | var b = a;
171 | a.x = a = {n: 2};
172 |
173 | console.log(a.x)
174 | console.log(b.x)
175 | ```
176 |
177 | ### 执行结果和原因
178 |
179 | 结果是 `undefined` 和 `{n: 2}`。
180 |
181 | 这段代码可以分解为以下步骤:
182 |
183 | 1. 创建一个对象 `a`,属性 `n` 的值为 `1`。
184 | 2. 将变量 `b` 指向 `a`,`b` 现在也引用了这个对象。
185 | 3. 执行赋值语句 `a.x = a = {n: 2}`,其中 `a.x` 引用的是对象 `a` 的 `x` 属性,但是此时 `a` 的值被重新赋值为一个新的对象 `{n: 2}`。
186 | 4. 所以现在 `a` 引用的是 `{n: 2}`,而 `b` 仍然引用原始的对象 `{n: 1}`,且其 `x` 属性被赋值为 `{n: 2}`。
187 | 5. 所以 `console.log(a.x)` 结果为 `undefined`,因为 `a` 引用的对象没有 `x` 属性;而 `console.log(b.x)` 结果为 `{n: 2}`,因为 `b` 引用的对象的 `x` 属性被赋值为 `{n: 2}`。
188 |
189 |
190 |
191 | ## 220.`opacity: 0`、`visibility: hidden`、`display: none` 有啥区别, 主要使用场景是啥子?【CSS】
192 |
193 | `opacity: 0`、`visibility: hidden`、`display: none` 都可以使元素不可见,但它们之间有一些区别。
194 |
195 | * `opacity: 0`:设置元素透明度为0,元素依然占据原来的空间,并且可以接收到鼠标事件。通常用于实现淡出效果。
196 | * `visibility: hidden`:元素不可见,但是仍然占据原来的空间,并且可以接收到鼠标事件。常用于实现菜单的展开和收起。
197 | * `display: none`:元素不可见,且不占据空间,也不接收鼠标事件。通常用于实现元素的隐藏和显示。
198 |
199 | 因为这三种属性的区别,它们在使用场景上也有所不同:
200 |
201 | * `opacity: 0`:适用于需要实现淡出效果的场景,比如弹出层的显示和隐藏。
202 | * `visibility: hidden`:适用于需要占据原来空间的元素,但不需要显示的场景,比如菜单的展开和收起。
203 | * `display: none`:适用于需要完全隐藏元素的场景,比如实现一个开关,点击开关后可以隐藏或者显示某个元素。
204 |
205 |
206 | ## 221.箭头函数为何不能作为构造函数使用?【JavaScript】【出题公司: 腾讯】
207 |
208 | 在箭头函数中,`this`指向的是定义时所在的对象,而不是使用时所在的对象。换句话说,**箭头函数没有自己的this,而是继承父作用域中的this**。
209 |
210 | 看个例子:
211 |
212 | ```javascript
213 | var person = {
214 | name:'张三',
215 | age:18,
216 | getName:function(){
217 | console.log('我的名字是:'+this.name)
218 | },
219 | getAge:()=>{
220 | console.log('我的年龄是:'+this.age)
221 | }
222 | }
223 |
224 | person.getName() // 我的名字是张三
225 | person.getAge() // 我的年龄是undefined
226 |
227 | ```
228 |
229 | `person.getName()`中`this`指向函数的调用者,也就是`person`实例,因此`this.name = "张三"`。
230 |
231 | `getAge()`通过箭头函数定义,而箭头函数是没有自己的`this`,会继承父作用域的`this`,因此`person.getAge()`执行时,此时的作用域指向`window`,而`window`没有定义`age`属性,所有报`undefined`。
232 |
233 | 从例子可以得出:**对象中定义的函数使用箭头函数是不合适的**。
234 |
235 |
236 | **先解答下标题问题,为啥箭头函数不能作为构造函数?**
237 |
238 | ```javascript
239 | // 构造函数生成实例的过程
240 | function Person(name,age){
241 | this.name = name
242 | this.age = age
243 | }
244 | var p = new Person('张三',18)
245 |
246 | //new关键字生成实例过程如下
247 | // 1. 创建空对象p
248 | var p = {}
249 | // 2. 将空对象p的原型链指向构造器Person的原型
250 | p.__proto__ = Person.prototype
251 | // 3. 将Person()函数中的this指向p
252 | // 若此处Person为箭头函数,而没有自己的this,call()函数无法改变箭头函数的指向,也就无法指向p。
253 | Person.call(p)
254 |
255 | ```
256 |
257 | 构造函数是通过new关键字来生成对象实例,生成对象实例的过程也是通过构造函数给实例绑定this的过程,而箭头函数没有自己的this。创建对象过程,`new` 首先会创建一个空对象,并将这个空对象的`__proto__`指向构造函数的`prototype`,从而继承原型上的方法,但是箭头函数没有`prototype`。因此不能使用箭头作为构造函数,也就不能通过new操作符来调用箭头函数。
258 |
259 |
260 |
261 | ## 222.给定两个数组,写一个方法来计算它们的交集?【JavaScript】【出题公司: 腾讯】
262 |
263 | 可以使用 ES6 的 Set 数据结构来实现数组交集。
264 |
265 | 首先,将一个数组转化为 Set,然后遍历另一个数组,将数组中存在于 Set 中的元素存入结果数组中。
266 |
267 | 以下是一个示例代码:
268 |
269 | ```javascript
270 | function intersection(nums1, nums2) {
271 | const set1 = new Set(nums1);
272 | const res = [];
273 |
274 | for (let num of nums2) {
275 | if (set1.has(num)) {
276 | res.push(num);
277 | }
278 | }
279 |
280 | return res;
281 | }
282 | ```
283 |
284 | 使用示例:
285 |
286 | ```javascript
287 | const nums1 = [1, 2, 2, 1];
288 | const nums2 = [2, 2];
289 |
290 | console.log(intersection(nums1, nums2)); // [2]
291 | ```
292 |
293 | 该算法的时间复杂度为 O(m+n),其中 m 和 n 分别为两个数组的长度。
294 |
295 |
296 |
297 |
298 | # 高级开发者相关问题【共计 4 道题】
299 |
300 | ## 69.前端如何实现即时通讯?【网络】
301 |
302 | ## 前端如何实现即时通讯
303 | ### 短轮询
304 | 短轮询的原理很简单,每隔一段时间客户端就发出一个请求,去获取服务器最新的数据,一定程度上模拟实现了即时通讯。
305 |
306 | - 优点:兼容性强,实现非常简单
307 | - 缺点:延迟性高,非常消耗请求资源,影响性能
308 |
309 | ### comet
310 | comet有两种主要实现手段,
311 | 一种是基于 AJAX 的长轮询(long-polling)方式,
312 | 另一种是基于 Iframe 及 htmlfile 的流(streaming)方式,通常被叫做长连接。
313 |
314 | 具体两种手段的操作方法请移步 [Comet技术详解:基于HTTP长连接的Web端实时通信技术](http://www.52im.net/thread-334-1-1.html)
315 |
316 | - 长轮询优缺点:
317 | - 优点:兼容性好,资源浪费较小
318 | - 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护
319 |
320 | - 长连接优缺点:
321 | - 优点:兼容性好,消息即时到达,不发无用请求
322 | - 缺点:服务器维护长连接消耗资源
323 |
324 |
325 | ### SSE
326 | SSE(Server-Sent Event,服务端推送事件)是一种允许服务端向客户端推送新数据的HTML5技术。
327 | - 优点:基于HTTP而生,因此不需要太多改造就能使用,使用方便,而websocket非常复杂,必须借助成熟的库或框架
328 | - 缺点:基于文本传输效率没有websocket高,不是严格的双向通信,客户端向服务端发送请求无法复用之前的连接,需要重新发出独立的请求
329 |
330 |
331 | ### Websocket
332 | Websocket是一个全新的、独立的协议,基于TCP协议,与http协议兼容、却不会融入http协议,仅仅作为html5的一部分,其作用就是在服务器和客户端之间建立实时的双向通信。
333 |
334 | - 优点:真正意义上的实时双向通信,性能好,低延迟
335 | - 缺点:独立与http的协议,因此需要额外的项目改造,使用复杂度高,必须引入成熟的库,无法兼容低版本浏览器
336 |
337 | ### Web Worker
338 | Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行
339 |
340 | ### Service workers
341 | Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理,创建有效的离线体验。
342 |
343 |
344 |
345 | ## 206.浏览器缓存中 Memory Cache 和 Disk Cache, 有啥区别?【网络】【出题公司: 字节跳动】
346 |
347 | ### Memory Cache 和 Disk Cache 的区别
348 |
349 | 在浏览器缓存中,Memory Cache 和 Disk Cache 是两种不同的缓存类型,它们有以下区别:
350 |
351 | 1. 存储位置:Memory Cache 存储在内存中,而 Disk Cache 存储在硬盘中。
352 | 2. 读取速度:Memory Cache 读取速度比 Disk Cache 快,因为内存访问速度比硬盘访问速度快。
353 | 3. 存储容量:Memory Cache 存储容量比较小,一般只有几十兆,而 Disk Cache 存储容量比较大,可以有数百兆或者更多。
354 | 4. 生命周期:Memory Cache 生命周期短暂,一般只在当前会话中有效,当会话结束或者浏览器关闭时,Memory Cache 就会被清空;而 Disk Cache 生命周期比较长,数据可以被保存很长时间,即使浏览器关闭了,下次打开还可以使用。
355 |
356 | 一般来说,浏览器在请求资源时,会优先从 Memory Cache 中读取,如果没有找到再去 Disk Cache 中查找。如果两种缓存中都没有找到,则会向服务器发送请求。如果需要强制刷新缓存,可以通过清空浏览器缓存来实现。
357 |
358 | ### 什么情况下资源会缓存在 Memory Cache, 什么情况下会缓存在 Disk Cache ?
359 |
360 | 浏览器中的缓存是为了提高网页访问速度和减少网络流量而存在的。缓存分为 Memory Cache 和 Disk Cache 两种。
361 |
362 | Memory Cache 是浏览器内存缓存,资源会被缓存在内存中,由于内存读取速度快,所以 Memory Cache 的读取速度也较快。资源被缓存在 Memory Cache 中的情况有:
363 |
364 | 1. 当前页面中通过 或者