├── 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 | <img width="1378" alt="image" src="https://user-images.githubusercontent.com/22188674/222943207-390166d3-062e-469d-a480-d34dc4db1895.png"> 17 | 18 | 3. 题目的类型分类:使用 labels 方式管理 19 | <img width="927" alt="image" src="https://user-images.githubusercontent.com/22188674/222943276-0cf2146a-f7a9-416d-bd66-890fc81e736b.png"> 20 | 21 | 4. 关于题目序号, 直接使用 issue 自增 id 即可, 便于收藏记忆记录等: 22 | <img width="620" alt="image" src="https://user-images.githubusercontent.com/22188674/222943315-fb58b939-53a2-467f-bc57-cccc66a166eb.png"> 23 | 24 | 5. 关于问题讨论:开通 discussions 社区, 可以直接在 discussions 区进行讨论即可。 25 | <img width="1334" alt="image" src="https://user-images.githubusercontent.com/22188674/222943370-122d4d33-73cb-44c7-b18d-7db089e0bdfe.png"> 26 | 27 | 6. 使用技巧:本项目所有 open 的 issue 是作者进行整理了的问题。如何精确筛选呢? 28 | - 搜索 title : `is:open in:title [txt]` 29 | - 搜索 内容: `is:open in:body [txt]` 30 | <img width="767" alt="image" src="https://user-images.githubusercontent.com/22188674/223155285-7cf7e2f5-e0ed-4d6c-adea-bc5ec3e2933c.png"> 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<string, Array<any>>) => { 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 | <!DOCTYPE html>\n<!--[if lt IE 7]><html class="ie ie6"><! 2 | [endif]-->\n<!--[if IE 7]><html class="ie ie7"><! 3 | [endif]-->\n<!--[if IE 8]><html class="ie ie8"><! 4 | [endif]-->\n<!--[if IE 9]><html class="ie9"><! 5 | [endif]-->\n 6 | <!--[if (gt IE 9)|!(IE)]><!--><html class="standard"><!--<![endif]--> 7 | \n 8 | <head> 9 | \n 10 | <meta charset="utf-8" /> 11 | \n 12 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> 13 | \n \n 14 | <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> 15 | \n 16 | <meta http-equiv="Pragma" content="no-cache" /> 17 | \n 18 | <meta http-equiv="Expires" content="0" /> 19 | \n 20 | <title>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. 当前页面中通过 或者