基础篇
HTML
Q1: 前端需要注意哪些SEO A: SEO optimization helps search engines understand page content and improve rankings. Key points: use semantic HTML tags (header, nav, main, article, section, aside, footer) for content hierarchy; unique <title> per page (under 60 chars) and <meta name="description"> (under 160 chars); one <h1> per page with proper heading hierarchy; alt attributes on images; <link rel="canonical"> for duplicate content; fast page speed (Core Web Vitals: LCP < 2.5s, CLS < 0.1); JSON-LD structured data for rich snippets; sitemap.xml and robots.txt; mobile-friendliness; descriptive anchor text for internal links. Avoid: Flash/iframe content not indexable, SPA without SSR, blocked robots.txt, duplicate content, slow crawl budget.
Q2:
<img>的title和alt有什么区别 A: alt attribute: alternative text when image fails to load or for screen readers. Required for valid HTML5, critical for accessibility (WCAG), indexed for image SEO. Should describe image content or function. title attribute: advisory tooltip text on hover, optional, not reliably read by screen readers. Best practice: write descriptive alt (never keyword-stuff), use title only for extra context beyond alt. For decorative images: alt="" (empty) tells screen readers to ignore.Q3: HTTP的几种请求方法用途 A: GET: retrieve resource (idempotent, safe, cached). POST: submit data creating resource (non-idempotent). PUT: fully replace resource (idempotent). PATCH: partially modify resource (not necessarily idempotent). DELETE: remove resource (idempotent). HEAD: like GET but only returns response headers (check existence/metadata before download). OPTIONS: query supported methods (CORS preflight). CONNECT: establish tunnel (HTTPS proxy). TRACE: echo received request for debugging (disabled in production for security). REST convention: GET=query, POST=create, PUT=full update, PATCH=partial update, DELETE=remove.
Q4: 从浏览器地址栏输入url到显示页面的步骤 A: 1. DNS resolution: browser cache -> OS cache -> hosts -> local DNS server -> root/TLD/authoritative servers recursive query. 2. TCP three-way handshake (SYN->SYN-ACK->ACK). HTTPS adds TLS handshake (certificate verify, key exchange). 3. HTTP request: request line + headers + optional body. 4. Server processing: static file or dynamic generation, returns response. 5. Browser rendering: Parse HTML -> DOM tree, Parse CSS -> CSSOM, Merge -> Render Tree, Layout (geometry), Paint (pixel commands), Composite (layer merge). 6. Connection: close or reuse. Optimizations: DNS prefetch, HTTP/2 multiplexing, critical render path (CSS head, async JS).
Q5: 如何进行网站性能优化 A: Loading: bundle CSS/JS, CDN, HTTP/2, resource hints (preload/prefetch/preconnect), gzip/brotli, WebP/AVIF images, responsive srcset+sizes, lazy loading, Cache-Control + ETag caching. Rendering: inline critical CSS, CSS in head, JS async/defer, reduce DOM depth, minimize reflows/repaints, content-visibility: auto, will-change for compositing. Runtime: debounce/throttle, virtual lists, Web Workers, requestAnimationFrame, object pools. Measurement: Lighthouse, WebPageTest, Chrome DevTools, RUM. Track Core Web Vitals (LCP/FID/INP/CLS).
Q6: HTTP状态码及其含义 A: 1xx: 100 Continue, 101 Switching Protocols. 2xx Success: 200 OK, 201 Created (POST success), 204 No Content (DELETE success), 206 Partial Content (range). 3xx Redirection: 301 Moved Permanently (SEO updates URL), 302 Found (temporary), 304 Not Modified (cache valid), 307 (preserves method), 308 (permanent, preserves method). 4xx Client: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 408 Timeout, 413 Payload Too Large, 429 Rate Limited. 5xx Server: 500 Internal Error, 502 Bad Gateway, 503 Unavailable, 504 Gateway Timeout.
Q7: 语义化的理解 A: Semantic HTML uses meaningful tags (nav, article, section, aside, header, footer, h1-h6) rather than presentational divs/span. Benefits: 1) Accessibility: screen readers navigate via landmarks, keyboard users benefit from proper heading hierarchy. 2) SEO: search engines weight content by semantic structure. 3) Maintainability: self-documenting code. 4) Future-proof: standards-compliant across devices. Core principle: choose HTML elements that describe content purpose, style with CSS. Anti-pattern: "div soup" - all divs with no structural meaning.
Q8: 介绍一下你对浏览器内核的理解? A: Browser kernel (rendering engine) parses HTML/CSS and renders pages. Two components: rendering engine + JavaScript engine. Major rendering engines: Blink (Chrome, Edge, Opera - multi-process, sandboxed, forked from WebKit 2013), WebKit (Safari - all iOS browsers use WKWebView), Gecko (Firefox - Mozilla, Servo parallel CSS), Trident (legacy IE, retired), EdgeHTML (legacy Edge). Pipeline: HTML->DOM, CSS->CSSOM, DOM+CSSOM->Render Tree, Layout, Paint, Composite. JS engines: V8 (Chrome, JIT+inline caching), SpiderMonkey (Firefox), JavaScriptCore/Nitro (Safari).
Q9: html5有哪些新特性、移除了那些元素? A: New features: semantic tags (header, footer, nav, article, section, aside, main, figure, figcaption); multimedia (audio, video, source, track); canvas (2D/WebGL); native SVG; form enhancements (email, url, number, date, color input types; placeholder, autofocus, required, pattern attributes); APIs (Geolocation, Web Storage, Web Workers, WebSocket, History API pushState/replaceState, Drag and Drop, File API, Intersection Observer, Resize Observer); offline (Service Workers, Cache API, IndexedDB); performance (requestAnimationFrame, requestIdleCallback); <details>/<summary>, <progress>, <meter>, <datalist>. Removed: presentational tags (big, center, font, basefont, strike, tt), frameset elements (frame, frameset, noframes), acronym, applet, dir.
Q10: HTML5的离线储存怎么使用,工作原理能不能解释一下? A: Service Workers: JS running in a separate thread as a programmable network proxy. 1) Register: navigator.serviceWorker.register('/sw.js'). 2) Install event: pre-cache app shell resources. 3) Activate event: clean old caches. 4) Fetch event: intercept requests with cache strategies - Cache First (static assets), Network First (API with cache fallback), Cache Only (shell), Network Only (real-time), Stale-while-revalidate (serve cache, background update). Storage: Cache API (Request/Response pairs) + IndexedDB (structured data). SW works offline and survives reload. AppCache (deprecated): manifest file approach, removed due to opaque behavior and cache poisoning issues.
Q11: 浏览器是怎么对HTML5的离线储存资源进行管理和加载的呢 A: Registration: browser downloads SW script and spawns background thread. Install: fires for new/updated SW, used for pre-caching. If install fails, SW is discarded. Activate: fires after install and all old SW tabs close, used to delete old caches. Versioning: cache names include version identifier (e.g., my-app-v2); activate handler deletes non-matching caches. Update: browser detects byte-level difference in SW file on each navigation, fetches new version in background. New SW enters 'waiting' state until all clients close. self.skipWaiting() + clients.claim() forces immediate takeover. Lifecycle: Parsed -> Installing -> Installed (Waiting) -> Activating -> Activated -> Redundant.
Q12: 请描述一下 cookies,sessionStorage 和 localStorage 的区别? A: Cookie: ~4KB, lifespan via Expires/Max-Age, domain+path scope, auto-sent via Cookie header, HttpOnly/Secure/SameSite support, string API via document.cookie. localStorage: ~5-10MB, persistent until deleted, origin scope (protocol+domain+port), never sent to server, key-value API (getItem/setItem/removeItem), JS-accessible (XSS vulnerable). sessionStorage: ~5-10MB, per-tab until closed, origin+tab scope, never sent to server, same API as localStorage but tab-isolated. Usage: cookies for server-session auth (HttpOnly+Secure+SameSite), localStorage for client-only persistent data (preferences, cache), sessionStorage for tab-specific transient state (form drafts). Never store sensitive data in localStorage/sessionStorage.
Q13: iframe有那些缺点? A: 1) Performance: each iframe creates full browsing context (separate DOM/CSSOM/JS engine), increases memory and blocks parent onload. 2) SEO: search engines don't fully index iframe content; value doesn't transfer to parent. 3) Security: clickjacking vector - use X-Frame-Options: DENY/SAMEORIGIN or CSP: frame-ancestors. 4) Communication: cross-origin requires postMessage (complex and security-sensitive). 5) Accessibility: screen readers struggle with iframe navigation (always add title attribute). 6) Responsive: extra CSS needed (aspect-ratio hack). Modern alternatives: Web Components, Fetch + innerHTML content embedding, Server-Side Includes.
Q14: WEB标准以及W3C标准是什么? A: W3C (World Wide Web Consortium, founded 1994 by Tim Berners-Lee) develops open web standards ensuring consistency, accessibility, and interoperability. Core standards: HTML (WHATWG jointly maintains Living Standard), CSS (by modules), DOM API, SVG, WCAG (accessibility), WebAssembly, WebRTC, WebAuthn. WHATWG formed in 2004 (Apple, Mozilla, Opera) due to W3C's slow progress, now collaboratively maintains HTML. Following standards ensures cross-browser compatibility, future-proof code, accessibility, maintainability, and improved performance.
Q15: xhtml和html有什么区别? A: XHTML reformulates HTML as XML. Differences: 1) Syntax strictness - must close all tags (<br />, not <br>), quote attributes, no minimization (checked="checked"), lowercase tags, proper nesting. 2) Error handling - XHTML as application/xhtml+xml uses XML parser: ANY syntax error shows fatal 'yellow screen of death'. HTML uses forgiving parser that auto-corrects. 3) MIME - most 'XHTML' served as text/html used HTML parser, negating benefits. XHTML 2.0 abandoned in 2009 (backward incompatible). Modern practice: HTML5 with <!DOCTYPE html>. Write clean markup but don't force XML strictness unless you need XSLT transforms.
Q16: Doctype作用? 严格模式与混杂模式如何区分?它们有何意义? A: DOCTYPE tells browser which HTML version, determining rendering mode. Standars Mode: follows W3C specs strictly (standard box model). Triggered by <!DOCTYPE html> (HTML5), HTML4 Strict DTD, XHTML DTDs. Quirks Mode: emulates legacy IE5/Netscape 4 behavior (non-standard box model where width includes padding/border). Triggered by missing DOCTYPE or old DOCTYPEs. Almost Standards Mode (Firefox): strict except for legacy table cell line-height behavior. Detection: document.compatMode returns 'CSS1Compat' (standards) or 'BackCompat' (quirks). Always use <!DOCTYPE html> to ensure consistent cross-browser rendering.
Q17: 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?行内元素和块级元素有什么区别? A: Inline: span, a, strong, em, b, i, u, small, abbr, cite, code, dfn, kbd, mark, q, samp, sub, sup, time, var, br, img, input, label, select, textarea, button. Block: div, p, h1-h6, ul, ol, li, table, form, section, article, nav, aside, header, footer, main, blockquote, pre, hr, address, figure, figcaption, dl, dt, dd. Void (self-closing, no children): br, hr, img, input, meta, link, area, base, col, embed, source, track, wbr. Differences: inline sit on same line; block start new line, take full width. Block respect all width/height/margin/padding; inline only respect horizontal margins/padding. Block can contain other blocks/inline; inline can only contain inline or text (except a wraps anything in HTML5).
Q18: HTML全局属性(global attribute)有哪些 A: class (CSS class selector), id (unique identifier), style (inline CSS), title (tooltip), lang (language - affects hyphenation, quotes, screen reader pronunciation), dir (text direction: ltr/rtl/auto), hidden (not relevant, hidden from render), tabindex (Tab order: -1=programmatic, 0=natural, positive=explicit order), contenteditable (user-editable content), draggable (drag/drop), spellcheck, translate (localization), accesskey (keyboard shortcut), data-* (custom data via element.dataset), role (ARIA role), aria-* (accessibility attributes), slot (Shadow DOM named slot), is (custom built-in elements), part (exposes parts for ::part() styling).
Q19: Canvas和SVG有什么区别? A: Canvas: pixel-based immediate-mode rendering. Drawing commands execute and render instantly; elements NOT retained as objects. Best for dynamic real-time graphics (games, data viz, video processing, image filters). Performance degrades with pixel count (canvas size). No DOM per element - requires manual hit detection. Resolution-dependent (handle devicePixelRatio for HiDPI). SVG: vector-based retained-mode. Elements persist as DOM nodes, CSS-styleable, event-bindable. Resolution-independent (crisp at any zoom). Best for static/interactive scalable graphics (icons, logos, charts, illustrations). Performance degrades with DOM node count. Supports CSS animations/transitions. Canvas for many dynamic pixels; SVG for scalable interactive elements.
Q20: HTML5 为什么只需要写
<!DOCTYPE HTML>A: HTML5 is not SGML-based unlike HTML 4.01. In HTML 4.01, DOCTYPE required a DTD URL: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">. HTML5 abandoned SGML, using its own parsing algorithm independent of any formal grammar. The DOCTYPE's only purpose is to trigger standards mode in browsers. No DTD is fetched or validated against - the browser sees <!DOCTYPE html> and switches to standards mode immediately. Backward compatible: works in all browsers including IE6+. Short, simple, impossible to get wrong.Q21: 如何在页面上实现一个圆形的可点击区域? A: 1) CSS border-radius: width/height equal + border-radius: 50% + overflow: hidden + cursor: pointer. Simplest, widely compatible. Click area is the visual circle (CSS clips). 2) SVG <circle>: native DOM element with precise geometric click handling and events. 3) HTML Image Map: <area shape="circle" coords="x,y,radius"> - native image-based circular click regions. 4) Canvas: draw circle, manual hit detection with Math.hypot(dx, dy) <= radius. For most use cases, CSS border-radius is sufficient. For pixel-perfect circular zones, use SVG or image map.
Q22: 网页验证码是干嘛的,是为了解决什么安全问题 A: CAPTCHA distinguishes humans from bots. Problems solved: brute force password guessing, comment spam, fake account registration, ticket scalping, vote rigging, resource exhaustion (scraping). Types: Text-based (distorted characters - legacy, broken by ML); Image-based (select objects - reCAPTCHA v2); Behavioral (mouse tracking, timing - reCAPTCHA v3, no user action needed); Audio (accessibility). Modern: reCAPTCHA v3 assigns risk score (0.0-1.0), low-risk auto-approved, high-risk triggers challenge. Server-side verification is mandatory (client-side only is bypassable). Balance security vs UX.
Q23: viewport A: Viewport meta tag controls the layout viewport on mobile. Default mobile viewport is ~980px (simulating desktop), causing zoomed-out appearance. <meta name="viewport" content="width=device-width, initial-scale=1.0">: width=device-width matches device CSS pixels; initial-scale=1.0 prevents auto-zoom. Parameters: width (device-width or pixels), initial-scale (0.25-5.0), minimum-scale/maximum-scale (zoom limits), user-scalable (yes/no - no violates WCAG), viewport-fit (auto/cover/contain for notched devices). Important: never disable zoom (WCAG failure). Use env(safe-area-inset-*) for notched devices. Combine with CSS media queries for responsive design.
Q24: 渲染优化 A: Rendering optimization reduces the time from page change to pixel update. Critical Rendering Path: inline critical CSS in <head>, defer non-critical CSS/JS, reduce DOM depth (< 32 layers), minimize reflows/repaints by batching DOM operations and using requestAnimationFrame. Compositing: use will-change or transform: translateZ(0) for compositor layers; animate only transform and opacity (skip layout/paint). Loading: content-visibility: auto for off-screen sections, loading="lazy" for images, contain: layout style paint to scope rendering. Frame budget: all work must complete within 16.67ms (60fps) or 8.33ms (120fps). Use Performance panel to identify bottlenecks.
Q25: meta viewport相关 A: Full syntax: <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, viewport-fit=cover">. width=device-width: sets viewport to device CSS pixel width (prevents 980px virtual viewport). initial-scale: zoom factor at load (1.0 = no zoom). minimum-scale/maximum-scale: zoom range limits. user-scalable: allow pinch-zoom (no violates WCAG 2.0). viewport-fit: iPhone X+ handling - auto (safe area respect), cover (extend into notch), contain (stay safe). Best practices: always include on responsive sites; never set user-scalable=no or maximum-scale=1.0; with viewport-fit=cover, add env(safe-area-inset-*) padding; use dvh units for iOS Safari viewport height.
Q26: 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? A: Desktop: Chrome (Blink+V8), Firefox (Gecko+SpiderMonkey), Edge (Blink+V8 since 2020 Chromium), Safari macOS (WebKit+JavaScriptCore), Opera (Blink+V8). Legacy: IE (Trident+Chakra, retired 2022). Mobile: Safari iOS (WebKit - all iOS browsers mandatory WKWebView per App Store policy), Chrome Android (Blink+V8), Samsung Internet (Blink+V8). Testing strategy: latest 2 versions of Chrome, Firefox, Safari (desktop+mobile). Use BrowserStack/Sauce Labs for cross-platform. CanIUse for feature support. Enterprise: test Chrome 90+ and Safari 14+ based on analytics.
Q27: div+css的布局较table布局有什么优点? A: 1) Separation of concerns: CSS separates presentation from content; table intertwines them and <table> implies tabular data (semantically incorrect for layout). 2) Performance: tables require full download before rendering (column widths depend on total content); CSS renders progressively. 3) Responsiveness: flexbox/grid naturally adapt; tables are rigid requiring complex restructuring. 4) Accessibility: screen readers announce table rows/columns - confusing for layout-not-data. 5) Maintenance: CSS is DRY, one file change affects all pages. 6) Bandwidth: less markup (no deeply nested tables). 7) SEO: semantic elements carry more weight. Use <table> only for tabular data.
Q28: a:img的alt与title有何异同?b:strong与em的异同? A: a) alt vs title: alt = required alternative text, for screen readers/image fail/indexed for SEO. title = optional tooltip, hover only (desktop), not reliably read by screen readers. b) strong vs em: strong = strong importance/urgency, screen readers change tone (louder), visual bold. em = stress emphasis (as if spoken), screen readers change pitch/accent, visual italic. <b> is purely presentational bold (keywords, product names). <i> is purely presentational italic (technical terms, foreign words). Use <strong> and <em> for semantic meaning; use CSS instead of <b>/<i> for styling.
Q29: 你能描述一下渐进增强和优雅降级之间的不同吗 A: Graceful Degradation: build for modern browsers first (full CSS Grid, CSS Variables), add fallbacks/polyfills for older/less capable browsers. Top-down (modern -> legacy). Example: build with CSS Grid, add float fallback. Progressive Enhancement: start with basic universal baseline (semantic HTML, basic CSS), layer enhanced features for supporting browsers. Bottom-up (baseline -> modern). Example: simple form (works everywhere) -> CSS styling -> JS validation -> AJAX. Modern consensus: Progressive Enhancement is preferred - it ensures universal access and aligns with the web's inherently progressive and fault-tolerant nature.
Q30: 为什么利用多个域名来存储网站资源会更有效? A: 1) Parallel downloads: HTTP/1.1 limits ~6 connections per origin; multiple domains increase total concurrent connections. 2) Cookie-less domain: cookies sent with every request to the origin (including static assets). A separate domain avoids cookie overhead, reducing header size and latency. 3) CDN distribution: multiple domains often point to CDN edge servers for geographic proximity. 4) Failure isolation: one domain failure doesn't break everything. Modern caveat: HTTP/2 multiplexing makes domain sharding harmful (breaks single-connection stream multiplexing). Use one CDN domain for static assets in HTTP/2+ setups. Cookie-less domain benefit remains valid.
Q31: 简述一下src与href的区别 A: src (source): used on <img>, <script>, <iframe>, <video>, <audio>. The resource is embedded INTO the document, replacing the element's content. <script src> blocks HTML parsing until fetched and executed (unless async/defer). href (hypertext reference): used on <a>, <link>, <area>, <base>. Establishes a RELATIONSHIP between documents. <link href="style.css"> downloads CSS in parallel without blocking HTML parsing (but blocks rendering). <a href> doesn't fetch anything until clicked. Key distinction: src embeds and may block the parser; href references and typically doesn't block parsing.
Q32: 知道的网页制作会用到的图片格式有哪些? A: Raster: JPEG - lossy, 24-bit, photos, no transparency. PNG-8 - lossless, 256 colors, 1-bit transparency, simple graphics. PNG-24 - lossless, 24-bit, full alpha transparency. GIF - 256 colors, animation, 1-bit transparency. WebP - Google format, lossy/lossless, alpha, animation, 25-35% smaller than JPEG (95%+ browser support). AVIF - AV1-based, 50% smaller than JPEG, HDR/wide-gamut/alpha/animation (Chrome 85+, Firefox 93+). Vector: SVG - XML, resolution-independent, CSS-styleable, DOM-manipulable. Best for icons, logos, illustrations that need crisp scaling. Next-gen: JPEG XL (pending broad adoption), HEIF (Apple ecosystem).
Q33: 在CSS/JS代码上线之后,开发人员经常会优化性能。从用户刷新网页开始,一次JS请求一般情况下有哪些地方会有缓存处理? A: Cache layers in order: 1) Service Worker Cache - programmable CacheStorage intercept (developer-controlled strategy). 2) Memory Cache - RAM, current session only, fastest but non-persistent. 3) Disk Cache (HTTP Cache) - controlled by Cache-Control (max-age, no-cache, immutable), ETag/Last-Modified for revalidation (304 Not Modified if unchanged). 4) CDN Cache - edge servers cache based on headers. 5) Proxy Cache - corporate/ISP (Cache-Control: private vs public). 6) HTTP/2 Push Cache - resources pushed via server push. Invalidation strategy: content hash in filename (app.a3b4c5.js) + immutable + long max-age. Hash changes -> new URL -> guaranteed fresh.
Q34: 一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。 A: 1) Lazy loading: <img loading="lazy"> or Intersection Observer (trigger ~1000px before viewport). 2) Responsive images: srcset + sizes attributes - mobile devices download appropriately sized images, not 2000px desktop versions. 3) Modern formats: WebP/AVIF with <picture> fallback. 4) Image CDN: Cloudinary/Imgix for on-the-fly resize/compress/convert. 5) Progressive JPEG: low-quality preview first, then refine. 6) LQIP: tiny blurred placeholder (10x10px, ~200 bytes) transitioning to full image. 7) Preload critical images: <link rel="preload" as="image"> for above-the-fold. 8) Caching: content-hashed URLs + aggressive Cache-Control. 9) Compression: quality 80-85 for JPEG/WebP.
Q35: 常见排序算法的时间复杂度,空间复杂度 A: Bubble: O(n)/O(n^2)/O(n^2)/O(1)/Y; Selection: O(n^2)/O(n^2)/O(n^2)/O(1)/N; Insertion: O(n)/O(n^2)/O(n^2)/O(1)/Y; Merge: O(n log n)/O(n log n)/O(n log n)/O(n)/Y; Quick: O(n log n)/O(n log n)/O(n^2)/O(log n)/N; Heap: O(n log n)/O(n log n)/O(n log n)/O(1)/N; Shell: O(n log n)/O(n(log n)^2)/O(n(log n)^2)/O(1)/N; Counting: O(n+k)/O(n+k)/O(n+k)/O(k)/Y; Radix: O(nk)/O(nk)/O(nk)/O(n+k)/Y (format: Best/Average/Worst/Space/Stable). QuickSort fastest in practice (cache locality), worst-case O(n^2) with poor pivot (use median-of-three). MergeSort is stable, guaranteed O(n log n). V8 uses TimSort (hybrid merge+insertion) for Array.sort() - stable, O(n log n).
Q36: web开发中会话跟踪的方法有哪些 A: 1) Cookies: Set-Cookie: sessionId=abc; HttpOnly; Secure; SameSite=Lax. Most common, 4KB limit, can be disabled, CSRF risk. 2) URL rewriting: session ID in URL params. Works without cookies, but exposes ID in logs/bookmarks. 3) Hidden form fields: <input type="hidden" name="sessionId"> - form-only tracking. 4) localStorage: ~5MB, sent via Authorization header. XSS vulnerable. 5) HTTP headers: Authorization: Bearer <token> - common in REST APIs/SPAs. 6) Server-side sessions: only session ID on client; actual data in Redis/database - most secure. 7) Fingerprinting: IP+UA+screen resolution+fonts - inaccurate, privacy-concerning. Best practice: HttpOnly+Secure+SameSite cookie for session + Redis storage. JWT for stateless API auth.
Q37: HTTP request报文结构是怎样的 A: Request Line: METHOD PATH HTTP_VERSION (e.g., GET /api/users?page=1 HTTP/1.1). Headers (key:value, one per line): General (Cache-Control, Connection), Request (Host, User-Agent, Accept, Accept-Encoding, Authorization, Cookie), Entity (Content-Type, Content-Length, Content-Encoding for body-bearing methods). Headers end with \r\n\r\n (blank line). Body: present for POST/PUT/PATCH (JSON, form-data, multipart, binary). GET/DELETE typically no body. HTTP/2 uses binary frames but logically equivalent structure: pseudo-headers replace the request line (":method", ":path", ":scheme", ":authority")).
Q38: HTTP response报文结构是怎样的 A: Status Line: HTTP_VERSION STATUS_CODE STATUS_TEXT (e.g., HTTP/1.1 200 OK). Headers: General (Date, Connection, Cache-Control), Response (Server, Set-Cookie, WWW-Authenticate), Entity (Content-Type, Content-Length, Content-Encoding, Last-Modified, ETag), CORS (Access-Control-Allow-Origin, Access-Control-Allow-Methods). Headers end with \r\n\r\n. Body: format matches Content-Type (JSON, HTML, XML, binary, plain text). May be chunked (Transfer-Encoding: chunked) for streaming responses. HEAD requests have no body. 204 No Content and 304 Not Modified also have no body. HTTP/2 uses binary frames with equivalent logical structure.
Q39: title与h1的区别、b与strong的区别、i与em的区别 A: title vs h1: <title> is metadata in <head> - browser tab title, bookmark label, SERP display. One per page, critical for SEO ranking. <h1> is content heading in <body> - in-page structure hierarchy, screen reader navigation landmark. HTML5 allows multiple <h1> (one per sectioning element). b vs strong: <b> is purely presentational bold (stylistic offset, keywords). <strong> conveys strong importance/urgency - screen readers modify vocal emphasis. i vs em: <i> is purely presentational italic (technical terms, foreign words). <em> conveys stress emphasis - screen readers change intonation. Golden rule: use semantic elements for meaning; use CSS instead of <b>/<i> for styling.
Q40: 请你谈谈Cookie的弊端 A: 1) Size limit: ~4KB per cookie, insufficient for complex state. 2) Performance: sent with EVERY request to origin including static assets - 2KB cookie x 100 requests = 200KB unnecessary overhead per page. 3) Security: XSS (without HttpOnly, injected JS reads document.cookie), CSRF (automatic cross-origin sending - SameSite mitigates), cross-site tracking (3rd-party cookies being phased out by browsers). 4) Usability: users can disable/clear cookies. Behavior varies (Safari ITP). 5) Plain-text: sent unencrypted on HTTP (always use Secure+HTTPS). Modern approach: HttpOnly+Secure+SameSite cookie for session ID only; actual data server-side (Redis). localStorage for client-only data. JWT for stateless API auth.
Q41: git fetch和git pull的区别 A: git fetch: downloads remote changes into local tracking branches (origin/main). Does NOT modify working branch - safe read-only operation. Use to review before integrating: git fetch origin, then git log origin/main..main to see behind commits, then manual merge/rebase. git pull: shortcut for git fetch + git merge (or git rebase with --rebase). Modifies working directory, may create merge commits. Use case: git fetch for cautious review-first workflow; git pull for convenience when confident. For shared branches, prefer git pull --rebase to avoid unnecessary merge commits and maintain clean linear history. git pull = fetch + merge/merge-rebase.
Q42: http2.0 做了哪些改进 http3.0 呢 A: HTTP/2 (2015): 1) Multiplexing - multiple concurrent streams over single TCP connection, eliminating HTTP/1.1 application-layer HOL blocking. 2) Binary framing - efficient frame-based protocol (HEADERS, DATA, SETTINGS). 3) Server push - server proactively pushes resources (being deprecated by Chrome due to misuse). 4) Header compression (HPACK) - Huffman + dynamic table, 85-90% reduction. 5) Stream prioritization - client prioritizes critical resources. 6) Per-stream flow control. HTTP/3 (2022): 1) QUIC transport (UDP-based) - eliminates TCP-level HOL blocking; packet loss only blocks its stream, not all streams. 2) 0-RTT - returning users send data immediately. 3) Connection migration - survives IP changes (Wi-Fi->cellular). 4) Encryption by default (transport headers encrypted).
Q43: css sprite是什么,有什么优缺点 A: CSS Sprite combines multiple small images into one file, displaying portions via background-position. Advantages: fewer HTTP requests (critical for HTTP/1.1), better compression (shared color palette), atomic loading (all icons appear together). Disadvantages: maintenance overhead (regenerating entire sprite when adding icons), wasted bandwidth (entire sprite downloaded even if few icons used), no partial cache invalidation (changing one icon invalidates entire sprite), HiDPI complexity (need separate sprites). Modern alternatives: SVG sprites (<symbol> + <use>), icon fonts, or HTTP/2 multiplexing (reduces need for sprite optimization since multiple requests are cheap).
CSS
Q44: css sprite是什么,有什么优缺点 A: See Q43. CSS Sprite combines multiple small images into one file using background-position to display portions. Advantages: fewer HTTP requests, better compression, atomic loading. Disadvantages: maintenance overhead, wasted bandwidth, no partial cache invalidation, HiDPI complexity. Modern alternatives: SVG sprites (<symbol> + <use>), icon fonts, HTTP/2 multiplexing.
Q45: display: none;与visibility: hidden;的区别 A: display: none - removes element from render tree entirely. Takes NO layout space - surrounding elements reflow to fill gap. NOT accessible to screen readers. Triggers reflow (layout recalculation) + repaint. Resources (images) may not load if display:none initially. CANNOT be animated. visibility: hidden - hides element visually but SPACE remains in layout (element still in render tree). DOES NOT trigger reflow - only repaint or compositing (for GPU-accelerated layers). Still accessible to screen readers (use aria-hidden="true" to hide from AT). CAN be animated (opacity transition). Choose display:none for truly removing elements; visibility:hidden for keeping layout space or fade-out transitions.
Q46: link与@import的区别 A: link: <link rel="stylesheet" href="style.css"> - HTML tag, works in all browsers including legacy. Loads in PARALLEL with HTML parsing (does NOT block parsing but blocks render). Can include media queries (<link media="print">). Can be dynamically injected from JS (creates a new HTTP request). No additional HTTP request for multiple link tags in head. @import: @import url('style.css') - CSS directive, must appear BEFORE other CSS rules. Loads SEQUENTIALLY (blocks until imported stylesheet loads). Cannot be used in older IE (before IE5). Cannot be dynamically loaded from JS. Creates additional HTTP request cascade. Cannot use media queries. Performance: @import blocks parallel downloads and increases critical path, avoids in modern development.
Q47: 什么是FOUC?如何避免 A: FOUC (Flash of Unstyled Content) occurs when the browser renders HTML before all CSS has loaded, causing a brief flash of unstyled content before styles apply. Common in IE and with slow network. Causes: stylesheets loaded via @import causing waterfall; stylesheets in the wrong order; slow CSS loading; JavaScript waiting for stylesheets. Prevention: 1) Inline critical CSS in <head> for above-the-fold content. 2) Use <link> instead of @import. 3) Load non-critical CSS asynchronously. 4) Place stylesheets early in <head>. 5) Use consistent font-loading strategy (font-display: swap). 6) For maximum control, hide body with CSS opacity: 0 and reveal after CSS loads (using Critical CSS + load event).
Q48: 如何创建块级格式化上下文(block formatting context),BFC有什么用 A: BFC (Block Formatting Context) is a CSS rendering region where block elements are laid out and interactions with outside elements are isolated. Creating BFC: overflow: hidden/auto/scroll (not visible); display: flow-root (best choice, no side effects); display: flex/inline-flex/grid/inline-grid; float: left/right (not none); position: absolute/fixed; display: inline-block; column-count: not auto. Benefits: 1) Contain floats - prevents parent collapse with floating children. 2) Prevent margin collapsing - margins of elements inside BFC don't collapse with outside elements. 3) Prevent wrapping around floats - creates a new column beside floated elements used in multi-column layouts. display: flow-root is preferred as it creates BFC without side effects (unlike overflow which clips shadows).
Q49: display、float、position的关系 A: display determines the element's box type and initial layout behavior. float moves element to side, taking it out of normal flow - it overrides display to compute as block-level for most elements (except inline-table, flex, etc.). position: absolute/fixed takes element completely out of flow - float is ignored (computed as none). position: relative keeps normal flow but allows offset. Relationship rules: 1) If position is absolute/fixed, float becomes none and display computes to block. 2) If float is not none, display computes to block or table. 3) Elements with display: flex/grid ignore float on children. Understanding this cascade avoids layout bugs where float or absolute positioning unexpectedly changes element sizing behavior.
Q50: 清除浮动的几种方式,各自的优缺点 A: 1) Clearfix with ::after pseudo-element (most common): .clearfix::after { content: ''; display: table; clear: both; } - works everywhere, no extra HTML. 2) overflow: hidden/auto on parent - creates BFC, contains floats. Con: clips overflow content (shadows, absolute positioned children). 3) display: flow-root on parent - creates BFC without side effects. Modern CSS, but not supported in older browsers. 4) Empty clearing div: <div style="clear: both"> - extra non-semantic HTML element. 5) Using flexbox/grid - modern approach that avoids floats entirely. Recommendation: use clearfix pattern for legacy float layouts; prefer flexbox/grid for new layouts.
Q51: 为什么要初始化CSS样式? A: CSS initialization (CSS reset) removes browser default styles which vary across browsers (e.g., margins on body, padding on ul, font sizes on h1-h6). Without reset, the same CSS can look different in Chrome vs Firefox vs Safari due to different user-agent stylesheets. Approaches: 1) CSS Reset (Eric Meyer) - removes ALL defaults to zero. Elements need explicit restyling. 2) Normalize.css - preserves useful defaults while normalizing differences across browsers. More practical approach. 3) Custom reset - minimal reset for project-specific needs (e.g., *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }). Benefit: consistent baseline across browsers, predictable layout calculations, reduced cross-browser QA time.
Q52: css3有哪些新特性 A: Selectors: attribute selectors ([attr^=val], [attr$=val], [attr*=val]), structural pseudo-classes (:nth-child, :nth-of-type, :last-child, :first-of-type, :not()), UI pseudo-classes (:enabled, :disabled, :checked). Box model: box-sizing (content-box/border-box). Layout: Flexbox, CSS Grid, Multi-column. Visual: border-radius, box-shadow, text-shadow, gradient (linear-gradient, radial-gradient), multiple backgrounds, background-size, rgba/hsla colors, opacity. Transitions: transition-property, transition-duration, transition-timing-function, transition-delay. Transforms: rotate, scale, translate, skew (2D + 3D). Animations: @keyframes + animation properties. Web Fonts: @font-face, font-display. Media Queries: @media for responsive design. Calc: calc() for CSS math. Variables: custom properties (--var-name). Filters: filter (blur, grayscale, contrast).
Q53: display有哪些值?说明他们的作用 A: none: hides element (removes from render tree). block: starts new line, takes full width. inline: stays in line, width/height determined by content. inline-block: inline flow but respects width/height/margin/padding (no line break). flex: block-level flex container. inline-flex: inline-level flex container. grid: block-level grid container. inline-grid: inline-level grid container. table/inline-table/table-row/table-cell/table-caption: table layout behavior for non-table elements. list-item: behaves like <li>. flow-root: creates BFC without side effects. contents: removes element from render tree, children inherit layout position. inherit/initial/unset/revert: CSS keyword values for inheritance control.
Q54: 介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的? A: Standard W3C box model (content-box): width/height = content area only. padding and border are EXTRA additions. Total width = width + padding-left + padding-right + border-left + border-right. IE box model (border-box): width/height = content + padding + border. Total width = width (padding/border included). box-sizing: border-box is preferred because it makes sizing predictable - percentage widths don't overflow when adding padding. Padding can be adjusted without recalculating widths. Most projects set *, *::before, *::after { box-sizing: border-box; } globally. Margin is NEVER included in width in either model.
Q55: CSS优先级算法如何计算? A: CSS specificity is calculated as four levels (a,b,c,d): a = inline styles (style attribute) - 1000; b = ID selectors (count) - 100 each; c = class selectors, pseudo-classes, attributes (count) - 10 each; d = element selectors, pseudo-elements (count) - 1 each. Examples: #header (0,1,0,0) > .nav (0,0,1,0) > div (0,0,0,1). !important overrides all specificity (use sparingly - breaks natural cascade). Same specificity: later rule wins. Concatenated string comparison: (0,1,0,0) beats (0,0,10,0) because 1 ID > 10 classes. Algorithm: browsers use a four-part tuple comparison, not a base-10 sum. Practice: keep specificity low, avoid !important, use BEM naming to manage specificity.
Q56: 对BFC规范的理解? A: BFC (Block Formatting Context) is a region of the page where block boxes are laid out according to normal flow rules, with interactions with outside elements isolated. BFC establishes an independent rendering context: margins of child elements don't collapse with outside elements; floats inside are contained; the BFC box creates a new column next to floated elements (used in adaptive layouts). BFC creation methods: float (not none), overflow (not visible), display (inline-block, flow-root, flex, grid), position (absolute, fixed), contain (layout, content, paint). display: flow-root is the semantic way to create BFC without side effects. Modern layouts (flexbox, grid) create their own formatting contexts similar to BFC.
Q57: 谈谈浮动和清除浮动 A: Float takes an element out of normal document flow, positioning it to the left or right of its container. Content flows around the floated element. Floats were originally for text wrapping around images but became the primary CSS layout method before flexbox/grid. Issues: parent height collapse (parent doesn't contain floated children), overlapping content, unexpected width behavior. Solutions: 1) Clearfix with ::after { content: ''; display: table; clear: both; }. 2) overflow: hidden on parent (creates BFC). 3) display: flow-root (BFC without side effects). Modern approach: use flexbox for 1D layouts and grid for 2D layouts. Floats should only be used for their original purpose: text wrapping around images.
Q58: position的值, relative和absolute定位原点是 A: static: default, element follows normal document flow, z-index/top/left/right/bottom ignored. relative: element stays in normal flow but offset relative to its normal position (top/left/right/bottom). Creates a new containing block for absolute children. ancestor reference for absolute positioning. absolute: removed from normal flow, positioned relative to nearest positioned ancestor (non-static). If no positioned ancestor, uses document (initial containing block). width shrinks to content. used for overlays, modals, tooltips, precise positioning. fixed: removed from normal flow, positioned relative to viewport (initial containing block). Stays fixed on scroll. Uses: sticky headers, floating action buttons, back-to-top buttons. sticky: hybrid of relative+fixed. Behaves as relative until scroll threshold, then fixes. Uses: sticky headers, section labels. Containing block for fixed: viewport. Containing block for sticky: nearest scroll container.
Q59: display:inline-block 什么时候不会显示间隙? A: inline-block gap occurs when HTML has whitespace (space, tab, newline) between inline-block elements, because inline-block elements are treated as inline content where whitespace collapses into a single space character (~4px). Situations WITHOUT gap: 1) No whitespace between tags in HTML: <div>a</div><div>b</div>. 2) Font-size: 0 on parent (font-size zero makes space character width zero - re-set font-size on children). 3) Negative margin compensation (fragile, depends on font). 4) Flexbox/grid (gap property doesn't apply to inline-block). 5) Comments between elements: <div>a</div><!-- --><div>b</div>. Best practice: for layout, prefer flexbox/grid which handle spacing natively without whitespace issues.
Q60: PNG\GIF\JPG的区别及如何选 A: PNG: Lossless, supports full alpha transparency (PNG-24) or 1-bit (PNG-8). Best for: screenshots, UI elements with transparency, graphics with sharp edges/ text, logos with gradients. File size larger than JPEG for photos. GIF: Lossless (limited to 256 colors), supports simple animation, 1-bit transparency (hard edges, no alpha). Best for: simple animations (spinners, emoji memes), small animated icons. Not suitable for: photos or high-color images due to limited palette. JPEG: Lossy compression, 24-bit color (16.7M colors), no transparency/animation. Best for: photographs, complex images with smooth gradients. Smaller than PNG for photos. Rule of thumb: JPEG for photos, PNG-8 for simple graphics, PNG-24 for quality+transparency, GIF for animation, WebP/AVIF as modern replacements.
Q61: 行内元素float:left后是否变为块级元素? A: When an inline element (like span or a) is floated with float: left/right, its computed display value effectively becomes 'block' (for most original display values). This happens because float participation forces the element to establish a block formatting context. However, the element is NOT fully equivalent to display: block - while it does accept width/height and vertical margins (which inline elements normally don't), its computed display value in CSSOM may still not be literally 'block' for all cases. Key practical result: floated inline elements can accept explicit width, height, top/bottom margin, and padding - behaviors that non-floated inline elements reject. This is part of the CSS spec: floating an element makes it a block container for layout purposes.
Q62: 在网页中的应该使用奇数还是偶数的字体?为什么呢? A: Using even font sizes is recommended for better rendering and layout consistency. Reasons: 1) Sub-pixel rendering - browsers render fonts based on physical device pixels. Even sizes (12px, 14px, 16px) map better to device pixels, resulting in sharper text with less anti-aliasing artifacts. 2) Line-height calculation - even font sizes produce cleaner integer line-height values with common multipliers (1.5x14=21 vs 1.5x13=19.5), reducing rounding inconsistencies. 3) Designer convention - most design systems (Material Design, Ant Design, Bootstrap) use even-based typography scales. 4) Rem/Ems consistency - base font-size (16px) is even, percentage multiples produce cleaner values. However, odd sizes can be appropriate for specific design intentions (creating visual tension, fitting exact pixel measurements).
Q63: ::before 和 :after中双冒号和单冒号 有什么区别?解释一下这2个伪元素的作用 A: Single colon (😃 is the legacy CSS2 syntax for pseudo-classes and pseudo-elements (pre-CSS3): :before, :after, :first-line, :first-letter. Double colon (:😃 is the CSS3 syntax for pseudo-elements only: ::before, ::after, ::first-line, ::first-letter. This distinction separates pseudo-elements (create virtual elements) from pseudo-classes (select states). Modern browsers support both syntaxes for pseudo-elements but :: is the recommended standard. ::before inserts generated content BEFORE the element's actual content; ::after inserts AFTER. Uses: clearfix (.clearfix::after { clear: both; }), decorative icons (::before with font-icons), tooltips, custom checkboxes, quote decorations. Both require content property to render. Custom attributes: content: attr(data-tooltip); counter: content: counter(section); icons: content: "\f007".
Q64: 如果需要手动写动画,你认为最小时间间隔是多久,为什么?(阿里) A: The minimum animation interval for smooth animation (especially with requestAnimationFrame) is approximately 16.67ms (1000ms / 60fps). This corresponds to the standard display refresh rate of 60Hz monitors. The human eye perceives smooth motion at ~60 frames per second. requestAnimationFrame synchronizes with the display's refresh cycle, typically firing every 16.67ms. For 120Hz+ displays (iPad Pro, high-refresh monitors), the interval can be ~8.33ms (120fps) or ~4.17ms (240fps). requestAnimationFrame automatically matches the display's refresh rate - using shorter intervals (setTimeout/setInterval < 16ms) causes unnecessary calculations without visual benefit and can lead to dropped frames and battery drain. The rendering pipeline (style -> layout -> paint -> composite) must complete within this frame budget for jank-free animation.
Q65: CSS合并方法 A: CSS merging combines multiple CSS files into one to reduce HTTP requests (important for HTTP/1.1). Methods: 1) Build tool merging (Webpack/PostCSS/Grunt/Gulp) - concatenates all CSS files into one bundle during build. 2) @import in CSS (not recommended - creates sequential blocking requests). 3) CSS-in-JS solutions (styled-components, Emotion) naturally bundle styles with components. 4) CSS modules + bundler (Webpack CSS loader) produces merged output. 5) Manual concatenation (fragile, not scalable). Modern approach (HTTP/2+): merging is less critical because HTTP/2 multiplexing handles multiple concurrent requests efficiently. Instead of one large file, serve separate files per component/page for better caching granularity (changing one rule doesn't invalidate entire bundle). Code splitting with route-based CSS loading is optimal.
Q66: CSS不同选择器的权重(CSS层叠的规则) A: CSS specificity calculation: inline styles (1000) > IDs (100) > classes/pseudo-classes/attributes (10) > elements/pseudo-elements (1). !important overrides everything (avoid). Tie-breaking: later origin (author > user > user-agent) and later declaration order win at same specificity. Cascade layers (@layer) allow explicit origin ordering. Origin priority: !important user-agent > !important user > !important author > animations > author > user > user-agent. The cascade algorithm: 1) Filter declarations by selector match. 2) Sort by origin/importance. 3) Sort by specificity. 4) Sort by order. Reducing cascade issues: use scoped styles (CSS modules, Shadow DOM), BEM naming, CSS-in-JS.
Q67: 列出你所知道可以改变页面布局的属性 A: Layout-changing CSS properties: display (block/inline/flex/grid/none), position (static/relative/absolute/fixed/sticky), float/clear, width/height (and min/max variants), margin/padding, top/right/bottom/left (positioned elements), transform (translate, rotate, scale - creates new stacking context, affects layout for relative/static), flex properties (flex-direction, flex-wrap, flex-basis, flex-grow, flex-shrink, order), grid properties (grid-template-columns/rows, grid-area, grid-column/row), column-count/column-width (multi-column), box-sizing (affects how dimensions are calculated), writing-mode/direction (affects block flow direction). Modern layout uses flexbox (1D) and grid (2D). Key understanding: some properties trigger reflow (width/height/top/left), others only composite (transform/opacity) - choose accordingly for performance.
Q68: CSS在性能优化方面的实践 A: CSS performance optimization: 1) Simplify selectors - avoid deeply nested selectors (Sass depth > 4). Browsers read selectors right-to-left, so .content .sidebar .item > a span is expensive. 2) Use class selectors over descendant selectors. 3) Avoid expensive properties (box-shadow, border-radius, filter, backdrop-filter cause paint overhead; will-change triggers layer promotion). 4) Minimize reflows - animate only transform and opacity (composite-only). 5) Reduce unused CSS - use PurifyCSS/UnCSS to remove unused styles. 6) Critical CSS inlining - extract above-the-fold CSS and inline in <head>. 7) Code splitting - lazy-load CSS per route/component. 8) contains: layout style paint - scope rendering to individual elements. 9) content-visibility: auto - skip off-screen rendering. 10) Use CSS variables for theme changes instead of multiple property updates.
Q69: CSS3动画(简单动画的实现,如旋转等) A: CSS3 animations use @keyframes rules defining animation states at various points (0%-100%), applied via animation properties. Example: @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }.element { animation: rotate 2s ease-in-out infinite; }. Animation properties: animation-name, animation-duration, animation-timing-function (ease, linear, cubic-bezier), animation-delay, animation-iteration-count (number/infinite), animation-direction (normal/reverse/alternate), animation-fill-mode (none/forwards/backwards/both - controls styles before/after animation), animation-play-state (running/paused). Performance: animate only transform and opacity (composite-only, no layout/paint). Use will-change or translateZ(0) to promote to compositor layer. For simple transitions, prefer CSS transitions over animations. For complex timelines or dynamic changes, consider Web Animations API.
Q70: base64的原理及优缺点 A: Base64 encodes binary data (images, fonts) into ASCII text strings, embeddable directly in CSS/HTML as data URIs: background-image: url('data:image/png;base64,iVBOR...'). Advantages: 1) Fewer HTTP requests - resource embedded in CSS/HTML, no separate fetch. 2) No extra DNS/TLS/connection overhead. 3) Immediate availability when CSS loads - no 'flash of missing image'. Disadvantages: 1) ~33% larger file size than binary original (base64 adds 33% overhead). 2) No browser caching independently - if embedded in CSS, the image is cached as part of CSS; changing the CSS recaches the image. 3) Not shared across pages - each page's CSS has its own copy of the base64 string. 4) CSS/HTML file size increases significantly. Use case: very small images (under 2KB), critical above-the-fold images, icons where HTTP overhead exceeds data savings.
Q71: 几种常见的CSS布局 A: Common CSS layouts: 1) Normal flow - block elements stack vertically, inline horizontally. 2) Float layout - elements floated for multi-column (legacy, text wrapping). 3) Flexbox - 1D layout (row OR column). Perfect for navigation bars, centering, equal-height columns, auto-spacing. 4) CSS Grid - 2D layout (rows AND columns simultaneously). Best for full page layouts, magazines, complex overlapping. 5) Multi-column - text flows into columns like newspaper. 6) Positioning - absolute/fixed/sticky for overlays, tooltips, headers. 7) Table layout (display: table) - vertical centering and equal-width columns (legacy, less flexible). Modern best practice: Flexbox for 1D components (navigation, cards, toolbars); Grid for 2D page layout (header/sidebar/main/footer); combine both for complex layouts.
Q72: 流体布局 A: Fluid layout (liquid layout) uses percentage-based widths instead of fixed pixels, allowing the page to stretch and adapt to different screen widths. Key characteristics: uses relative units (%, vw, vh, em, rem); containers resize proportionally; min-width/max-width prevent extremes (too narrow/wide). Implementation: main container { width: 90%; max-width: 1200px; margin: 0 auto; }; sidebar { width: 30%; }; content { width: 70%; }. Benefits: works across all screen sizes without horizontal scroll. Limitations: doesn't adapt layout structure (columns stay as columns), content may look too stretched or compressed. More advanced than fixed-width, less capable than responsive with media queries. Modern combination: fluid layout + media queries = responsive design.
Q73: 圣杯布局 A: Holy Grail layout: a 3-column layout with header and footer, where the center column is fluid (fills remaining space) and both side columns have fixed widths. The challenge: center content should load first in HTML (for SEO/perceived performance) while appearing between the two sidebars. Implementation (flexbox): .container { display: flex; }. .center { flex: 1; order: 2; }. .left { width: 200px; order: 1; }. .right { width: 200px; order: 3; }. HTML order: center first, left second, right third. Implementation (grid): .container { display: grid; grid-template-columns: 200px 1fr 200px; grid-template-areas: 'left center right'; }. CSS Grid is cleaner - no need for order manipulation. The layout originated from the pre-flexbox era used negative margins with floats.
Q74: 双飞翼布局 A: Double Flying Wing layout is similar to the Holy Grail layout but uses a different technique for the center column. It uses an extra wrapper div inside the center column. Structure: .center (with 100% width, float: left) contains .center-inner (with mx margin equal to sidebars width). .left (float: left, margin-left: -100%) and .right (float: left, margin-left: -width) are positioned using negative margins. Key difference from Holy Grail: Holy Grail uses padding on the container and relative positioning; Double Flying Wing uses nested divs and negative margins without relative positioning, making it cleaner in float-based implementations. Both solve the same problem: three-column layout with fluid center that loads first in HTML. Modern flexbox and grid implementations are simpler and more maintainable.
Q75: stylus/sass/less区别 A: All three are CSS preprocessors extending CSS with variables, nesting, mixins, functions, and logic. Sass: most mature, two syntaxes (.scss and .sass). SCSS syntax is CSS-compatible. Features: variables ($), nesting, mixins (@mixin/@include), functions, control directives (@if/@for/@each), color manipulation, @extend. Compiled with Dart Sass. Less: similar to Sass but JavaScript-based (runs in Node/browser). Uses @ for variables (@var instead of $). Less forgiving with syntax. Simpler than Sass. Stylus: most flexible, indentation-based (like .sass but brackets/colons optional). Very concise syntax. Powerful built-in functions. Less community and tooling support. Modern preference: Sass (SCSS) is the most widely adopted. Dart Sass is the reference implementation. CSS-in-JS and PostCSS are growing alternatives that reduce need for preprocessors.
Q76: postcss的作用 A: PostCSS is a tool for transforming CSS with JavaScript plugins. It uses a plugin architecture where each plugin transforms CSS in some way. NOT a preprocessor (though it can replace one). Processing stages: CSS string -> AST -> plugin transformations -> transformed CSS string. Key plugins: Autoprefixer (adds vendor prefixes), PostCSS Preset Env (enables future CSS today, like nesting, custom media queries), CSS Nano (minification), Stylelint (linting), PostCSS Modules (scoped CSS), PostCSS Import (inlines @import), Tailwind CSS (built on PostCSS). Benefits: modular plugin architecture (use only what you need), faster than Sass (JS-based, no Ruby), ability to use future CSS syntax (CSS Variables, nesting, color functions) now. Build tools (Webpack, Vite) integrate PostCSS by default. Modern approach: PostCSS + a preprocessor (Sass) for maximum flexibility.
Q77: css样式(选择器)的优先级 A: CSS selector specificity (from high to low): 1) !important annotations (overrides all, avoid). 2) Inline styles (style attribute). 3) ID selectors (#header, #sidebar). 4) Class selectors (.nav, .active), pseudo-classes (:hover, :nth-child), attribute selectors ([type="text"]). 5) Element selectors (div, p, span), pseudo-elements (::before, ::after). Universal selector (*) and combinators (>, +, ~) add no specificity. Same specificity: later declaration wins. :is() and :not() pseudo-classes take the specificity of their MOST specific argument. Compound selectors sum specificity. Best practices: keep specificity low and flat (avoid over-qualification: div.nav instead of .nav), use BEM naming to minimize selector nesting, avoid !important. CSS-in-JS avoids specificity wars by scoping styles to components.
Q78: 自定义字体的使用场景 A: Custom fonts (@font-face) are used for brand typography beyond web-safe fonts. Use cases: 1) Brand identity - using the company's custom typeface across the site (e.g., Airbnb's Cereal, GitHub's Mona Sans). 2) Icon fonts - Font Awesome, Material Icons as icon sets (being replaced by SVG). 3) International scripts - fonts for languages not covered by system fonts (CJK, Arabic, Devanagari). 4) Digital publications - variable fonts for reading apps (weight/width axis control). 5) Design systems - consistent typography across all products. Performance: use font-display: swap (FOUT) to prevent invisible text; subset fonts to include only needed characters; preload critical fonts (<link rel="preload" as="font">); self-host fonts vs external services (control vs convenience). Variable fonts reduce file size by storing multiple weights in one file.
Q79: 如何美化CheckBox A: Native checkboxes are difficult to style cross-browser because their appearance is OS-native. Approaches: 1) Hide native checkbox and use label + ::before/::after pseudo-elements for custom appearance. input[type="checkbox"] { position: absolute; opacity: 0; } label::before { content: ''; display: inline-block; width: 20px; height: 20px; border: 2px solid #333; border-radius: 3px; } input:checked + label::before { background: blue; } input:checked + label::after { content: '\2713'; color: white; }. Pseudo-elements can also be styled for :focus, :disabled states. 2) SVG-based - use hidden checkbox + SVG icon swap on :checked. 3) CSS appearance: none - input[type="checkbox"] { appearance: none; -webkit-appearance: none; } then style from scratch (works in modern browsers). 4) Icon font characters. Ensure accessibility: use <label> wrapping, maintain keyboard navigation, include focus styles.
Q80: 伪类和伪元素的区别 A: Pseudo-classes (😃 select elements based on STATE or position, not creating new elements. Examples: :hover (mouse hover), :focus (keyboard focus), :nth-child(n) (position in parent), :first-child, :last-child, :not(selector), :checked (checkbox state), :disabled, :empty, :target (URL fragment matching element id). They filter existing elements based on conditions. Pseudo-elements (:😃 create virtual elements that don't exist in the DOM, allowing styling of specific parts. Examples: ::before (insert content before element), ::after (insert after), ::first-letter (first letter style), ::first-line (first line style), ::selection (user-selected text), ::placeholder (input placeholder), ::marker (list marker). They generate new styled 'elements' from the content. Key distinction: pseudo-classes describe state-based conditions; pseudo-elements create imaginary elements or target sub-parts of existing elements.
Q81: base64的使用 A: Base64 encodes binary data to ASCII for embedding as data URIs in CSS/HTML. Syntax: url('data:image/png;base64,iVBORw0KG...'). Use cases: 1) Small icons (under 2-3KB) to reduce HTTP requests. 2) Critical images that must appear immediately with CSS (avoid separate request). 3) Inline images in emails (single self-contained file). 4) Tiny patterns/backgrounds repeated across elements. 5) Font files as data URIs (rare, large). Best practices: use only for small files (base64 overhead ~33%); NOT suitable for photos or large images; consider inlining in HTML <link> or CSS rather than making separate requests; combine with automated build tools (Webpack url-loader, PostCSS); be aware that embedded resources can't be cached independently or shared across pages. For HTTP/2, the request overhead argument is weaker, making base64 less attractive.
Q82: 自适应布局 A: Responsive/adaptive design makes web pages work across devices of different sizes. Approaches: 1) Fluid/Percentage layout - elements resize proportionally with viewport. 2) Media queries - CSS @media breakpoints (min-width: 768px, 1024px) to change layout structure at specific widths. 3) Flexible images - max-width: 100% to prevent overflow. 4) Viewport meta tag - <meta name="viewport" content="width=device-width, initial-scale=1.0">. 5) CSS Grid/Flexbox - naturally responsive with fr units, auto-fit, auto-fill. Common breakpoints: mobile < 768px, tablet 768-1024px, desktop > 1024px. Design approach: mobile-first (base styles for mobile, media queries for larger screens) vs desktop-first. Mobile-first is recommended: starts with single-column, adds complexity at larger widths. Types: Responsive (fluid, same URL) vs Adaptive (fixed layouts at breakpoints) vs Hybrid.
Q83: 请用CSS写一个简单的幻灯片效果页面 A: CSS-only slideshow using @keyframes animations: HTML: <div class="slideshow"><div class="slides"><img src="1.jpg"><img src="2.jpg"><img src="3.jpg"></div></div>. CSS: .slideshow { width: 600px; height: 400px; overflow: hidden; position: relative; }. .slides { display: flex; width: 300%; animation: slide 9s infinite; }. .slides img { width: 33.333%; }. @keyframes slide { 0%, 25% { transform: translateX(0); } 33%, 58% { transform: translateX(-33.333%); } 66%, 91% { transform: translateX(-66.666%); } 100% { transform: translateX(0); } }. Key: animation pauses at each image (using % ranges) then transitions to next. Enhancement: add animation-play-state: paused on .slideshow:hover for hover control; navigation dots with opacity transition; autoplay with manual control using checkbox hack. Limitations: CSS-only cannot dynamically add slides or handle swipe events. For interactive slideshows, use JS.
Q84: 什么是外边距重叠?重叠的结果是什么? A: Margin collapsing (collapsing margins) occurs when vertical margins of adjacent block elements overlap, combining into a single margin equal to the LARGER of the two margins (not their sum). Cases: 1) Adjacent siblings - bottom margin of first + top margin of second collapse. 2) Parent and first/last child - top margin of first child collapses with parent's top margin; bottom margin of last child with parent's bottom margin. 3) Empty blocks - all three margins (top, bottom, and auto height) collapse into one. When margins collapse: the resulting margin = max(margin1, margin2). Negative margins: max of positive + min of negative (can cancel out). Prevention: add border/padding between margins, create BFC (overflow: hidden, display: flow-root), use flexbox/grid (don't collapse), or use padding instead of margin. Horizontal margins NEVER collapse (only vertical in normal flow).
Q85: rgba()和opacity的透明效果有什么不同? A: rgba() and opacity both create transparency but affect different elements. opacity: affects the ENTIRE element including ALL its children and their backgrounds, borders, text. The whole subtree becomes transparent together (children cannot be MORE opaque than parent). This creates a flattening effect where descendant elements' transparency is capped by ancestor opacity. triggering a new stacking context (z-index behavior changes). rgba(): affects only the SPECIFIC PROPERTY it's applied to (color, background-color, border-color, etc.). Children are NOT affected - they inherit color values normally (which may include alpha values). Example: background: rgba(0,0,0,0.5) makes only the background semi-transparent; text remains fully opaque. Related: hsla() works like rgba() with Hue-Saturation-Lightness color model. Use opacity for whole-element fades; use rgba/hsla for targeted property transparency.
Q86: css中可以让文字在垂直和水平方向上重叠的两个属性是什么? A: Properties causing text overlap vertically and horizontally: 1) letter-spacing (horizontal) - controls space between characters. Large negative values cause characters to overlap: letter-spacing: -5px. 2) line-height (vertical) - controls height of text line. Smaller than font-size with overflow: hidden causes vertical overlap: line-height: 0.8; overflow: hidden. 3) Negative margin - margin-top: -20px pulls the element (and its text) up to overlap previous content. 4) Transform - transform: scale(2) makes text larger, potentially overlapping neighbors. 5) Position with negative offset - position: relative; top: -20px moves text up. 6) text-shadow can create overlapping visual effects. 7) white-space: nowrap combined with overflow: hidden makes text horizontally clipped. Intended overlap uses: stacked text effects, decorative drop caps, overlapping headlines.
Q87: 如何垂直居中一个浮动元素? A: Vertical centering of floating elements: 1) Flexbox (preferred): .container { display: flex; align-items: center; justify-content: center; }.float-element { } - flexbox on parent overrides float behavior. 2) Transform: .parent { position: relative; }.child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } - works regardless of width/height. 3) Inline-block + line-height: .parent { text-align: center; line-height: height; }.child { display: inline-block; vertical-align: middle; line-height: 1.2; } - hacky, requires known parent height. 4) Table-cell: .parent { display: table-cell; vertical-align: middle; text-align: center; }. 5) CSS Grid: .parent { display: grid; place-items: center; }. Best practice: use flexbox or CSS grid for centering - they handle unknown dimensions, are widely supported, and don't break document flow like absolute positioning.
Q88: px和em的区别 A: px (pixel): absolute unit, 1 CSS pixel = 1/96th of an inch (logical pixel, not physical device pixel). Fixed size, does not scale with user's font size preferences. Predictable and precise. em: relative unit, relative to the PARENT element's font-size. If parent is 16px, 1em = 16px for child. Nested elements compound: child in em-based parent gets smaller/larger. Used for spacing that should scale with text. rem (root em): relative to the ROOT element's (html) font-size. Avoids compounding issue. Default: 1rem = 16px (browser default). Modern approach: use rem for font sizes and spacing (accessibility - respects user's browser font-size setting), use px for borders, shadows, and small fixed elements. Avoid em for complex nesting. Percentage for layout widths. vw/vh for viewport-relative sizing.
Q89: Sass、LESS是什么?大家为什么要使用他们? A: Sass (Syntactically Awesome Style Sheets) and LESS (Leaner Style Sheets) are CSS preprocessors extending CSS with features not natively available. They compile to regular CSS. Why use them: 1) Variables - store colors, fonts, spacing values for consistent theming. 2) Nesting - mirror HTML structure, reducing repetitive selectors. 3) Mixins - reusable style blocks with parameters (like functions). 4) Functions - color manipulation (darken/lighten), math operations. 5) Partials and @import - modular CSS file organization. 6) Loops and conditionals - generate repetitive styles programmatically. 7) Extend/Inheritance - share rule sets. Sass (SCSS) is more popular with Dart Sass compiler. LESS is JS-based, simpler but less powerful. Modern shift: CSS now has native variables (custom properties), nesting (draft spec), color functions. PostCSS + future CSS plugins reduce need for preprocessors.
Q90: 知道css有个content属性吗?有什么作用?有什么应用? A: The CSS content property is used with ::before and ::after pseudo-elements to insert generated content. Without content (value other than none), the pseudo-element won't render. Values: string: content: "prefix: ";; attr(): content: attr(data-tooltip); - reads element's attribute value. url(): content: url(icon.svg); - inserts an image. counter(): content: counter(section); - auto-numbering. open-quote/close-quote: content: open-quote; - automatic quotation marks. none/normal: suppresses pseudo-element. Applications: 1) Clearfix: .clearfix::after { content: ''; display: table; clear: both; }. 2) Icon insertion: .icon::before { content: '\f007'; font-family: 'FontAwesome'; }. 3) Tooltips: content: attr(data-tip);. 4) Auto-numbering headings/sections with counter(). 5) Custom list markers: li::before { content: '>> '; }. 6) Decorative elements (shapes, dividers).
Q91: 水平居中的方法 A: Horizontal centering methods: 1) Inline/inline-block + text-align: .parent { text-align: center; }.child { display: inline-block; } - works for inline/inline-block children. 2) Block + auto margins: .child { width: fit-content; margin: 0 auto; } - requires width to be set (or fit-content for auto-width). 3) Flexbox: .parent { display: flex; justify-content: center; } - best for modern browsers. 4) CSS Grid: .parent { display: grid; justify-items: center; } or .parent { display: grid; } .child { justify-self: center; }. 5) Absolute + transform: .parent { position: relative; }.child { position: absolute; left: 50%; transform: translateX(-50%); } - works with unknown width. 6) Table: .parent { display: table; margin: 0 auto; } or .parent { text-align: center; display: table-cell; }. Flexbox is recommended for simplicity and flexibility.
Q92: 垂直居中的方法 A: Vertical centering methods: 1) Flexbox: .parent { display: flex; align-items: center; } - simplest, works for single/multiple elements. Combine with justify-content: center for both axes. 2) CSS Grid: .parent { display: grid; align-items: center; } or .parent { display: grid; } .child { align-self: center; }. place-items: center for both axes. 3) Absolute positioning + transform: .parent { position: relative; }.child { position: absolute; top: 50%; transform: translateY(-50%); } - works with unknown height. 4) Absolute positioning + margin: auto: .child { position: absolute; top: 0; bottom: 0; margin: auto 0; height: 100px; } - requires known height. 5) Table-cell: .parent { display: table-cell; vertical-align: middle; } - legacy approach. 6) Line-height: .parent { height: 100px; line-height: 100px; }.child { display: inline-block; vertical-align: middle; line-height: 1.2; } - single line text or inline-block children. Flexbox is the most flexible and widely recommended approach.
Q93: 如何使用CSS实现硬件加速? A: CSS hardware acceleration uses the GPU (graphics processing unit) for rendering, offloading from the CPU. Triggers: 1) will-change: transform/opacity - hints browser to create compositor layer. 2) transform: translateZ(0) / translate3d(0,0,0) - forces 3D acceleration (older hack, less needed today). 3) transform: rotateX(0) / scaleZ(1) - 3D transforms in general. 4) opacity animations. 5) filter: blur()/drop-shadow() - can't be GPU-accelerated on CPU. How it works: GPU-accelerated elements are promoted to their own compositing layer (like a separate texture). The CPU only sends the initial layer content, then the GPU composites layers together. Animations of transform/opacity don't trigger layout or paint - just compositing. Benefits: smooth 60fps animations, reduced CPU load. Pitfalls: excessive layers consume GPU memory (especially on mobile), creating layers for thousands of elements causes memory pressure. Use will-change sparingly, only on elements that will animate.
Q94: 重绘和回流(重排)是什么,如何避免? A: Reflow (layout): recalculating element positions and dimensions when DOM geometry changes. Occurs when: adding/removing visible elements; changing width/height/margin/padding; changing font-size; window resize; activating CSS pseudo-class (:hover). Triggers recalculation of all descendant and ancestor elements' geometry. Expensive: affects the entire render tree or large subtrees. Repaint: redrawing pixels when visual changes don't affect layout (color, background-color, visibility, outline). Less expensive than reflow but still costs GPU/CPU. Composite: merging pre-drawn layers together. Cheapest operation (only GPU work). Avoid reflow/repaint: 1) Use transform instead of top/left for position changes. 2) Use opacity instead of visibility/display for show/hide. 3) Batch DOM reads/writes (read first, write later, or use requestAnimationFrame). 4) Use DocumentFragment for batch DOM insertions. 5) Cache layout properties (offsetTop, scrollHeight) by reading once. 6) Use will-change for upcoming animations.
Q95: 说一说css3的animation A: CSS3 animation consists of @keyframes defining animation states at progress points (0%-100% or from-to), applied via animation shorthand. Properties: animation-name (keyframes name), animation-duration (time), animation-timing-function (ease/linear/cubic-bezier(...)), animation-delay (time before start), animation-iteration-count (number/infinite), animation-direction (normal/reverse/alternate/alternate-reverse), animation-fill-mode (none/forwards/backwards/both - determines styles before/after), animation-play-state (running/paused - useful for hover controls). Example: @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.2); opacity: 0.7; } 100% { transform: scale(1); opacity: 1; } }.element { animation: pulse 2s ease-in-out infinite; }. Performance: animate only transform and opacity for GPU-composited smooth animations. Use will-change on animated elements. Prefer CSS animation over JS-driven for simple declarative sequences.
Q96: 左边宽度固定,右边自适应 A: Fixed left + right adaptive layout: 1) Flexbox (simplest): .container { display: flex; }.left { width: 200px; flex-shrink: 0; }.right { flex: 1; }. The right fills remaining space. 2) CSS Grid: .container { display: grid; grid-template-columns: 200px 1fr; }. 3) Float + BFC: .left { float: left; width: 200px; }.right { overflow: hidden; } - overflow: hidden creates BFC, preventing wrapping. 4) Absolute positioning: .container { position: relative; }.left { position: absolute; left: 0; width: 200px; }.right { margin-left: 200px; } - but right height doesn't auto-match left. 5) Calc: .right { width: calc(100% - 200px); margin-left: 200px; } - if both are floated. Flexbox and Grid are recommended for clarity and flexibility. For multi-row layouts, Grid is superior.
Q97: 两种以上方式实现已知或者未知宽度的垂直水平居中 A: Both axes centering with known/unknown dimensions: 1) Flexbox (unknown, simplest): .parent { display: flex; justify-content: center; align-items: center; }. 2) CSS Grid: .parent { display: grid; place-items: center; }. 3) Absolute + transform (unknown dimensions): .parent { position: relative; }.child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }. 4) Absolute + margin: auto (known dimensions): .child { position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; width: 200px; height: 100px; }. 5) Table-cell: .parent { display: table-cell; vertical-align: middle; text-align: center; }.child { display: inline-block; }. 6) Inline-block + line-height: .parent { text-align: center; line-height: height; }.child { display: inline-block; vertical-align: middle; line-height: 1.2; }. Flexbox is recommended: simplest syntax, handles any dimension, multiple children, no absolute positioning issues.
Q98: 如何实现小于12px的字体效果 A: Browsers (especially Chrome) enforce a minimum font-size of 12px (the default minimum for readability). To display fonts smaller than 12px: 1) transform: scale(): .small-text { font-size: 12px; transform: scale(0.5); transform-origin: left; } - reduces visual size to 6px. Note: the element still occupies its original space (use negative margin or width: 200% to compensate). 2) Non-CSS workaround - prepare images of small text (bad for accessibility, maintenance). 3) zoom property (non-standard): .small-text { zoom: 0.5; } - works in IE/Chrome. 4) SVG text - SVG text elements render at exact specified font-size regardless of browser minimum. 5) Canvas text - similar to SVG, renders at any size. 6) Browser settings override - Chrome's minimum font-size can be changed in settings (chrome://settings/fonts). Users can set to 0. Transform: scale() is the most practical CSS solution.
Q99: css hack原理及常用hack A: CSS hacks exploit browser-specific CSS parsing bugs/quirks to apply styles conditionally to specific browsers (mostly legacy IE). Types: 1) Conditional comments (HTML, IE-specific): <!--[if IE]><link rel="stylesheet" href="ie.css"><![endif]-->. 2) Underscore/star hacks (IE6/7): .element { _color: red; } /* IE6 */; color: red; / IE7 /. 3) Property-value hacks: .element { color: red\9; } / IE8-10 /; color: red\0; / IE8+ */. 4) Selector hacks: html .element {} / IE6 /; :root .element {} / IE9+ /. 5) @media hacks: @media screen\0 { } / IE8-10 */. Modern approach: avoid CSS hacks entirely. Use feature detection (Modernizr, @supports), progressive enhancement, vendor prefixes via Autoprefixer. Hacks make code fragile, unmaintainable, and fail in unexpected ways. For legacy IE, use conditional comments to serve separate stylesheets.
Q100: CSS有哪些继承属性 A: CSS inherited properties (children automatically get parent's value unless overridden): 1) Text: color, font-family, font-size, font-weight, font-style, font-variant, font-stretch, letter-spacing, line-height, text-align, text-indent, text-transform, word-spacing, white-space, word-break, word-wrap. 2) Visibility: visibility, cursor. 3) List: list-style, list-style-type, list-style-position, list-style-image. 4) Table: border-collapse, border-spacing, caption-side, empty-cells. 5) Others: direction, quotes, writing-mode, hyphens, orphans, widows. NOT inherited: 1) Box model: width, height, margin, padding, border, display, box-sizing. 2) Background: background, background-color, background-image etc. 3) Positioning: position, top, left, right, bottom, z-index, overflow, float, clear. 4) Generated: content. 5) Others: outline, text-decoration. inherit keyword forces inheritance; initial resets to browser default; unset = inherit if property inherits, else initial.
Q101: 外边距折叠(collapsing margins) A: See Q84. Margin collapsing is when vertical margins of adjacent block elements combine into a single margin equal to the larger value. Three scenarios: 1) Adjacent siblings - element's bottom margin collapses with next element's top margin. Result = max(margin-bottom, margin-top). 2) Parent-first/last child - parent's top margin collapses with first child's top margin. Prevention: border/padding on parent, overflow: hidden, BFC creation. 3) Empty blocks - all margins (top, bottom) collapse into one. Complex cases: negative margins, max of positive + min of negative; nested collapsing (multiple levels of nested elements can result in margins collapsing through). IMPORTANT: Horizontal margins NEVER collapse. Only block elements in normal flow collapse (not floated, positioned, inline-block, flex/grid items). Using padding instead of margins on container elements avoids collapse issues entirely.
Q102: CSS选择符有哪些?哪些属性可以继承 A: CSS selectors: 1) Element/Type: div, p, span. 2) Class: .classname. 3) ID: #idname. 4) Universal: * (all elements). 5) Attribute: [attr], [attr=val], [attr^=val], [attr$=val], [attr*=val], [attr~=val], [attr|=val]. 6) Pseudo-class: :hover, :focus, :nth-child(n), :first-child, :last-child, :not(sel), :checked, :enabled, :disabled, :target, :empty, :root. 7) Pseudo-element: ::before, ::after, ::first-line, ::first-letter, ::selection, ::placeholder. 8) Combinators: descendant (div p), child (div > p), adjacent sibling (div + p), general sibling (div ~ p), column (div || p). Inherited properties: color, font-family, font-size, font-style, font-weight, font-variant, font-stretch, letter-spacing, line-height, text-align, text-indent, text-transform, visibility, cursor, list-style, quotes, direction, empty-cells, border-collapse, hyphens, orphans, widows, white-space, word-spacing, writing-mode.
Q103: CSS3新增伪类有那些 A: CSS3 pseudo-classes: 1) Structural: :nth-child(n), :nth-last-child(n), :nth-of-type(n), :nth-last-of-type(n), :first-child, :last-child, :first-of-type, :last-of-type, :only-child, :only-of-type, :empty, :root. 2) UI state: :checked, :disabled, :enabled, :default, :indeterminate, :valid, :invalid, :in-range, :out-of-range, :required, :optional, :read-only, :read-write. 3) Negation: :not(selector) - selects elements NOT matching the argument. 4) Target: :target - matches element whose ID matches URL fragment (#section). 5) Negation: :not() in CSS3 only supports simple selectors. 6) Other: :first-letter and :first-line (were pseudo-elements, still :: in CSS3). nth-child(an+b): matches every element whose position in a group equals an+b (e.g., :nth-child(3n+1) selects every 3rd starting from 1st). odd/even are shorthand for 2n+1/2n. of-type variants are similar but consider only siblings of same element type (tag name).
Q104: 如何居中div?如何居中一个浮动元素?如何让绝对定位的div居中 A: Div centering: 1) margin: 0 auto; (block with width). 2) display: flex; justify-content: center; align-items: center;. Floating element centering: 1) For horizontal, wrap in container with width: 100%; float: left; then position relative+left: 50%, child right: 50%. Better: 2) Wrap container display: flex; justify-content: center; (float ignored in flex). 3) Absolute positioning of floated element (float ignored when absolute). Absolute positioned div centering: 1) .parent { position: relative; } .child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } - no known dimensions. 2) .child { position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; width: 200px; height: 100px; } - known dimensions. 3) CSS Grid: .parent { display: grid; place-items: center; } .child { position: absolute; } - works but grid controls the alignment.
Q105: 用纯CSS创建一个三角形的原理是什么 A: CSS triangle uses borders. An element with zero width/height and thick transparent borders on three sides, with one side's border colored: .triangle { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid red; } creates an upward-pointing triangle. Why it works: when border meets at a corner and the element has no content, each border edge forms a triangle. With zero width/height, each border occupies a triangular area. Making three borders transparent creates a single visible triangle. Variations: equilateral (border-width ratio), right triangle (unequal borders), pointing direction (different border colored), speech bubble (with ::before/::after). Border-color: transparent for hidden sides. Practical: avoid CSS triangles in modern design; prefer SVG (scalable, more maintainable, better for accessibility).
Q106: 一个满屏 品 字布局 如何设计? A: "品" (pin) layout: top section spans full width, bottom row split into two equal halves. Implementation with CSS Grid: .container { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 10px; height: 100vh; }.top { grid-column: 1 / -1; }.bottom-left { }.bottom-right { }. With Flexbox: .container { display: flex; flex-direction: column; height: 100vh; }.top { flex: 1; }.bottom-row { display: flex; flex: 1; }.bottom-row > div { flex: 1; }. With float: .top { width: 100%; height: 50%; }.bottom-left, .bottom-right { width: 50%; height: 50%; float: left; }. Grid provides the most semantic and concise approach. Ensure: full viewport height (100vh), no overflow, consistent gap. For responsiveness, adjust at breakpoints to stack vertically.
Q107: li与li之间有看不见的空白间隔是什么原因引起的?有什么解决办法 A: The gap between li elements is caused by whitespace (line breaks, spaces) in HTML between the </li> and <li> tags. When li has display: inline-block (old horizontal nav technique), whitespace collapses into a single space (~4px depending on font-size). Solutions: 1) Remove whitespace in HTML: <li>a</li><li>b</li> (no newline). 2) font-size: 0 on parent ul, reset on li children (space character has zero width). 3) Use flexbox: ul { display: flex; } - flex items ignore whitespace. 4) Negative margin: li { margin-right: -4px; } - fragile, depends on font. 5) HTML comment between tags: <li>a</li><!-- --><li>b</li>. Best: use flexbox for horizontal lists. If inline-block is required (legacy), use font-size: 0 on parent. This gap also occurs with img, span, and any inline-block elements.
Q108: 请列举几种隐藏元素的方法 A: Element hiding methods with key differences: 1) display: none - removed from render tree, no space, not accessible, triggers reflow. 2) visibility: hidden - visually hidden, space remains, accessible to screen readers (needs aria-hidden="true" for AT), triggers repaint only. 3) opacity: 0 - visually transparent, space remains, still interactive (click events fire!) unless pointer-events: none. Animatable - can transition. 4) position: absolute + off-screen: position: absolute; left: -9999px; top: -9999px; - visually off-screen, still in render tree, accessible (text hidden this way is read by screen readers). 5) clip-path: clip-path: circle(0); - visually clipped to nothing. Space may remain. 6) transform: scale(0) / translate(-9999px) - visual hidden, space may remain. 7) width: 0; height: 0; overflow: hidden - zero dimensions, hidden overflow. 8) <hidden> HTML attribute: <div hidden> - built-in browser hidden state (same as display: none).
Q109: rgba() 和 opacity 的透明效果有什么不同 A: See Q85. opacity affects the ENTIRE element and all its children (creating a single combined transparency surface). Children cannot be more opaque than their parent. Creates a new stacking context (affects z-index behavior). Cannot be applied selectively to backgrounds only. rgba() applies transparency to a SINGLE PROPERTY (background-color, color, border-color, etc.) without affecting other properties or children. Text inside an element with rgba background remains fully opaque. rgba background with opacity: 1 is a common technique for semi-transparent overlays without affecting text readability. Use rgba when: you want transparency on a specific property (background only, or text only). Use opacity when: you want the entire element including all children to fade together (common for fade-in animations, hover effects, disabled states).
Q110: css 属性 content 有什么作用 A: See Q90. content property works with ::before/::after pseudo-elements to insert generated content. Required for pseudo-elements to render (value other than none/normal). Values: string: content: "Hello";; attr(): content: attr(data-custom); - reads attribute value; url(): content: url(/icon.svg); - image; counter(): content: counter(my-counter); - auto-numbering; open-quote/close-quote: content: open-quote; - automatic quotes. Common applications: clearfix hack (content: ''; display: table; clear: both), font icons (content: '\f007'; font-family: FontAwesome), custom bullets (li::before { content: '> '; }), attribute-based tooltips (content: attr(data-tip)), heading numbering (counter-increment + content). Accessibility: inserted content may not be read by all screen readers - don't use for critical information.
Q111: 请解释一下 CSS3 的 Flexbox(弹性盒布局模型)以及适用场景 A: Flexbox is a 1D CSS layout model that distributes space and aligns content within a container. Key properties: container: display: flex; flex-direction (row/column - main axis direction); flex-wrap (nowrap/wrap/wrap-reverse); justify-content (main axis alignment: flex-start/center/flex-end/space-between/space-around/space-evenly); align-items (cross axis alignment: stretch/center/flex-start/flex-end/baseline); align-content (multi-line cross axis distribution); gap (spacing between items). Item: flex (shorthand for flex-grow flex-shrink flex-basis); align-self (override align-items); order (reorder visually). Use Flexbox for: navigation bars, card grids, centering, equal-height columns, form layouts, any 1D arrangement. NOT for: full page 2D layouts (use Grid). Flexbox is one-dimensional - deals with row OR column at a time. The flex algorithm distributes remaining space according to flex-grow factors.
Q112: 经常遇到的浏览器的JS兼容性有哪些?解决方法是什么 A: Common browser JS compatibility issues (mostly legacy IE): 1) addEventListener vs attachEvent - IE < 9 uses attachEvent. Solution: feature detection wrapper. 2) event object - IE uses window.event, target vs srcElement. Solution: event = event || window.event; target = event.target || event.srcElement. 3) preventDefault vs returnValue - IE uses event.returnValue = false. 4) stopPropagation vs cancelBubble - IE uses cancelBubble = true. 5) XMLHttpRequest - IE < 7 uses ActiveXObject. 6) getElementsByClassName - IE < 9 doesn't support. 7) Array methods (forEach, map, filter) - IE < 9 missing. Polyfill or use Babel. 8) CSS property prefixes - -webkit-, -moz-, -ms-, -o- per browser. Use Autoprefixer. Modern approach: transpile with Babel (target specific browsers via browserslist), use polyfills (core-js, polyfill.io), avoid deprecated APIs. Modern browsers (Chrome, Firefox, Safari, Edge) have good ES6+ support.
Q113: 请写出多种等高布局 A: Equal height columns (same height regardless of content): 1) Flexbox: .container { display: flex; }.column { flex: 1; } - all columns automatically same height (align-items default: stretch). 2) CSS Grid: .container { display: grid; grid-template-columns: 1fr 1fr 1fr; } - grid items equal height by default. 3) Table-cell: .container { display: table; width: 100%; }.column { display: table-cell; } - equal height by table behavior (legacy, less flexible). 4) Padding + negative margin (pretend equal): .column { padding-bottom: 9999px; margin-bottom: -9999px; }.container { overflow: hidden; } - visually appears equal height but each column's actual height is its content. 5) display: inline-block + line-height: hacky, not recommended. Modern recommendation: Flexbox for 1D, Grid for 2D. Both provide true equal-height layout without hacks.
Q114: 浮动元素引起的问题 A: Floating element issues: 1) Parent height collapse - floated children don't contribute to parent's height (parent height = 0). Fix: clearfix or overflow: hidden (creates BFC). 2) Float drop - not enough container width pushes last float to next line. Fix: use percentage widths, flex-wrap, or ensure enough space. 3) Text/inline content wrapping - content flows around floated elements, which may be desired (text wrapping) or unwanted. Fix: clear: both or overflow: hidden on content. 4) Consecutive float stacking order - not possible to vertically center floats. 5) Negative margin behavior - interacts complexly with floats. 6) IE6/7 double margin bug on floated elements with same direction margin as float (IE-specific). Modern approach: avoid floats for layout. Use flexbox (1D) or grid (2D). Reserve floats for their original purpose: text wrapping around images.
Q115: CSS优化、提高性能的方法有哪些 A: CSS optimization methods: 1) Reduce file size - minify (CSSNano), remove unused CSS (PurifyCSS/UnCSS), combine files (HTTP/1.1). 2) Loading strategy - inline critical CSS, defer non-critical CSS, use <link rel="preload"> for important CSS, avoid @import (blocks parallel downloads). 3) Selector optimization - avoid deep nesting, use class selectors over descendant chains (browser reads right-to-left). 4) Reduce reflows - minimize repaint-heavy properties (box-shadow, border-radius, filter), use transform/opacity for animations. 5) Containment - use contain: layout style paint to scope rendering to sub-trees. 6) content-visibility: auto on below-fold sections to defer rendering. 7) Asset optimization - compress images, use data URIs sparingly (base64 increases size), sprite small icons. 8) Use SVG over icon fonts for icons (better scaling, smaller subsets).
Q116: 浏览器是怎样解析CSS选择器的 A: Browsers parse CSS selectors RIGHT-TO-LEFT (bottom-up), not left-to-right as intuitively read. Example: .sidebar .nav a - browser first matches all <a> elements, then checks if they have an ancestor with class .nav, then checks if .nav has ancestor with .sidebar. Why right-to-left? It's more efficient for the browser. Starting from the key selector (the rightmost part) limits the candidate set. With left-to-right, the engine would need to traverse every .sidebar, then .nav, then all <a> inside - potentially many elements that don't match the final selector. With right-to-left, it finds <a> elements first (usually fewer candidates), then filters by ancestry. Performance implication: the rightmost selector should be as specific as possible. * or tag name on right is slower than class or id. The more specific the key selector, the faster the match.
Q117: 在网页中的应该使用奇数还是偶数的字体 A: See Q62. Even font sizes (12px, 14px, 16px) are recommended. Reasons: 1) Better sub-pixel rendering - even sizes align better with device pixel grids, reducing anti-aliasing artifacts. 2) Line-height consistency - common multipliers (1.5x14=21 vs 1.5x13=19.5) produce cleaner values. 3) Design system convention - most design systems use even-based typographic scales (Material Design, Bootstrap). 4) Readability consistency - odd sizes may render inconsistently across browsers. However, odd sizes are not prohibited and can be used intentionally for precise design requirements. The key is consistency: use a modular typographic scale for harmonious sizing, whether based on even or odd base increments.
Q118: margin和padding分别适合什么场景使用 A: Padding is INSIDE the element's border, between content and border. Margin is OUTSIDE the border, between the element's border and adjacent elements. Use padding when: 1) Adding space between content and its container (button padding, card padding). 2) Creating click/visual area around text (larger click target for links). 3) Adding background/color area extension (padding keeps background visible). 4) Separating content within the same element. Use margin when: 1) Spacing between separate elements (gap between cards, sections). 2) Centering block elements (margin: 0 auto). 3) Pushing elements away from each other. 4) Creating visual separation between unrelated components. Rendering: padding respects background and border; margin is always transparent. Margin collapses (vertical), padding doesn't. padding affects box-sizing: border-box dimensions; margin doesn't change element size (just position).
Q119: 抽离样式模块怎么写,说出思路 A: Style module extraction (modular CSS) organizes styles for reusability and maintainability. Approach: 1) Base/Reset layer - normalize global defaults, box-sizing, root font-size. 2) Utility classes - single-purpose classes (text-center, mt-4, flex, hidden). Tailwind or custom. 3) Component styles - styles scoped to a specific component (Card, Button, Modal). Use CSS modules, BEM naming, or CSS-in-JS. 4) Layout styles - grid/flexbox page skeletons, responsive breakpoints. 5) Theme tokens - CSS custom properties for colors, spacing, typography, shadows. Organization: by feature/component, not by type (avoid separate files for 'buttons' or 'text'). File structure: each component has its own .module.css file. Build: PostCSS + CSS modules + autoprefixer + minification. Namespace with BEM (Block__Element--Modifier) for global styles, or auto-scoped with CSS modules. Benefits: no style conflicts, tree-shakeable, clear dependencies, easier debugging.
Q120: 元素竖向的百分比设定是相对于容器的高度吗 A: Generally NO. Vertical percentage values (padding-top, padding-bottom, margin-top, margin-bottom, top, bottom) are calculated relative to the WIDTH of the containing block (not the height). This counter-intuitive behavior exists because CSS layout typically determines height based on content, so using height for percentage reference would create circular dependencies. Exception: height property percentage IS relative to the parent element's height (when parent has an explicit height). If parent height is auto (content-based), percentage height behaves like auto. min-height/max-height also require explicit parent height for percentage. padding-top/bottom percentage: always relative to CONTAINING BLOCK's WIDTH. This is exploited for aspect-ratio boxes (padding-top: 56.25% for 16:9). For modern aspect ratio: use aspect-ratio property.
Q121: 全屏滚动的原理是什么? 用到了CSS的那些属性 A: Full-screen scrolling (fullpage.js style) captures scroll events to snap between full-viewport sections. CSS properties used: 1) scroll-snap-type/s-scroll-snap-align - native CSS scroll snapping: .container { scroll-snap-type: y mandatory; overflow-y: scroll; height: 100vh; }.section { scroll-snap-align: start; height: 100vh; }. 2) height: 100vh - sections fill viewport. 3) overflow: hidden on body to prevent native scroll. 4) transform: translateY for transitions between sections (JS-driven). 5) will-change: transform on sections for GPU acceleration. JS implementation: listen to wheel/touch events, calculate scroll direction, animate section transform (translateY) with requestAnimationFrame or CSS transitions. Debounce/throttle events to prevent multi-section skips. Performance: use transform for smooth GPU-composited scrolling; avoid layout-triggering properties. Accessibility: provide skip navigation, keyboard support (arrow keys), proper ARIA landmarks.
Q122: 什么是响应式设计?响应式设计的基本原理是什么?如何兼容低版本的IE A: Responsive design adapts page layout and content to different screen sizes/device capabilities. Principles: 1) Fluid grids - relative units (%, fr, vw) instead of fixed px. 2) Flexible images - max-width: 100% to prevent overflow. 3) Media queries - @media (min-width: breakpoint) { } to change layout at specific widths. 4) Mobile-first CSS - base styles for mobile, progressive enhancement at larger breakpoints. Breakpoints: content-based (not device-based): write media queries at widths where content breaks. Common breakpoints: 480px, 768px, 1024px, 1200px. IE compatibility: use respond.js polyfill for media query support in IE8-9; use html5shiv for HTML5 elements. Modern approach: use CSS Grid auto-fill/auto-fit for responsive layouts without media queries: grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)). Flexbox wrap: flex-wrap: wrap with flex-basis for responsive components.
Q123: 什么是视差滚动效果,如何给每页做不同的动画 A: Parallax scrolling creates an illusion of depth by moving background and foreground content at different speeds during scroll. CSS implementation: background-attachment: fixed - backgrounds appear stationary while content scrolls over them. Combined with multiple background layers with different animations. JS implementation (more controllable): listen to scroll events, calculate scroll progress (scrollTop / (scrollHeight - viewportHeight)), use requestAnimationFrame to adjust element transforms based on depth factor (e.g., transform: translateY(scrollTop * 0.5) for slow-moving background). z-index layering: element depth determines scroll speed (deeper = slower). Performance: use transform for GPU compositing; debounce scroll handlers; use Intersection Observer for triggering parallax on visible elements. Warning: parallax on mobile can cause jank and battery drain. Consider disabling on mobile or using simpler effects.
Q124: a标签上四个伪类的执行顺序是怎么样的 A: a tag pseudo-class order: :link -> :visited -> :hover -> :active. Mnemonic: LoVe-HA (Love-Hate). 🔗 unvisited link. :visited: already visited link (restricted styles - only color, background-color, border-color due to privacy). :hover: mouse hovering over link. :active: link being clicked (moment between mousedown and mouseup). If order is wrong (e.g., :active before :hover), the previous state's specificity equals current, and cascade order applies (later overrides). Since :active typically comes after :hover, if incorrectly ordered, :active may be hidden by :hover style. Focus state (:focus) should be included for keyboard accessibility: :focus-visible modern, :focus legacy. Placement of :focus: after :hover and :active, or consider using :focus-visible to show focus only on keyboard navigation. All selectors at same specificity; order matters.
Q125: 伪元素和伪类的区别和作用 A: See Q80. Pseudo-classes (single colon 😃 select elements based on state or position without modifying the DOM. Examples: :hover (hover state), :focus (focus state), :nth-child(n) (position), :first-child, :last-child, :not(sel), :checked, :disabled, :empty. They filter existing elements. Pseudo-elements (double colon :😃 create virtual elements or target parts of an element that don't exist in DOM. Examples: ::before (inserts content before element), ::after (inserts after), ::first-letter (first character styling), ::first-line (first line styling), ::selection (selected text styling), ::placeholder (input placeholder). ::before and ::after require content property to render. Pseudo-elements cannot use pseudo-elements (no ::before::after). Multiple pseudo-elements can be used but some elements can't have ::before/::after (replaced elements like <img>, <input>, <select>, <textarea>).
Q126: ::before 和 :after 中双冒号和单冒号有什么区别 A: See Q63. Single colon (😃 is CSS2 syntax for both pseudo-classes AND pseudo-elements. Double colon (:😃 is CSS3+ syntax reserved for pseudo-elements only. The separation clarifies: pseudo-classes = states/conditions of existing elements; pseudo-elements = generated virtual elements or targeted sub-parts. Modern browsers accept both :before and ::before for backward compatibility, but :: is the official standard. Examples: ::before, ::after, ::first-line, ::first-letter, ::selection, ::placeholder, ::marker, ::backdrop. The distinction helps avoid confusion between :hover (a state) and ::after (a generated element).
Q127: 如何修改Chrome记住密码后自动填充表单的黄色背景 A: Chrome autofill applies a yellow background to form fields, overriding user styles (user-agent stylesheet with !important). Solutions: 1) Use CSS box-shadow inset to simulate background (works because Chrome doesn't override box-shadow): input:-webkit-autofill { -webkit-box-shadow: 0 0 0 30px white inset !important; } 2) Transition trick - set a long transition on background-color: input:-webkit-autofill { transition: background-color 9999s ease-in-out 0s; } - delays the background change indefinitely. 3) Set autofill background via -webkit-autofill pseudo-class with important: input:-webkit-autofill { -webkit-text-fill-color: #333 !important; background-color: #fff !important; }. Chrome's autofill behavior is by design to prevent sites from hiding the autofill indicator (security). The box-shadow hack is most reliable. For complete control, use autocomplete="off" (now ignored by some browsers) or dynamic form field naming.
Q128: 网站图片文件,如何点击下载?而非点击预览 A: By default, <a href="image.jpg"> opens the image for preview in the browser. To force download: 1) HTML5 download attribute: <a href="image.jpg" download="filename.jpg">Download</a> - tells browser to download instead of navigate. download attribute sets the suggested filename. 2) For same-origin images, download attribute works directly. For cross-origin, the server must set CORS header Access-Control-Allow-Origin (and the image must not be cached). 3) JS approach: fetch the image as blob, create object URL, trigger download: fetch('image.jpg').then(r => r.blob()).then(blob => { const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'filename.jpg'; a.click(); URL.revokeObjectURL(a.href); }). 4) Server-side: Content-Disposition: attachment; filename="image.jpg" header forces download regardless of HTML. For cross-origin images, the download attribute is only respected if CORS allows (and the image includes crossorigin="anonymous" on img).
Q129: 你对 line-height 是如何理解的 A: line-height controls the vertical space between lines of text. It determines the distance from one baseline to the next baseline. How it works: the browser calculates line-height, subtracts the font-size, and distributes the remaining difference equally above and below the text (half-leading). Example: font-size: 16px, line-height: 1.5 -> effective line height = 24px; half-leading = (24 - 16) / 2 = 4px above and below text. Values: normal (browser default, typically ~1.2), number (multiplier relative to font-size, 1.5 = 1.5x font-size - recommended for inheritance), length (px, em, rem), percentage (150% = 1.5x font-size). line-height affects: 1) Text readability - comfortable reading requires adequate line-height (1.5-1.8 for body text). 2) Container height - single line with line-height determines element height. 3) Vertical centering - setting line-height equal to container height vertically centers single-line text. line-height is an inherited property.
Q130: line-height 三种赋值方式有何区别?(带单位、纯数字、百分比) A: Three line-height assignment methods differ in inheritance behavior: 1) Number (unitless): line-height: 1.5. The 1.5 ratio is INHERITED by child elements. Each child calculates its line-height as 1.5 * child's font-size. This is the CORRECT approach because it scales proportionally regardless of font-size. 2) Length (px, em): line-height: 24px or 1.5em. The COMPUTED VALUE is inherited (e.g., if parent font-size is 16px, 1.5em = 24px). Children inherit 24px even if their font-size is different (24px for 12px text = line-height 2.0). This causes disproportionate spacing when font sizes vary. 3) Percentage: line-height: 150%. Same problem as length - the PERCENTAGE IS COMPUTED RELATIVE TO PARENT's font-size, and the computed pixel value is inherited. 150% of 16px = 24px inherited as 24px regardless of child font-size. Best practice: ALWAYS use unitless number for line-height to ensure proper proportional inheritance across elements with different font-sizes.
Q131: 设置元素浮动后,该元素的 display 值会如何变化 A: When an element is set to float: left/right, its computed display value changes to 'block' (or 'table' for the table-related inline values). This happens because floated elements must establish a block formatting context. Specifically: inline elements -> block; inline-block -> block; inline-table -> table; table-cell/table-row/table-caption -> block; flex/inline-flex -> flex (flex items); grid/inline-grid -> grid. The element's original display serves as 'display-outside' which float overrides. Elements with display: none or with position: absolute/fixed are not floated (float computed value becomes 'none'). Practical implication: floated inline elements (like <span>) accept width, height, and vertical margins - behaviors they normally don't have as inline elements. This is why floated layouts work before flexbox/grid.
Q132: 让页面里的字体变清晰,变细用CSS怎么做?(IOS手机浏览器字体齿轮设置) A: iOS Safari renders fonts with thicker strokes by default (especially on Retina displays). To improve font rendering (make text appear thinner/clearer): 1) -webkit-font-smoothing: antialiased; - enables subpixel antialiasing for sharper text. Default is subpixel-antialiased. antialiased makes text thinner and lighter; auto uses browser default. 2) -moz-osx-font-smoothing: grayscale; (Firefox macOS equivalent). 3) font-weight: 300 or lighter weight - iOS default rendering makes even light weights appear normal. 4) text-rendering: optimizeLegibility; - improves kerning and ligature support. Important: -webkit-font-smoothing: antialiased is NOT a standard CSS property (WebKit extension). It may affect accessibility (lower contrast). Default rendering varies by OS: macOS/Safari uses subpixel AA by default (slightly thicker); antialiased mode uses grayscale AA (thinner). Test on actual devices. Apply globally: body { -webkit-font-smoothing: antialiased; }.
Q133: font-style 属性 oblique 是什么意思 A: oblique is a value for the font-style property, alongside normal and italic. Both italic and oblique produce slanted/angled text, but they come from different font files. italic: uses a dedicated italic font variant (specially designed cursive letterforms with different shapes). oblique: uses the regular (roman) font face and applies a slant transformation (shear/skew) to create angled text, without using a separate font design. Many fonts have an italic variant but not an oblique variant. When only italic is available and oblique is specified, browsers typically use italic as fallback (and vice versa). The CSS font-style property can also accept oblique with an angle: font-style: oblique 15deg (degree of slant, CSS Fonts Level 4). Practical difference: italic is usually designed by the type designer with modified letterforms; oblique is a mechanical transformation. For most web use, italic is preferred.
Q134: display:inline-block 什么时候会显示间隙 A: See Q59. display: inline-block gap occurs when HTML whitespace (spaces, tabs, newlines) between inline-block elements is rendered as a single space character (~4px). When the gap does NOT occur: 1) Whitespace removed from HTML: <span>a</span><span>b</span> (no gap). 2) font-size: 0 on parent (re-set on children) - space has zero width. 3) Negative margin compensation: margin-right: -4px (fragile, depends on font). 4) Comments between tags: <!-- --> (reduces readability). 5) Using flexbox instead - flex items ignore whitespace entirely. 6) display: flex + gap property for controlled spacing (modern). The gap is visible only in vertical writing or horizontal inline contexts. Best solution: use flexbox for horizontal layouts (gap between items, no whitespace issues). If forced to use inline-block, use font-size: 0 on the parent.
Q135: 一个高度自适应的div,里面有两个div,一个高度100px,希望另一个填满剩下的高度 A: Fill remaining height with a second div when first div has fixed height: 1) Flexbox: .container { display: flex; flex-direction: column; height: 100%; }.fixed { height: 100px; flex-shrink: 0; }.fill { flex: 1; } - fills the remaining space automatically. 2) CSS Grid: .container { display: grid; grid-template-rows: 100px 1fr; height: 100%; }. 3) Calc: .fill { height: calc(100% - 100px); } - requires the container to have defined height and first div's height known. 4) Absolute positioning: .container { position: relative; height: 100%; }.fixed { height: 100px; }.fill { position: absolute; top: 100px; bottom: 0; left: 0; right: 0; } - fills remaining space without knowing remaining height. 5) Table: .container { display: table; height: 100%; width: 100%; }.row-group { display: table-row-group; }.fixed { display: table-row; height: 100px; }.fill { display: table-row; height: auto; }. Flexbox and Grid are the most maintainable and responsive approaches.
Q136: css 的渲染层合成是什么 浏览器如何创建新的渲染层 A: Compositing layer synthesis (rendering layer creation) is the process by which the browser creates separate layers for parts of the page and composites them together via the GPU. When the browser promotes an element to its own compositing layer: the element is painted onto a separate texture, and subsequent transforms/opacity changes only require re-compositing (GPU) without re-painting (CPU). Triggers for new compositing layer: 1) 3D transforms (translate3d, rotateX, scaleZ). 2) will-change: transform/opacity/top/left. 3) <video>, <canvas>, <iframe> elements. 4) position: fixed. 5) opacity animation with transparency. 6) CSS filters (blur, contrast). 7) mix-blend-mode. 8) overflow: scroll with -webkit-overflow-scrolling: touch. Benefits: isolated animations, GPU-accelerated compositing (60fps). Costs: increased GPU memory usage, layer management overhead, potential layer explosion (thousands of layers). Use will-change judiciously - only on elements that WILL animate.
JavaScript 核心概念
Q137: 闭包 A: 闭包是指一个函数能够访问其外部函数作用域中变量的能力,即使外部函数已经执行完毕。JavaScript中,函数在创建时会形成一个闭包,保留对定义时所在作用域的引用。常见应用场景:1)数据私有化,通过闭包创建私有变量,外部无法直接访问;2)函数工厂,根据参数生成特定功能的函数;3)回调函数与事件处理中保持状态;4)模块模式,实现信息隐藏。需要注意的是,闭包会导致引用变量无法被垃圾回收,不当使用可能造成内存泄漏。实用技巧:在闭包中如果不需要保留外部变量,可以主动将变量置为null释放引用。
Q138: 说说你对作用域链的理解 A: 作用域链是JavaScript中变量查找的机制。当函数执行时,会创建一个包含当前函数局部变量、函数参数等的变量对象,并通过Scope属性链接到外部函数的作用域,形成链式结构。变量查找从当前作用域开始,逐级向上直到全局作用域,若未找到则返回undefined。作用域链在函数定义时即确定(静态作用域/词法作用域),而非执行时。ES6的let/const引入块级作用域,与var的函数作用域有所不同。理解作用域链对理解闭包、变量提升以及this指向等问题至关重要。
Q139: JavaScript原型,原型链?有什么特点? A: JavaScript通过原型实现继承。每个对象都有一个内部属性Prototype(可通过__proto__访问或Object.getPrototypeOf获取),指向其构造函数的prototype对象。当访问对象属性时,若本身不存在,则沿原型链向上查找。原型链的顶端是Object.prototype,其__proto__为null。特点:1)动态性,给原型添加属性会影响到所有实例;2)共享性,原型上的方法被所有实例共享,节省内存;3)继承主要通过原型链实现,ES6的class本质也是语法糖。注意避免过长的原型链影响性能。
Q140: 请解释什么是事件代理 A: 事件代理(事件委托)利用DOM事件冒泡机制,将子元素的事件处理委托给父元素统一处理。原理:事件从目标元素冒泡到祖先元素,父元素通过事件对象的target属性判断实际触发元素,执行相应逻辑。优点:1)减少事件监听器数量,节省内存,尤其适合大量同类子元素(如列表);2)动态元素自动获得事件处理,新添加的子元素无需重新绑定;3)代码更简洁。缺点:部分事件(如focus、blur)不冒泡,需用事件捕获阶段处理。React中不推荐事件代理,因其使用合成事件已有统一管理。
Q141: JavaScript如何实现继承? A: ES6之前主要通过原型链实现继承,常见方式:1)原型链继承,将子类prototype指向父类实例,缺点是引用类型属性被所有实例共享;2)借用构造函数继承,在子类中调用Parent.call(this),解决共享问题但方法无法复用;3)组合继承,原型链+构造函数结合,最常用但会调用两次父类构造函数;4)寄生组合继承,通过Object.create创建父类原型的副本,是最理想的继承方式。ES6的class继承通过extends关键字实现,本质是寄生组合继承的语法糖,更简洁易用。
Q142: 谈谈This对象的理解 A: this是函数执行时自动创建的一个内部指针,指向调用函数的上下文对象。this的指向不是在函数定义时确定的,而是在调用时根据调用方式动态决定:1)作为普通函数调用,this指向全局对象(浏览器中为window,严格模式下为undefined);2)作为对象方法调用,this指向该对象;3)作为构造函数调用(new),this指向新建的实例;4)通过call/apply/bind调用,this指向指定的第一个参数;5)箭头函数没有自己的this,继承外层词法作用域的this。常见问题:setTimeout中的回调函数this指向window,可用箭头函数或bind解决。
Q143: 事件模型 A: DOM事件模型分为三个阶段:1)捕获阶段(Capturing Phase),事件从document向目标元素传播,依次触发沿途元素的捕获监听器;2)目标阶段(Target Phase),事件到达目标元素本身;3)冒泡阶段(Bubbling Phase),事件从目标元素向上冒泡回document。addEventListener的第三个参数控制监听阶段:false(默认)注册在冒泡阶段,true注册在捕获阶段。事件委托利用冒泡机制实现。需要注意的是,并非所有事件都冒泡(如focus、blur、scroll、mouseleave等)。阻止传播使用event.stopPropagation(),阻止默认行为用event.preventDefault()。
Q144: new操作符具体干了什么呢? A: new操作符执行以下步骤:1)创建一个空的普通对象;2)将该对象的__proto__指向构造函数的prototype属性;3)将构造函数的this绑定到这个新对象上;4)执行构造函数内部的代码,为新对象添加属性;5)如果构造函数返回了一个非空对象,则返回该对象,否则返回新创建的对象。模拟实现:function myNew(fn, ...args) { const obj = Object.create(fn.prototype); const result = fn.apply(obj, args); return result instanceof Object ? result : obj; }。理解new的实现原理有助于深入理解JavaScript的对象模型和继承机制。
Q145: Ajax原理 A: Ajax(Asynchronous JavaScript and XML)的核心是XMLHttpRequest对象。工作流程:1)创建XHR实例:const xhr = new XMLHttpRequest();2)调用xhr.open(method, url, async)配置请求方法、URL和是否异步;3)监听xhr.onreadystatechange事件,当readyState变为4(请求完成)且status为2xx或304时处理响应;4)调用xhr.send(data)发送请求。现代开发中常使用fetch API替代XHR,它基于Promise设计,语法更简洁,支持Stream和Service Worker。缺点:fetch不主动携带Cookie(需配置credentials),且不会自动处理HTTP错误状态码。
Q146: 如何解决跨域问题? A: 跨域问题源于浏览器的同源策略(协议、域名、端口均相同)。常见解决方案:1)CORS(最推荐),服务端设置Access-Control-Allow-Origin等响应头实现跨域资源共享;2)JSONP,利用script标签不受同源限制的特性,只能用于GET请求,需服务端配合;3)反向代理,开发环境通过webpack-dev-server或Vite配置proxy代理,生产环境由Nginx代理转发;4)postMessage + iframe,页面间跨域通信;5)document.domain + iframe,适用于主域名相同子域名不同的情况;6)WebSocket,不受同源策略限制。生产环境首选CORS,开发环境常用反向代理。
Q147: 模块化开发怎么做? A: 模块化开发将代码拆分为独立、可复用的模块。演进历史:1)全局函数模式(污染全局);2)命名空间模式(仍可被修改);3)IIFE模式(立即执行函数创建私有作用域),通过返回对象暴露接口;4)CommonJS(Node端,同步加载,module.exports导出,require导入);5)AMD(RequireJS,异步加载,define/require);6)CMD(SeaJS,按需加载);7)ES Module(ES6标准,静态编译,export/import,支持tree-shaking)。现代项目首选ES Module,它在语言层面提供支持,静态导入导出让构建工具能做更好的优化。
Q148: 异步加载JS的方式有哪些? A: 异步加载JS的方式:1)async属性,<script async src="file.js">,下载完成后立即执行,不保证执行顺序;2)defer属性,<script defer src="file.js">,HTML解析完成后按顺序执行;3)动态创建script标签,通过document.createElement('script')插入DOM;4)模块加载器(RequireJS、SystemJS等);5)ES Module通过import()动态导入;6)AJAX获取代码后eval执行(不推荐,有安全风险);7)Webpack等构建工具的代码分割(dynamic import)。推荐使用defer或async来控制脚本加载顺序,ES Module的import()是动态加载的最佳实践。
Q149: 那些操作会造成内存泄漏? A: 常见的内存泄漏场景:1)意外的全局变量,未声明的变量或挂在window上的属性;2)闭包中引用了外部变量且未及时释放;3)DOM引用,JS变量持有已移除DOM元素的引用(如事件监听器未解绑);4)定时器未清除,setInterval持续执行但不再需要;5)事件监听器未移除,尤其是单页应用中频繁挂载卸载组件;6)循环引用,IE低版本中JS对象与DOM对象相互引用;7)Map/Set使用了对象作为键但未清理;8)大量console.log在控制台保留对象引用。预防措施:使用WeakMap/WeakSet避免强引用,组件卸载时清理副作用,工具推荐Chrome Memory面板进行堆快照分析。
JavaScript / ES6 / 进阶概念
Q150: XML和JSON的区别? A: XML(可扩展标记语言)和JSON(JavaScript对象表示法)都是数据交换格式。区别:1)语法简洁性,JSON语法更简洁轻量,XML标记冗长;2)数据类型,JSON原生支持数字、字符串、布尔值、数组、对象,XML所有内容均为文本;3)解析性能,JSON解析更快(可用JSON.parse直接转换),XML解析需要DOM/SAX解析器且更耗资源;4)元数据能力,XML支持命名空间、属性、注释及Schema验证,更擅长描述复杂文档结构;5)可读性,JSON更接近编程语言数据结构,XML更适合文档标记;6)数组表达,JSON原生支持数组,XML需用重复标签模拟。接口通信领域JSON已占绝对主导。
Q151: 谈谈你对webpack的看法 A: Webpack是现代前端最核心的构建工具之一。核心理念是模块打包,将项目中的JS、CSS、图片、字体等所有资源视为模块,通过loader转换、plugin优化,最终输出静态资源包。优点:1)模块化支持完善,兼容CommonJS、ES Module、AMD等多种规范;2)插件生态丰富,几乎所有构建需求都有现成方案;3)代码分割(Code Splitting)支持良好,可实现按需加载;4)HMR(热模块替换)极大提升开发体验。缺点:配置复杂,学习曲线陡峭,大型项目构建速度较慢。Vite等基于ES Module的构建工具正在崛起,但Webpack在复杂项目稳定性和生态成熟度上仍有优势。
Q152: 说说你对AMD和Commonjs的理解 A: CommonJS和AMD是ES Module出现前的两种主要模块规范。CommonJS:同步加载模块,主要用于Node.js服务端。通过require()导入、module.exports导出。在浏览器端使用需打包工具转换。AMD(Asynchronous Module Definition):异步加载模块,主要用于浏览器端,代表实现RequireJS。使用define()定义模块,require()加载模块,支持依赖前置声明。两者区别:CommonJS同步(适合服务端) vs AMD异步(适合浏览器)。ES Module统一了前端和后端的模块方案,成为语言标准。
Q153: 常见web安全及防护原理 A: 常见Web安全攻击及防护:1)XSS(跨站脚本攻击),攻击者注入恶意脚本。防护:对用户输入进行HTML转义,设置Content-Security-Policy头,使用HttpOnly Cookie;2)CSRF(跨站请求伪造),诱导用户执行非本意操作。防护:使用CSRF Token,设置SameSite Cookie(Lax/Strict),验证Referer/Origin头;3)SQL注入,拼接恶意SQL语句。防护:使用参数化查询/ORM框架,避免字符串拼接;4)中间人攻击,防护:全站HTTPS,HSTS头;5)点击劫持,防护:X-Frame-Options: DENY或CSP的frame-ancestors。
Q154: 用过哪些设计模式? A: 前端常用的设计模式:1)单例模式,全局唯一实例(如Vuex/Pinia的store、全局弹窗管理);2)工厂模式,批量创建相似对象(如创建不同类型的表单控件);3)观察者模式/发布订阅模式,事件驱动架构(如EventBus、Vue的响应式系统);4)策略模式,根据不同策略执行不同算法(如表单验证规则);5)装饰器模式,动态扩展功能(如高阶组件HOC);6)适配器模式,统一不同接口(如数据格式转换);7)代理模式,控制对目标对象的访问(如虚拟代理做图片懒加载);8)职责链模式,请求沿处理链传递(如中间件机制)。
Q155: 为什么要有同源限制? A: 同源策略是浏览器最重要的安全机制之一,要求两个页面必须协议、域名、端口完全相同才能互相访问资源。目的:隔离不同站点的数据,防止恶意网站窃取用户在其他网站的信息。如果没有同源策略,恶意网站可以:1)通过脚本读取用户在其他网站的Cookie和LocalStorage;2)获取用户在其他网站的DOM内容;3)拦截用户在其他网站的请求响应。同源策略允许跨页面写入(如form提交、link/script/img标签加载)但不允许读取响应内容。CORS机制在保证安全的前提下提供了受控的跨域访问。
Q156: offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别 A: 三者区别:offsetWidth/offsetHeight:元素的实际可视尺寸,包含content + padding + border + 滚动条(如果存在)。常用于判断元素整体占位大小。clientWidth/clientHeight:元素的内容可视区域,包含content + padding,不包含border和滚动条。常用于获取元素内部可用空间。scrollWidth/scrollHeight:元素内容的总尺寸,包括不可见(滚动)的部分。当内容溢出时大于clientWidth/clientHeight。用于判断是否需要滚动或已滚动距离。三者均返回整数(四舍五入),获取精确浮点数用element.getBoundingClientRect()。
Q157: javascript有哪些方法定义对象 A: JavaScript定义对象的多种方式:1)对象字面量:{ key: value },最常用的方式;2)构造函数:function Person(name) { this.name = name; } + new Person();3)Object.create():基于指定原型创建对象;4)ES6 Class:class Person { constructor(name) } + new Person(),语法糖;5)工厂函数:function createPerson(name) { return { name }; };6)Object构造函数:new Object(),不推荐;7)Object.assign():合并属性创建对象。推荐使用对象字面量定义简单对象,Class定义具有方法的复杂对象。
Q158: 常见兼容性问题? A: 常见浏览器兼容问题及解决:1)CSS前缀差异,使用Autoprefixer自动添加-webkit-、-moz-等前缀;2)flexbox旧版语法,使用老版本flexbox语法;3)ES6+语法,使用Babel转译为ES5;4)Promise/Array.from等API缺失,使用core-js等polyfill;5)移动端click 300ms延迟,使用touch事件处理;6)IE8以下不支持HTML5新标签,引入html5shiv;7)addEventListener/attachEvent差异,封装统一的事件绑定函数;8)getComputedStyle/currentStyle差异;9)event对象差异(window.event vs 参数e)。推荐使用CanIUse查询兼容性,配置browserslist自动决策。
Q159: 说说你对promise的了解 A: Promise是ES6引入的异步编程解决方案,用于解决回调地狱问题。有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已失败),状态一旦改变不可逆。核心用法:new Promise((resolve, reject) => { })创建实例,then()处理成功结果,catch()处理错误,finally()无论成败都会执行。Promise.all()等待所有成功或任一失败;Promise.race()取最先完成的;Promise.allSettled()等待所有结束(不论成功失败);Promise.any()取最先成功的。链式调用中每个then都返回新的Promise,支持串行异步操作。async/await是更优雅的语法糖。
Q160: 你觉得jQuery源码有哪些写的好的地方 A: jQuery源码的设计值得学习:1)IIFE包裹避免全局污染,传入window和undefined确保内部变量正确;2)原型方法扩展通过jQuery.fn实现,节省内存;3)链式调用设计,每个方法返回this;4)Sizzle选择器引擎的高效实现;5)Deferred异步队列的设计,是Promise的前身;6)数据缓存系统,通过$.data()避免直接挂载DOM元素造成内存泄漏;7)extend深度合并机制;8)ready方法的DOMContentLoaded封装。虽然现在原生API已成熟,但jQuery在兼容性处理和方法设计思想方面仍有参考价值。
Q161: 谈谈你对vue、react、angular的理解 A: 三者都是主流前端框架。Vue:轻量灵活,采用模板语法 + 响应式系统,上手简单,适合中小型项目和渐进式改造。核心特性:响应式数据、虚拟DOM、组件化、指令系统。React:函数式理念,JSX语法 + 不可变数据,生态庞大,适合大型复杂应用(尤其是跨平台React Native)。核心特性:单向数据流、虚拟DOM、Hooks、Fiber架构。Angular:企业级全栈框架,TypeScript基础,依赖注入、模块化、RxJS,适合大型企业应用。选型建议:快速迭代选Vue,大型应用选React,企业级标准选Angular。
Q162: Node的应用场景 A: Node.js凭借事件驱动、非阻塞I/O的特性,在以下场景广泛应用:1)Web服务/RESTful API,结合Express/Koa搭建高性能API服务;2)前端工程化工具链(Webpack、Vite、Babel等);3)中间层/BFF(Backend For Frontend),聚合后端数据适配前端需求;4)SSR服务端渲染(Next.js/Nuxt.js);5)实时通信(WebSocket + Socket.io);6)CLI命令行工具(ESLint、Prettier等);7)微服务架构中的服务节点。不适合场景:CPU密集型任务(视频编码、大数据计算)。Node是前端工程师向后端延伸的桥梁。
Q163: 谈谈你对AMD、CMD的理解 A: AMD和CMD都是浏览器端的模块加载规范,产生于ES Module之前。AMD(Asynchronous Module Definition):由RequireJS推广,define(id?, deps[], factory),依赖前置,在factory执行前所有依赖都会加载完成。CMD(Common Module Definition):由SeaJS推广,define(function(require, exports, module) {}),依赖就近,按需加载,在需要时才执行require。区别:AMD推崇依赖前置、提前执行;CMD推崇依赖就近、延迟执行。AMD更适合自动化构建管理,CMD在开发时体验更自然。如今ES Module是标准方案,AMD和CMD已逐渐被淘汰。
Q164: JS的基本数据类型和引用数据类型 A: JS数据类型分为两大类。基本类型(值类型):number、string、boolean、undefined、null、symbol(ES6)、bigint(ES2020)。基本类型存储在栈内存中,赋值时按值拷贝,比较时比较值。引用类型:Object(对象、数组、函数、Date、RegExp等)。引用类型存储在堆内存中,变量持有的是内存地址指针,赋值时传递引用,比较时比较引用地址。深浅拷贝的概念源于此:浅拷贝只复制第一层引用,深拷贝递归复制所有层级。类型检测:typeof判断基本类型,instanceof判断引用类型,Object.prototype.toString.call()精确判断。
Q165: 介绍js有哪些内置对象 A: JavaScript内置对象包括:1)原始包装类型,String、Number、Boolean;2)构造函数类型,Object、Array、Function、Date、RegExp、Error;3)键值集合,Map、Set、WeakMap、WeakSet(ES6);4)结构化数据,ArrayBuffer、SharedArrayBuffer、DataView;5)数学和时间,Math、Date;6)国际化,Intl对象;7)JSON;8)Promise、Proxy、Reflect(ES6);9)Symbol;10)全局对象,globalThis。实用技巧:Object.prototype.toString.call(obj)可获取对象的Class标记,用于精确类型判断。
Q166: 说几条写JavaScript的基本规范 A: JavaScript编码规范建议:1)使用===和!==代替==和!=,避免隐式类型转换的意外结果;2)变量和函数命名遵循驼峰式,常量用全大写加下划线;3)使用let/const替代var;4)每行不超过80-120个字符;5)使用严格模式'use strict'避免意外全局变量;6)及时清理定时器、事件监听器防止内存泄漏;7)避免在循环中创建函数;8)使用解构赋值、展开运算符等ES6+语法;9)使用try-catch捕获异常,Promise.catch处理异步错误;10)配置ESLint + Prettier统一团队代码风格。
Q167: JavaScript有几种类型的值 A: JavaScript的值分为两大类:1)原始值(Primitive Values),包括undefined、null、boolean、number、string、symbol、bigint。原始值不可变,存储在栈内存中,按值访问和比较。2)引用值(Reference Values),包括Object、Array、Function、Date、RegExp、Map、Set等。引用值存储于堆内存,变量持有引用地址,按引用访问,比较引用地址是否相同。涉及概念:装箱(基本类型->包装对象)、拆箱(包装对象->基本类型)、深浅拷贝、传值与传址。typeof操作符区分基本类型(除null外),Object.prototype.toString()精确判断引用类型。
Q168: eval是做什么的 A: eval()是一个危险的全局函数,接收字符串参数并将其作为JavaScript代码执行。严格不推荐使用的原因:1)安全风险,可执行任意字符串代码,存在XSS注入风险;2)性能问题,JavaScript引擎无法对eval中的代码进行编译优化(如V8的JIT),因为它改变了词法作用域;3)调试困难,代码来源不明确;4)阻止CSP(内容安全策略)生效。替代方案:用JSON.parse解析JSON字符串,用new Function构造函数(相对安全,不访问当前作用域)。绝大多数场景中eval都是不需要的。
Q169: null,undefined 的区别 A: null和undefined都表示"无"值,但含义不同。undefined:表示变量已声明但未赋值,或者对象不存在的属性、函数无return的返回值、函数参数未传入等。typeof undefined返回"undefined"。null:表示一个空对象指针,通常用于主动清空对象引用。typeof null返回"object"(历史上遗留的bug)。实际使用习惯:1)变量声明后未赋值时是undefined;2)主动设置空值推荐用null;3)检测变量非空用if (val != null)同时排除null和undefined。区别:null == undefined为true,null === undefined为false。
Q170: ["1", "2", "3"].map(parseInt) 答案是多少 A: 结果是[1, NaN, NaN]。解析:Array.prototype.map接收三个参数(当前值、索引、数组本身),parseInt接收两个参数(字符串、进制radix)。实际调用:parseInt('1', 0) -> 1(0自动判断进制,'1'为10进制);parseInt('2', 1) -> NaN(进制不可为1);parseInt('3', 2) -> NaN(二进制没有数字3)。正确用法:["1", "2", "3"].map(num => parseInt(num))或["1", "2", "3"].map(Number)。这道经典面试题考察对高阶函数参数传递的深入理解。
Q171: javascript 代码中的"use strict";是什么意思 A: "use strict"是ES5引入的严格模式指令,写在脚本或函数开头。启用后JavaScript引擎遵循更严格的语法规则,主要限制:1)变量必须先声明后使用,禁止意外的全局变量;2)禁止with语句;3)禁止对只读属性赋值(如NaN = 1抛出错误);4)this在普通函数中为undefined而非全局对象;5)禁止重复参数名;6)禁止八进制字面量;7)删除不可配置属性报错;8)eval中不能创建外层作用域变量。严格模式使代码更安全,引擎可以更好地优化。ES Module和class定义默认启用严格模式。
Q172: JSON 的了解 A: JSON(JavaScript Object Notation)是一种轻量级数据交换格式,基于JavaScript对象字面量语法子集。特点:1)易于人阅读和编写,也易于机器解析和生成;2)数据结构简洁,支持对象{}、数组[]、字符串、数字、布尔值和null;3)JSON字符串必须使用双引号,不能有注释或函数。核心方法:JSON.stringify()将JavaScript对象序列化为JSON字符串,JSON.parse()将JSON字符串反序列化为JavaScript对象。应用场景:前后端API数据交换、配置文件、数据存储。JSON是Web API事实标准的数据格式。
Q173: js延迟加载的方式有哪些 A: JavaScript延迟加载的常用方式:1)defer属性,HTML解析完毕后按顺序执行;2)async属性,下载完成后立即执行,不保证顺序;3)动态创建script标签,在需要时加载;4)将script标签放在body底部;5)使用import()动态导入ES Module实现按需加载;6)Intersection Observer监测元素进入视口后再加载相关脚本;7)requestIdleCallback在浏览器空闲时加载非关键脚本。推荐策略:关键脚本用defer,非关键脚本用async或动态加载,避免使用阻塞渲染的同步script。
Q174: 同步和异步的区别 A: 同步和异步是代码执行的两种模式。同步:代码按顺序逐行执行,前一个任务完成后才会执行下一个。若某任务耗时较长(如网络请求),整个线程会被阻塞。异步:不等待耗时任务完成,先继续执行后续代码,耗时任务完成后通过回调/Promise/事件等方式通知主线程。JavaScript通过事件循环(Event Loop)机制实现异步。虽然JavaScript是单线程语言,但通过将I/O、定时器等任务交给浏览器Web APIs处理,避免了主线程阻塞。常见异步场景:网络请求(Ajax/fetch)、定时器(setTimeout/setInterval)、用户事件处理。
Q175: defer和async A: defer和async都是<script>标签的属性,用于控制外部脚本的加载和执行。默认(无属性):遇到script暂停HTML解析,立即下载并执行脚本,阻塞DOM构建。async:异步下载,下载完成后立即执行,不阻塞HTML解析。不保证执行顺序,适合独立无依赖的脚本。defer:异步下载,等待HTML解析完成后再按文档顺序执行。保证执行顺序,适合有DOM依赖关系的脚本。两者共同点:都不阻塞HTML解析时的下载过程。不同点:执行时机(async下载完即执行,defer等待HTML解析完)和执行顺序(async不保证,defer保证)。
Q176: 说说严格模式的限制 A: 严格模式("use strict")的限制:1)变量须先声明,禁止意外的全局变量;2)静默失败提升为错误(给不可写属性赋值、删除不可配置属性);3)函数this为undefined而非window;4)禁止with语句;5)禁止重复参数名(function(a, a)报错);6)禁止八进制字面量(010报错,0o10正确);7)arguments不与命名参数同步,且不能修改;8)禁止caller和callee属性;9)保留关键字不能用作变量名;10)eval拥有自己的作用域。class和ES Module默认严格模式。
Q177: attribute和property的区别是什么 A: attribute是HTML标签上的特性,通过getAttribute/setAttribute操作;property是DOM元素的JavaScript对象属性,通过点语法访问。主要区别:1)attribute始终是字符串(或null),property可以是任何类型(Boolean、Object、Number等);2)标准HTML特性(如id、class、value)与DOM property有同步关系;3)自定义attribute(data-x)不会自动创建property;4)某些特性与property值不同步,如input的value属性,用户输入后getAttribute('value')返回初始值,element.value返回当前值;5)checked、disabled等布尔特性,property为true/false,attribute为空字符串或未定义。操作标准属性用property,操作自定义数据用dataset API。
Q178: 谈谈你对ES6的理解 A: ES6(ECMAScript 2015)是JavaScript历史上最重要的版本升级,引入了大量新特性。核心新特性:1)let/const块级作用域;2)箭头函数,简洁语法且不绑定this;3)模板字符串;4)解构赋值;5)扩展运算符...;6)Promise异步编程;7)Class类语法;8)Module模块系统(import/export);9)Symbol新原始类型;10)Map/Set/WeakMap/WeakSet;11)Proxy/Reflect元编程;12)迭代器Iterator和生成器Generator;13)for...of循环。ES6之后每年发布新版本,持续添加新特性。熟悉ES6+是现代前端开发的基本要求,它使JavaScript从脚本语言发展为真正适合大型应用开发的工程化语言。
Q179: 什么是面向对象编程及面向过程编程,它们的异同和优缺点 A: 面向过程编程(POP)以过程/函数为核心,将程序分解为一系列步骤,数据在函数间传递。优点:简单直观,执行效率高,适合小规模程序。缺点:代码耦合度高,难以维护和扩展。面向对象编程(OOP)以对象为核心,将数据和操作封装在一起。三大特性:封装(隐藏内部实现)、继承(复用代码)、多态(不同对象响应相同消息)。优点:模块化程度高,代码复用性强,适合大型项目。缺点:设计复杂度高,性能开销略大。JavaScript是原型面向对象语言,ES6的class提供了语法糖。现代前端开发多采用OOP(组件化)与函数式编程结合的方式。
Q180: 面向对象编程思想 A: 面向对象编程是一种以对象为核心的程序设计范式。核心思想:1)封装,将数据和操作数据的方法绑定在一个对象中,通过访问控制隐藏内部实现细节,只暴露必要接口;2)继承,子类可以复用父类的属性和方法,并可在此基础上扩展;3)多态,不同对象对同一消息做出不同响应。JavaScript的面向对象基于原型链实现:对象通过__proto__链接到原型,形成继承链条。ES6的class本质是对原型继承的语法封装。前端组件化开发就是OOP思想的实践——每个组件是一个独立对象,拥有自己的状态和渲染方法,通过props传递数据实现组件通信。
DOM/BOM/性能/工程化
Q181: 对web标准、可用性、可访问性的理解 A: Web标准:由W3C/WHATWG制定的规范,包括HTML、CSS、DOM等。遵循标准可保证跨浏览器兼容性、降低维护成本。可用性:用户能高效完成任务,包括导航清晰、交互反馈及时、加载速度快、信息架构合理。可访问性(A11Y):残障人士也能正常使用,包括屏幕阅读器支持(语义HTML + ARIA)、键盘导航支持、足够的颜色对比度、非文本内容的替代文本。WCAG 2.1是国际标准。三者关系:标准是基础,可用性是目标,可访问性是包容性要求。好的前端开发应同时兼顾这三个维度。
Q182: 如何通过JS判断一个数组 A: 判断数组的方法:1)Array.isArray(arr),ES6最推荐的方式,兼容所有现代浏览器;2)Object.prototype.toString.call(arr) === '[object Array]',最通用的方法,兼容所有环境包括跨iframe;3)arr instanceof Array,依赖原型链,但在跨iframe场景会失效(不同全局执行环境);4)arr.constructor === Array,同样存在跨iframe问题;5)Array.isArray是V8引擎内部实现,效率最高。推荐:日常使用Array.isArray,需要兼容远古浏览器或跨iframe场景使用toString方案。
Q183: 谈一谈let与var的区别 A: let和var的主要区别:1)作用域不同,var是函数作用域,let是块级作用域({}内有效);2)变量提升,var会提升声明到作用域顶部并初始化为undefined,let也会提升但存在"暂时性死区"(TDZ),声明前访问会报ReferenceError;3)重复声明,var可重复声明同名变量,let报SyntaxError;4)全局声明,var在全局声明会挂载到window对象,let不会;5)for循环中的表现,var声明同一个变量导致闭包问题,let每次循环创建新绑定。ES6后推荐使用let和const替代var。
Q184: map与forEach的区别 A: map和forEach都是数组遍历方法:1)返回值不同,map返回一个新数组(每次回调返回值的集合),forEach返回undefined;2)链式调用,map可以继续链式调用(.filter().reduce()),forEach不能;3)用途不同,map用于"映射"转换数组元素,forEach用于执行副作用操作(如更新UI、打印日志);4)性能,现代引擎中map通常略快于forEach。选择原则:需要返回新数组用map,只需要遍历执行操作用forEach。两者都不改变原数组(除非回调中主动修改)。
Q185: 谈一谈你理解的函数式编程 A: 函数式编程是一种编程范式,将计算视为函数的求值,避免状态变化和副作用。核心概念:1)纯函数,相同输入永远得到相同输出,无副作用;2)不可变性,变量不改变,而是创建新值(如数组的map、filter,对象的...spread);3)函数是一等公民,函数可赋值给变量、作为参数传递、作为返回值;4)高阶函数,接收函数作为参数或返回函数(如map、reduce、filter);5)柯里化,将多参数函数转换为单参数函数链;6)函数组合,将多个函数组合成新函数。优点:代码可预测、易测试、易并行。React的纯组件理念和Redux的reducer设计都是函数式思想的体现。
Q186: 谈一谈箭头函数与普通函数的区别? A: 箭头函数与普通函数的主要区别:1)this绑定,普通函数的this动态绑定(取决于调用方式),箭头函数的this继承外层词法作用域(定义时确定),无法通过call/apply/bind改变;2)不能作为构造函数,箭头函数没有prototype属性,不能使用new;3)没有arguments对象,需用剩余参数...args代替;4)不能用作生成器函数,不支持yield;5)语法简洁,单行表达式可省略大括号和return。使用建议:需要动态this用普通函数(如对象方法、事件处理器),需要保留外层this用箭头函数(如回调、定时器)。
Q187: 谈一谈函数中this的指向 A: 函数中this的指向由调用方式决定:1)默认绑定,普通函数独立调用,非严格模式下this指向window/global,严格模式下为undefined;2)隐式绑定,作为对象方法调用,this指向该对象;3)显式绑定,call/apply/bind指定this指向的对象;4)new绑定,构造函数调用,this指向新创建的实例;5)箭头函数,无自己的this,继承外层函数或全局作用域的this;6)事件处理中,普通函数this指向触发事件的元素,箭头函数指向定义时的上下文。优先级:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定。
Q188: 异步编程的实现方式 A: JavaScript异步编程的演进:1)回调函数(callback),最基本的方式,简单场景有效但嵌套过深形成"回调地狱";2)事件监听/发布订阅,通过事件触发解耦,如EventEmitter;3)Promise(ES6),链式调用.then()/.catch(),解决回调地狱,支持Promise.all/race等组合;4)Generator函数(ES6),通过yield暂停执行,配合co等库实现类似同步的写法;5)async/await(ES2017),基于Promise的语法糖,用同步语法写异步代码,本质是Generator + Promise的封装。async/await是目前最推荐的异步编程方式,代码更直观易读,错误处理通过try-catch完成。
Q189: 谈谈你对原生Javascript了解程度 A: 我对原生JavaScript有较深入的了解,包括:1)ECMAScript核心,数据类型、作用域链、闭包、原型链、this绑定、执行上下文、事件循环等语言机制;2)DOM操作,节点增删改查、事件模型(捕获/冒泡/委托)、属性操作、样式操作;3)BOM,window对象、location、history、navigator、定时器;4)ES6+新特性,Promise/async、Module、Class、Proxy、Map/Set、Symbol、Iterator/Generator等;5)Web APIs,Fetch、Web Storage、WebSocket、Service Worker、Canvas、Intersection Observer等。我习惯在项目中使用原生API,必要时才引入第三方库。
Q190: Js动画与CSS动画区别及相应实现 A: JS动画和CSS动画各有优劣。CSS动画:使用transition和@keyframes实现。优点:浏览器可GPU加速(transform/opacity),不阻塞主线程,实现简单。缺点:控制力有限,复杂动画难以实现,无法逐帧控制。JS动画:使用requestAnimationFrame(推荐)、setTimeout/setInterval实现。优点:控制力强,可精准控制每一帧,支持复杂动画逻辑(路径动画、物理效果)。缺点:可能阻塞主线程,代码量较大。选择建议:简单过渡和UI动效用CSS动画;复杂、交互驱动或需要精确控制的动画用JS动画。rAF比setTimeout更适合动画场景。
Q191: JS 数组和对象的遍历方式,以及几种方式的比较 A: 数组遍历方式:for循环(性能最好)、forEach(简洁但无法break)、for...of(ES6,支持break)、map/filter/reduce(函数式)、every/some(条件检测)。对象遍历方式:for...in(遍历可枚举属性,含原型链)、Object.keys()(返回自身可枚举键名数组)、Object.values()(ES8,返回自身可枚举值数组)、Object.entries()(ES8,返回键值对数组)、Object.getOwnPropertyNames()(含不可枚举属性)。性能:for > forEach > for...of > for...in。推荐:常规数组遍历用for或forEach,需要break用for...of或some;对象遍历优先用Object.keys/entries配合数组方法。
Q192: gulp是什么 A: Gulp是一个基于流的自动化构建工具,通过代码优于配置的理念管理构建任务。核心概念:1)src读取源文件,dest输出到目标目录,pipe连接处理步骤;2)插件系统,gulp-uglify压缩JS、gulp-sass编译Sass、gulp-imagemin压缩图片等;3)watch监听文件变化自动执行任务。示例:gulp.task('scripts', () => gulp.src('src/*.js').pipe(uglify()).pipe(gulp.dest('dist')))。相比Webpack,Gulp更轻量、配置更直观,适合纯静态资源处理和文件转换任务。但随着Vite等工具的兴起,Gulp在新建项目中使用较少,主要用于维护遗留项目。
Q193: 说一下Vue的双向绑定数据的原理 A: Vue 2使用Object.defineProperty实现响应式数据。核心流程:1)递归遍历data对象,通过Object.defineProperty将每个属性转为getter/setter;2)每个组件实例对应一个Watcher,在组件渲染时访问响应式数据会触发getter,从而将Watcher添加到数据的依赖收集器Dep中;3)数据变化时触发setter,Dep通知所有依赖的Watcher,触发视图更新。Vue 3改用Proxy实现,解决了Vue 2的诸多限制(无法检测属性新增/删除、数组直接索引修改等)。指令v-model是语法糖,本质是:value + @input的组合。
Q194: let var const区别 A: 三者区别:1)作用域,var函数作用域,let/const块级作用域;2)变量提升,var会提升并初始化为undefined,let/const会提升但不初始化(暂时性死区TDZ),声明前访问报ReferenceError;3)重复声明,var可重复声明,let/const不可;4)重新赋值,var/let可重新赋值,const声明常量必须初始化且不可重新赋值(但const对象属性可修改);5)全局声明,var在全局会挂载到window,let/const不会。推荐:默认用const,需要重新赋值用let,不再使用var。const既能保证变量不被意外修改,也向开发者传达语义。
Q195: 快速的让一个数组乱序 A: 数组乱序(洗牌)最常用Fisher-Yates算法(也称作Knuth洗牌算法),复杂度O(n)。代码:function shuffle(arr) { const result = [...arr]; for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } return result; }。不推荐arr.sort(() => Math.random() - 0.5),因为sort的比较函数理论上需要返回一致的结果,随机比较会导致排序结果不均匀(某些排列概率更高)。Fisher-Yates从后向前遍历,每个元素与随机位置交换,保证所有排列等概率。
Q196: 如何渲染几万条数据并不卡住界面 A: 渲染大量数据的关键是避免一次性创建过多DOM元素导致主线程阻塞。方案:1)虚拟滚动(推荐),只渲染可视区域内的DOM节点(约10-20条),滚动时复用DOM(如react-window、vue-virtual-scroller);2)时间分片,使用requestAnimationFrame分批渲染,每次只创建一小部分DOM,setTimeout或requestIdleCallback也可;3)DocumentFragment批量插入,减少浏览器重排;4)使用Web Worker处理数据计算,避免阻塞UI线程;5)用canvas代替大量DOM元素(如表格、图表);6)开启CSS的content-visibility: auto跳过视口外元素的渲染。React中可用useDeferredValue延迟非紧急更新。
Q197: 希望获取到页面中所有的checkbox怎么做? A: 获取页面所有checkbox的方法:1)const checkboxes = document.querySelectorAll('input[type="checkbox"]'),返回NodeList,支持forEach等遍历方法,最推荐;2)const formElements = document.forms[0].elements; const checkboxes = Array.from(formElements).filter(el => el.type === 'checkbox'),适用于特定表单内;3)const allInputs = document.getElementsByTagName('input'); 然后遍历筛选type为checkbox的元素;4)如果使用jQuery,$('input:checkbox')。querySelectorAll兼容性最好,语法简洁。NodeList与数组的区别:它包含length属性和forEach方法,但不能直接使用map/filter(需Array.from转换)。
Q198: 怎样添加、移除、移动、复制、创建和查找节点 A: DOM节点操作:创建:document.createElement('div')、document.createTextNode('text')、document.createDocumentFragment()、element.cloneNode(true)(深克隆)。添加:parent.appendChild(child)(追加到最后)、parent.insertBefore(newChild, refChild)(插入到某元素前)、parent.prepend/append(child)(ES6)。移除:parent.removeChild(child)或element.remove()。替换:parent.replaceChild(newChild, oldChild)。查找:document.getElementById()、document.querySelector/querySelectorAll()(CSS选择器)、element.closest(selector)(查找最近的祖先)、element.parentElement/children/nextElementSibling等。现代API推荐querySelector/querySelectorAll作为首选查找方法。
Q199: 正则表达式 A: 正则表达式是用于匹配字符串中字符组合的模式。JavaScript中创建方式:字面量/pattern/flags 和 new RegExp('pattern', 'flags')。常用方法:regexp.test(str)(是否匹配,返回布尔值)、str.match(regexp)(匹配结果数组)、str.replace(regexp, replacement)(替换)、str.split(regexp)(分割)。常见模式:\d数字、\w单词字符、\s空白、^开头、$结尾、.任意字符、零次或多次、+一次或多次、?零次或一次、{n,m}次数范围、[]字符集、()分组、|或。修饰符:g全局、i不区分大小写、m多行。实用技巧:非贪婪匹配用?、正向零宽断言用(?=pattern)、反向零宽断言用(?<=pattern)。
Q200: Javascript中callee和caller的作用? A: callee和caller是arguments对象的属性,在严格模式下被禁用。arguments.callee:指向当前正在执行的函数,常用于匿名递归(如setTimeout中递归调用自身)。arguments.caller:指向调用当前函数的函数,即获取调用栈的上层函数。由于严格模式禁用(ES5+),且在性能优化方面引擎难以优化这些属性,推荐替代方案:1)给函数命名代替arguments.callee:const factorial = function fn(n) { return n <= 1 ? 1 : n * fn(n-1); };2)使用Error().stack获取调用栈信息代替arguments.caller。现代JavaScript开发中很少使用这两个属性。
Q201: window.onload和$(document).ready A: window.onload和$(document).ready都是DOM加载完成后执行回调的机制,但有区别:1)触发时机,window.onload等待所有资源(图片、样式、脚本、iframe等)加载完成后才触发;$(document).ready在DOM树构建完成后立即触发,不等待图片等资源加载;2)执行次数,window.onload是赋值操作,多次赋值只有最后一次生效;$(document).ready可以绑定多个回调,按注册顺序执行;3)原生替代,现代浏览器可用DOMContentLoaded事件代替$(document).ready:document.addEventListener('DOMContentLoaded', fn)。性能建议:操作DOM的脚本在DOMContentLoaded中执行,需要获取图片尺寸等资源信息的在load事件中执行。
Q202: addEventListener()和attachEvent()的区别 A: 两者都是注册事件监听器的方法,attachEvent是IE8及以下版本的专有API。区别:1)参数,addEventListener(type, listener, useCapture)接收三个参数(第三个控制是否在捕获阶段触发);attachEvent('on' + type, listener)只接收两个参数,不支持捕获阶段(IE低版本只有冒泡);2)this指向,addEventListener中回调的this指向触发事件的元素;attachEvent中回调的this指向全局window对象;3)事件名,addEventListener不需要'on'前缀,attachEvent需要(如'onclick')。封装兼容写法:if (el.addEventListener) { el.addEventListener(type, fn, false); } else { el.attachEvent('on' + type, fn); }。
Q203: 数组去重方法总结 A: 数组去重的常用方法:1)Set(最简洁),[...new Set(arr)],时间复杂度O(n),空间复杂度O(n);2)filter + indexOf,arr.filter((item, index) => arr.indexOf(item) === index),时间复杂度O(n^2);3)reduce + includes,arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []);4)Map键值对,利用Map键唯一性;5)双重for循环 + splice,性能较差。对于对象数组去重,可使用Map存储唯一键:const uniqueBy = (arr, key) => [...new Map(arr.map(item => [item[key], item])).values()]。Set方案简洁高效,日常开发首选。
Q204: 想实现一个对页面某个节点的拖曳?如何做?(使用原生JS) A: 原生JS拖拽实现步骤:1)绑定mousedown到目标元素,记录初始鼠标位置和元素位置;2)在mousedown中注册mousemove和mouseup事件;3)mousemove中计算偏移量,设置element.style.left/top(使用transform或position:absolute进行定位);4)mouseup中解绑mousemove和mouseup。注意点:设置user-select: none防止拖拽时选中文本;处理边界限制防拖出视口;使用document.addEventListener而非element.addEventListener防止鼠标移出元素时丢失拖拽;考虑使用pointer-events统一处理鼠标和触屏。更完善的方案:HTML5 Drag and Drop API支持更复杂场景。
Q205: Javascript全局函数和全局变量 A: JavaScript全局函数(可直接调用):parseInt()、parseFloat()、isNaN()、isFinite()、encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、eval()。全局值属性:undefined、NaN、Infinity。全局构造函数:Object、Array、Function、String、Number、Boolean、Date、RegExp、Error、Symbol、Map、Set、Promise等。ES6新增全局对象:globalThis,在不同环境中统一指向全局对象(浏览器window、Node global、Web Worker self)。注意:严格模式下eval被限制使用,parseInt应始终指定进制radix参数。
Q206: 使用js实现一个持续的动画效果 A: 实现持续JS动画最推荐的方式是requestAnimationFrame(rAF)。示例:function animate() { element.style.transform = translateX(${progress}px); progress += 2; requestAnimationFrame(animate); } requestAnimationFrame(animate);。rAF的优点:1)由浏览器优化调度,在每次重绘前执行,与屏幕刷新率同步(通常60fps);2)页面不可见时自动暂停,节省资源;3)相比setTimeout/setInterval更平滑。替代方式:1)setTimeout/setInterval模拟,但可能因任务队列延迟导致丢帧或卡顿;2)Web Animations API(element.animate()),适合简单动画。复杂动画配合缓动函数使用:progress = easeInOutCubic(t)实现加速减速效果。
Q207: 封装一个函数,参数是定时器的时间,.then执行回调函数 A: 这是封装一个Promise版的delay/sleep函数:function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }。使用:delay(1000).then(() => console.log('1秒后执行'))。async/await用法:await delay(2000); console.log('2秒后执行')。扩展:可支持取消,使用AbortController:function delay(ms, { signal } = {}) { return new Promise((resolve, reject) => { const timer = setTimeout(resolve, ms); signal?.addEventListener('abort', () => { clearTimeout(timer); reject(new DOMException('Aborted', 'AbortError')); }); }); }。这种模式广泛用于控制异步操作的时间间隔和超时处理。
Q208: 怎么判断两个对象相等? A: 判断两个对象是否相等需要区分场景:1)引用比较,obj1 === obj2比较的是内存地址,只有指向同一个对象才为true;2)浅比较,遍历第一层属性比较值,可用Object.is()或===,React的PureComponent使用这种比较方式;3)深比较,递归比较所有嵌套属性。JSON.stringify(obj1) === JSON.stringify(obj2)是最简单的深比较,但有限制(属性顺序不一致时误判、不支持函数/Symbol/undefined等);4)自定义递归比较:function deepEqual(a, b) { if (a === b) return true; if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false; const keysA = Object.keys(a), keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; return keysA.every(key => deepEqual(a[key], b[key])); }。生产环境推荐使用lodash的isEqual。
Q209: 项目做过哪些性能优化? A: 我在项目中做的性能优化涵盖多个方面:加载优化,代码分割(路由懒加载)、图片WebP/AVIF格式转换及懒加载、关键CSS内联、CDN加速、资源预加载preload/preconnect。渲染优化,虚拟列表处理大量数据、CSS contain/content-visibility跳过屏幕外渲染、优化重排重绘(transform代替top/left)、使用will-change提示浏览器。运行时优化,防抖节流处理高频事件、Web Worker处理密集计算、对象池优化内存分配、requestIdleCallback处理低优先级任务。构建优化,Tree-shaking去除无用代码、压缩混淆、splitChunks合理分包、按需引入第三方库。缓存策略,Service Worker离线缓存、合理配置HTTP缓存头。
Q210: 浏览器缓存 A: 浏览器缓存分为强缓存和协商缓存。强缓存:浏览器直接读取本地缓存,不发请求。控制字段:Expires(HTTP/1.0,绝对时间)、Cache-Control(HTTP/1.1,相对时间,优先级更高)。Cache-Control常用值:max-age=秒、public(可被任何缓存)、private(仅客户端缓存)、no-cache(每次需协商)、no-store(禁止缓存)。协商缓存:向服务器发送请求,由服务器判断资源是否可用。控制字段:Last-Modified/If-Modified-Since(最后修改时间,精确到秒)、ETag/If-None-Match(资源唯一标识,优先级更高)。缓存流程:浏览器请求->强缓存有效则直接返回->协商缓存有效返回304->新资源200。合理设置缓存可大幅减少网络请求,提升加载速度。
Q211: 谈谈你对WebSocket的理解 A: WebSocket是一种在单个TCP连接上实现全双工通信的协议。与HTTP的区别:1)通信模式,HTTP是请求-响应模式(客户端必须主动发起),WebSocket是双向推送模式(服务端可主动发送消息);2)连接开销,HTTP每次请求都有头部开销,WebSocket建立连接后头部极小(约2字节);3)实时性,WebSocket适合实时性要求高的场景(即时通讯、在线游戏、协同编辑)。建立过程:先通过HTTP发起Upgrade握手请求(Upgrade: websocket),服务端响应101状态码后切换为WebSocket协议。常用库:Socket.io(封装了降级方案,兼容不支持WebSocket的环境)。
Q212: 尽可能多的说出你对 Electron 的理解 A: Electron是一个使用Web技术(HTML/CSS/JS)构建跨平台桌面应用的框架。架构:主进程(Main Process)作为应用入口,负责创建窗口、系统交互;渲染进程(Renderer Process)运行Chromium显示页面,每个窗口独立进程;通过IPC(ipcMain/ipcRenderer)实现进程间通信。优点:跨平台(Windows/Mac/Linux),Web开发者可快速转向桌面开发,生态丰富(VS Code、Slack、Discord均基于Electron)。缺点:应用体积大(捆绑Chromium),内存占比较高,性能不如原生应用。关键技术点:自动更新、系统托盘、原生菜单、文件拖放、剪贴板操作、通知、屏幕捕获等。Electron虽然资源占用较大,但在快速开发和跨平台需求下是非常实用的选择。
Q213: 深浅拷贝 A: 深浅拷贝用于对象的复制操作。浅拷贝:只复制对象的第一层属性,若属性值是引用类型则复制引用地址。实现方式:Object.assign()、展开运算符{...obj}、Array.prototype.concat()、Array.prototype.slice()。深拷贝:递归复制所有层级的所有属性,新对象与原对象完全独立。实现方式:JSON.parse(JSON.stringify(obj))(有局限,不能处理函数、undefined、Symbol、循环引用)、lodash的_.cloneDeep()、structuredClone()(现代浏览器原生API)。选择建议:只有一层结构的对象用浅拷贝,有多层嵌套的对象用深拷贝。JSON序列化方案简单但有局限,生产环境推荐用lodash或structuredClone。
Q214: 防抖/节流 A: 防抖(debounce)和节流(throttle)是优化高频触发事件的两种策略。防抖:连续触发事件时,只在最后一次触发后等待指定时间再执行。适用场景:搜索输入(用户停止输入后才发送请求)、窗口resize完成后再计算。代码:function debounce(fn, delay) { let timer; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; }。节流:固定时间间隔内只执行一次。适用场景:滚动加载、resize过程更新。代码:function throttle(fn, limit) { let inThrottle; return function(...args) { if (!inThrottle) { fn.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }。防抖常用于"结束"场景,节流常用于"过程"场景。
Q215: 谈谈变量提升? A: 变量提升(Hoisting)是JavaScript引擎在代码执行前将变量和函数声明提升到作用域顶部的行为。var声明的变量提升到作用域顶部并初始化为undefined,因此可以在声明前访问(值为undefined)。function声明整体提升(包括定义),因此可以在声明前调用函数。let/const也会提升但存在"暂时性死区",声明前访问会抛出ReferenceError,体现了更安全的语法设计。示例:console.log(a); // undefined; var a = 1;console.log(b); // ReferenceError; let b = 1。变量提升是JavaScript设计的历史遗留问题,ES6的let/const解决了这个弊端。
Q216: 什么是单线程,和异步的关系 A: JavaScript是单线程语言,即同一时间只能执行一个任务。这是由浏览器的设计决定的——如果JavaScript是多线程的,两个线程同时操作同一个DOM节点会引起竞态条件。单线程面临的问题:遇到耗时任务(网络请求、定时器、大文件处理)会阻塞后续代码执行。解决方案就是异步机制:将耗时任务交给浏览器其他线程处理(Web APIs),主线程继续执行后续代码;耗时任务完成后将回调放入任务队列,等待主线程空闲时执行。这就是事件循环(Event Loop)的基本原理。所以,JavaScript虽然自身是单线程,但通过异步机制避免了阻塞,实现了高效的并发处理。
Q217: 前端面试之hybrid A: Hybrid App是结合Native和Web技术的混合开发模式。原理:Web页面运行在原生App的WebView容器中,通过JSBridge实现JS与Native的双向通信。JSBridge实现方式:1)拦截URL Scheme,Web发送特定协议请求(如jsbridge://method),Native拦截并处理,再将结果通过loadURL回调给Web;2)注入JavaScript API,Native向WebView全局注入JS对象(如window.NativeBridge),Web直接调用;3)现代方式使用JavaScriptCore/JSCore。Hybrid优势:跨平台复用Web代码,可动态更新无需发版(热更新),兼顾原生能力。Hybrid与纯H5区别:Hybrid可通过JSBridge调用原生能力(相机、定位、蓝牙等)。
Q218: 前端面试之组件化 A: 组件化是将页面拆分为独立、可复用、可组合的UI单元的开发方式。核心原则:1)单一职责,每个组件只负责一个功能;2)高内聚低耦合,组件内部紧密关联,对外暴露最小接口;3)可复用,通用组件在不同页面中重复使用。组件分类:基础组件(Button、Input、Icon)、业务组件(UserCard、ProductList)、页面组件(HomePage、DetailPage)。组件通信方式:父->子(props/attrs)、子->父(事件回调/emit)、兄弟(共同父组件中转)、跨层级(Context/Provide-inject/EventBus/状态管理)。组件化提升了代码复用率、可维护性,是现代前端框架(Vue/React/Angular)的核心设计思想。
Q219: 前端面试之MVVM浅析 A: MVVM(Model-View-ViewModel)是一种软件架构模式。Model:数据层,包含业务数据和验证逻辑,通常对应后端API返回的数据。View:视图层,即UI界面,显示数据。ViewModel:视图模型层,连接Model和View的核心,通过数据绑定实现自动同步。Vue和React都采用了类似MVVM的思想。Vue中,ViewModel对应组件实例,通过响应式数据系统(Object.defineProperty/Proxy)实现View与Model的双向绑定(v-model)。React中,通过单向数据流(state + setState)和受控组件实现View与Model的同步。MVVM的优势:开发者只需关注数据变化(ViewModel),无需手动操作DOM,显著降低了开发复杂度。
DOM/BOM/性能/JS进阶
Q220: 实现效果,点击容器内的图标,图标边框变成border 1px solid red,点击空白处重置 A: 实现方案:使用事件委托监听容器点击事件,判断点击目标是否为图标。const container = document.getElementById('container'); let activeIcon = null; container.addEventListener('click', (e) => { const icon = e.target.closest('[data-icon]'); if (icon) { if (activeIcon) activeIcon.style.border = ''; icon.style.border = '1px solid red'; activeIcon = icon; } else { if (activeIcon) { activeIcon.style.border = ''; activeIcon = null; } } });。使用closest方法确保点击图标内部子元素时也能正确命中图标元素。data-*属性标记图标,方便选择。
Q221: 请简单实现双向数据绑定MVVM A: 基于Object.defineProperty的简易实现:function defineReactive(obj, key, val) { const deps = []; Object.defineProperty(obj, key, { get() { if (Dep.target) deps.push(Dep.target); return val; }, set(newVal) { if (newVal !== val) { val = newVal; deps.forEach(fn => fn()); } } }); }。文本节点替换模板:用正则匹配,替换为data中对应值。输入框绑定v-model:<input id="input" />;监听input事件更新data对象。Vue 2即基于此原理,但增加了模板编译、指令系统、虚拟DOM、依赖收集优化等复杂机制。Vue 3使用Proxy替代Object.defineProperty,支持更多操作拦截。
Q222: 实现Storage,使得该对象为单例,并对localStorage进行封装 A: 单例模式封装Storage:class Storage { static getInstance() { if (!Storage.instance) { Storage.instance = new Storage(); } return Storage.instance; } setItem(key, value) { const str = typeof value === 'object' ? JSON.stringify(value) : String(value); localStorage.setItem(key, str); } getItem(key) { const value = localStorage.getItem(key); try { return JSON.parse(value); } catch { return value; } } removeItem(key) { localStorage.removeItem(key); } clear() { localStorage.clear(); } }。使用:const storage = Storage.getInstance(); storage.setItem('user', { name: 'Alice' });。单例模式保证全局只有一个实例,setItem自动序列化对象。
Q223: 谈谈你对Event Loop的理解 A: 事件循环是JavaScript异步机制的核心。先执行同步代码,遇到异步任务(setTimeout、Promise、I/O等)交给Web APIs处理,回调进入任务队列。主线程空闲时从任务队列取回调执行。任务分为宏任务(setTimeout、setInterval、I/O、UI渲染)和微任务(Promise.then、MutationObserver、queueMicrotask)。执行流程:1)执行当前宏任务;2)执行所有微任务;3)UI渲染(可能);4)取下一个宏任务执行。微任务优先级高于宏任务,在下一个宏任务之前会清空所有微任务。Node.js事件循环有额外阶段(timers、poll、check、close callbacks等),与浏览器环境略有不同。理解Event Loop对正确处理异步执行顺序至关重要。
Q224: JavaScript 对象生命周期的理解 A: 对象生命周期三阶段:1)创建,通过字面量、new、Object.create()分配堆内存;2)使用,通过引用访问属性和方法;3)销毁,无引用时GC自动回收。垃圾回收策略:引用计数(已淘汰),标记-清除(V8使用),分代回收(新生代用Scavenge复制算法,老生代用标记-清除/整理)。V8优化:增量标记(减少GC暂停时间)、并发标记(主线程不阻塞)。容易导致内存泄漏的操作:全局变量、未被清理的闭包、DOM引用未释放、定时器未清除、Map/Set中残留引用。使用WeakMap/WeakSet可让键为对象时,对象被回收后键值对自动移除。
Q225: 我现在有一个canvas,上面随机布着一些黑块,请实现方法,计算canvas上有多少个黑块 A: 使用连通区域标记算法(BFS/DFS):1)获取像素数据,const imageData = ctx.getImageData(0, 0, width, height); const data = imageData.data;。2)判断黑色阈值,function isBlack(data, x, y) { const idx = (y * width + x) * 4; return data[idx] === 0 && data[idx+1] === 0 && data[idx+2] === 0; }。3)BFS标记:function countBlocks(data, width, height) { const visited = new Uint8Array(width * height); let count = 0; const dirs = [[0,1],[0,-1],[1,0],[-1,0]]; function bfs(sx, sy) { const queue = sx, sy; visited[sy * width + sx] = 1; while (queue.length) { const [x, y] = queue.shift(); for (const [dx, dy] of dirs) { const nx = x + dx, ny = y + dy; if (nx >= 0 && nx < width && ny >= 0 && ny < height && !visited[nywidth+nx] && isBlack(data, nx, ny)) { visited[nywidth+nx] = 1; queue.push([nx, ny]); } } } } for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) { if (!visited[ywidth+x] && isBlack(data, x, y)) { count++; bfs(x, y); } } return count; }。时间复杂度O(wh)。
Q226: 现在要你完成一个Dialog组件,说说你设计的思路?它应该有什么功能? A: Dialog设计思路:Props:visible(控制显示)、title、width、confirmText/cancelText、showClose、closeOnClickOverlay、beforeClose(关闭前钩子)、destroyOnClose。功能:1)Teleport/Portal渲染到body防止父容器overflow影响;2)焦点管理,打开自动聚焦到确认按钮,Tab循环,ESC关闭;3)动画,enter/leave过渡效果;4)A11Y,role="dialog"、aria-modal="true"、aria-labelledby引用title;5)插槽支持自定义内容;6)拖拽功能可选;7)promise式调用(Dialog.confirm()返回Promise)。slot/content分发:标题区域、内容区域、底部按钮区域。通过v-if/v-show控制渲染。好的Dialog应具备灵活定制能力和良好的无障碍支持。
Q227: ajax、axios、fetch区别 A: Ajax泛指基于XMLHttpRequest的异步通信技术。axios是基于XHR的Promise封装,功能丰富:支持拦截器(请求/响应)、自动JSON转换、取消请求(AbortController)、超时设置、CSRF保护、上传进度监听、浏览器和Node双端支持。fetch是浏览器原生API,基于Promise设计,语法简洁(fetch(url).then(r => r.json()))。缺点:不自动处理HTTP错误状态码(4xx/5xx不reject,需手动检查response.ok),不默认带Cookie(需credentials: 'include'),不支持超时(需AbortController),不支持请求进度。选择建议:简单场景用fetch,项目复杂用axios。
Q228: JavaScript的组成 A: JavaScript由三部分组成:ECMAScript定义语言核心(语法、类型、语句、关键字、操作符、对象),由TC39委员会维护,每年发布新版本。DOM(文档对象模型)提供操作HTML/XML的API(节点操作、事件、样式),由W3C制定。BOM(浏览器对象模型)提供与浏览器交互的API(window、location、history、navigator、screen、定时器),虽然没有统一标准但各浏览器实现已趋同。Node.js环境实现了ECMAScript和部分W3C API(如timers、console),但没有DOM/BOM(因为没有浏览器环境)。理解三者关系有助于区分代码运行环境依赖。
Q229: 检测浏览器版本有哪些方式? A: 检测方式:1)navigator.userAgent解析UA字符串(如/Chrome/(\d+)/.test(ua)获得版本号)。缺点:UA可被伪造,不推荐用于功能决策。2)特征检测(推荐),通过检测特定API是否存在判断能力(如检测window.Promise判断Promise支持情况)。3)navigator.platform获取操作系统。4)navigator.vendor获取浏览器厂商("Google Inc."等)。5)navigator.userAgentData(新API)返回结构化浏览器数据(Chrome 90+支持)。最佳实践:优先使用特征检测,原理是用if (typeof API !== 'undefined')判断能力,而不是根据浏览器版本做假设。如需特定浏览器判断,使用第三方库(准确度更高)或简单的UA正则匹配。
Q230: 如何编写高性能的JavaScript A: 高性能JS编写建议:1)减少DOM操作,批量更新使用DocumentFragment,缓存DOM查询结果;2)使用事件委托减少监听器数量;3)高频事件(scroll/resize/input)使用防抖节流;4)使用requestAnimationFrame处理视觉更新,避免setTimeout动画;5)Web Worker处理复杂计算不阻塞UI;6)避免使用delete删除对象属性(影响V8优化),用赋值null代替;7)使用Map/Set代替Object/Array做频繁查找操作;8)避免内存泄漏(及时清理定时器、事件监听器);9)合理使用数据结构,选择合适的内置方法;10)懒加载非关键资源,按需加载代码。使用Chrome Performance面板分析性能瓶颈针对性优化。
Q231: 描述浏览器的渲染过程,DOM树和渲染树的区别 A: 浏览器渲染过程:1)HTML解析构建DOM树;2)CSS解析构建CSSOM树;3)DOM + CSSOM合并为渲染树(Render Tree);4)布局(Layout)计算几何位置;5)绘制(Paint)填充像素;6)合成(Composite)合并图层。DOM树与渲染树区别:DOM树包含所有节点(包括head、script、display:none的元素等),渲染树只包含可见节点(display:none不在渲染树中,但visibility:hidden在渲染树中且占位)。渲染树节点拥有计算后的样式(Computed Style)。渲染树构建完成后进入布局阶段,确定每个节点的几何位置。当DOM或样式变化时触发回流/重绘。
Q232: script 的位置是否会影响首屏显示时间 A: 会显著影响。默认<script>标签会阻塞HTML解析和渲染,直到脚本下载和执行完成。script放在<head>中会使页面在脚本下载期间白屏,首屏时间大幅增加。放在</body>之前只在DOM构建完成后才解析脚本,不影响首屏内容渲染。优化策略:1)使用defer属性(放在<head>中,HTML解析完按序执行);2)使用async属性(下载完立即执行,不保证顺序);3)关键脚本内联在<head>中减小体积;4)非关键脚本放在body底部或使用dynamic import();5)代码分割,路由级懒加载减少初始加载体积。现代框架(Next.js、Nuxt.js)通过SSR解决首屏显示延迟问题。
Q233: 介绍 DOM 的发展 A: DOM发展历程:DOM 0:早期浏览器实现的非标准DOM,包括document.forms等集合和element.onclick事件。DOM 1(1998):W3C标准化,定义核心接口(Document、Element、Node、NodeList)。DOM 2(2000):引入事件模型(addEventListener、事件传播机制)、CSS样式访问(getComputedStyle)、遍历和范围(TreeWalker、Range)、视图(getClientRects)。DOM 3(2004):增加XPath、键盘事件(KeyboardEvent)、load/save、验证。DOM 4(2015):MutationObserver替代废弃的MutationEvents、自定义事件(CustomEvent)、Element方法增强(closest、before/after/replaceWith、prepend/append)、classList等。现代DOM API趋于稳定,更新的焦点在性能优化(如IntersectionObserver、ResizeObserver)和开发体验提升。
Q234: 介绍DOM0,DOM2,DOM3事件处理方式区别 A: DOM0:通过属性赋值绑定事件(element.onclick = handler),每个事件只能绑定一个处理函数,新绑定的覆盖旧的。只能使用冒泡阶段,只能通过返回值控制默认行为。移除:element.onclick = null。DOM2:通过addEventListener/removeEventListener绑定/移除,可绑定多个处理函数(顺序执行),第三个参数控制事件阶段(true捕获/false冒泡)。DOM3:在DOM2基础上新增事件类型(键盘事件keydown/keyup、触屏事件touchstart/touchend、滚轮事件wheel、自定义事件CustomEvent等),新增事件初始化方式(new Event() / new CustomEvent()),废弃initEvent等旧方法。现代开发始终使用DOM2方式(addEventListener),兼容性和灵活性最好。
Q235: 区分什么是客户区坐标、页面坐标、屏幕坐标 A: 鼠标事件的三种坐标:clientX/Y(客户区坐标)相对于浏览器视口左上角,不随页面滚动改变。常用于定位浮层、tooltip跟随鼠标。pageX/Y(页面坐标)相对于整个页面的左上角,随滚动改变。pageY = clientY + window.scrollY。screenX/Y(屏幕坐标)相对于物理屏幕左上角。offsetX/Y相对于事件目标元素的padding边缘。区分使用场景:固定位置的UI元素用client坐标,相对于页面的定位用page坐标。获取方式:e.clientX、e.pageX、e.screenX、e.offsetX。移动端触摸事件使用同样的坐标体系(changedTouches[0].clientX等)。
Q236: Javascript垃圾回收方法 A: V8垃圾回收机制:分代回收,新生代(Young Generation)存放短生命周期对象,使用Scavenge(Cheney算法)将存活对象复制到To空间,速度快。老生代(Old Generation)存放长生命周期对象,使用标记-清除(Mark-Sweep)和标记-整理(Mark-Compact)。标记阶段从根(全局对象、活动函数等)遍历标记所有可达对象,清除阶段回收未标记对象,整理阶段解决内存碎片。优化技术:增量标记(将标记工作拆分为小步,穿插在JS执行间隙)、并发标记(主线程不阻塞)、懒清除(延迟垃圾页清理)。开发者注意事项:避免创建大量临时对象增加GC压力,及时解除引用帮助GC识别不可达对象。
Q237: 请解释一下 JavaScript 的同源策略 A: 同源策略限制不同源(协议+域名+端口三者相同)的页面间互相访问数据。禁止行为:跨域读取Cookie/localStorage/IndexedDB、跨域操作DOM、跨域读取AJAX/fetch响应内容。允许行为:script/img/link/iframe等标签加载跨域资源(但不能读取返回内容)、form提交跨域。跨域解决方案:CORS(服务端设置Access-Control-Allow-Origin头)、JSONP(script标签加载,仅GET)、代理转发(Nginx/devServer proxy)、postMessage(跨窗口通信)、WebSocket(不受同源限制)。同源策略是Web安全的基石,防止了XSS、CSRF等攻击窃取数据。
Q238: 如何删除一个cookie A: 将Cookie过期时间设为过去时间即可删除:document.cookie = "name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"。或将max-age设为0:document.cookie = "name=; max-age=0; path=/;"。关键点:删除时必须与设置时使用相同的path和domain,否则无法删除。例如创建时用了path=/app,删除时也得用path=/app。HttpOnly标记的Cookie不能用JS删除,只能通过服务端Set-Cookie头覆盖。安全建议:登录/退出时服务端主动清除会话Cookie,避免依赖客户端删除。
Q239: 页面编码和被请求的资源编码如果不一致如何处理 A: 编码不一致导致乱码。处理方法:1)统一使用UTF-8编码(HTML通过<meta charset="UTF-8">声明);2)JS文件可在script标签指定charset:<script src="file.js" charset="gbk">;3)CSS文件开头的@charset声明(如@charset "UTF-8");4)服务端通过Content-Type响应头指定编码(Content-Type: text/javascript; charset=utf-8);5)HTML页面编码声明优先于HTTP头。最佳实践:所有文件统一UTF-8编码,配合构建工具统一编码输出,混合编码场景下明确指定charset属性。
Q240: 把script放在</body>之前和之后有什么区别? A: 放在</body>之前:标准做法,脚本在DOM构建完成后、body关闭前执行。此时DOM元素已存在,可正常操作DOM。放在</body>之后:不合规范,但浏览器会容错处理。浏览器解析到</body>后认为DOM完成,遇到后续script标签会重新解析或作为body的尾部内容处理。实际上两者效果差异不大(都在DOM就绪后执行),但前者是标准规范。现代最佳实践:使用defer属性的script放在<head>中,浏览器在HTML解析完成后按序执行,完全不阻塞DOM构建。或将脚本放在</body>之前(更传统的方式)。
Q241: JavaScript 中,调用函数有哪几种方式 A: 函数调用方式决定this指向:1)普通函数调用fn(),this指向全局(严格模式undefined);2)方法调用obj.fn(),this指向对象;3)构造函数调用new Fn(),this指向新实例;4)call调用fn.call(ctx, a, b),显式绑定this;5)apply调用fn.apply(ctx, [a, b]),显式绑定this+数组传参;6)bind预设this返回新函数fn.bind(ctx);7)箭头函数继承外层this;8)间接引用(0, obj.fn)()丢失this指向全局;9)事件处理函数中this指向绑定事件的元素。不同调用方式造成this指向差异是JavaScript初学者最容易困惑的地方,理解调用方式是掌握this的关键。
Q242: 列举一下JavaScript数组和对象有哪些原生方法? A: 数组方法:push/pop(栈)、shift/unshift(队列)、splice(增删改)、slice(截取)、concat(合并)、join(拼接字符串)、indexOf/lastIndexOf(查找索引)、includes(包含判断)、forEach(遍历)、map(映射)、filter(过滤)、reduce/reduceRight(归约)、every/some(条件检测)、find/findIndex(查找)、sort(排序)、reverse(反转)、flat/flatMap(扁平化)、fill(填充)、Array.from(类数组转换)、Array.isArray(判断)。对象方法:Object.keys(键数组)、Object.values(值数组)、Object.entries(键值对数组)、Object.assign(合并)、Object.freeze(冻结)、Object.seal(密封)、Object.create(原型创建)、Object.defineProperty(属性定义)、Object.getPrototypeOf(获取原型)。
Q243: Array.slice() 与 Array.splice() 的区别? A: slice(切片)返回数组片段的新数组,不修改原数组。arr.slice(start, end)提取从start到end(不含)的元素,支持负数索引。只传start提取到末尾。splice(拼接)修改原数组,返回被删除元素。arr.splice(start, deleteCount, ...items)从start删除deleteCount个元素,再插入items。deleteCount为0时不删除只插入。示例:[1,2,3,4].slice(1,3) -> [2,3](原数组不变)。[1,2,3,4].splice(1,2,'a','b') -> [2,3](原数组变为[1,'a','b',4])。区分:slice是纯函数(不修改输入,推荐函数式编程),splice会修改原数组。
Q244: MVVM A: MVVM指Model-View-ViewModel架构模式。Model(数据层)定义业务数据和规则。View(视图层)即UI界面。ViewModel(视图模型)连接Model和View,通过数据绑定实现自动同步。Vue采用类似MVVM的架构(虽然不是严格实现),data对应Model、模板对应View、组件实例对应ViewModel。核心机制:响应式数据(Object.defineProperty/Proxy)实现数据变化自动更新视图;事件绑定/指令实现视图交互更新数据。MVVM优势:开发者只需维护ViewModel中的数据状态,无需手动操作DOM操作,实现了声明式UI编程,大大提升了开发效率和代码可维护性。
Q245: WEB应用从服务器主动推送Data到客户端有那些方式 A: 服务端主动推送方式:1)WebSocket,最推荐,全双工通信,适用于即时通讯、游戏、协同编辑等高实时场景;2)Server-Sent Events(SSE),基于HTTP的单向推送,客户端用EventSource接收,自动重连,适合服务端到客户端的单向通知(消息提醒、股票行情);3)长轮询(Long Polling),客户端发起请求,服务端保持连接直到有新数据,兼容性好但资源浪费;4)HTTP/2 Server Push(逐渐废弃);5)WebRTC,点对点通信(视频通话、文件传输)。选择建议:双向通信用WebSocket,服务端到客户端单向通知用SSE(更简单),兼容旧浏览器用长轮询。
Q246: 继承 A: JavaScript继承方式:1)原型链继承Child.prototype = new Parent()(引用类型属性共享);2)借用构造函数function Child() { Parent.call(this) }(解决了属性共享但方法不能复用);3)组合继承(原型链 + 构造)最常用但调两次父类构造函数;4)原型式继承Object.create(obj);5)寄生式继承在原型式基础上增强;6)寄生组合继承使用Object.create(Parent.prototype)创建原型副本,是最优方案(ES6 class原理);7)ES6 class extends语法糖,最简洁推荐。class A extends B { } 相当于寄生组合继承,内部调用super()执行父类构造函数。大多数场景使用class extends即可。
Q247: 有四个操作会忽略enumerable为false的属性 A: 以下操作会忽略enumerable:false(不可枚举)的属性:1)for...in循环(遍历自身+原型链的可枚举属性);2)Object.keys()(只返回自身可枚举属性);3)JSON.stringify()(只序列化可枚举属性);4)Object.assign()(只复制可枚举的自有属性)。需要访问不可枚举属性时使用:Object.getOwnPropertyNames()(包括不可枚举但不包括Symbol)、Object.getOwnPropertySymbols()(包括Symbol属性)、Reflect.ownKeys()(获取所有自身属性,包括不可枚举和Symbol)。理解这一点对处理Object.defineProperty定义的属性场景很有帮助。
Q248: 属性的遍历 A: 遍历对象属性的五种方式对比:1)for...in遍历自身和原型链的所有可枚举属性(不含Symbol),需配合hasOwnProperty过滤;2)Object.keys()返回自身可枚举属性名的数组;3)Object.getOwnPropertyNames()返回自身所有属性名(包括不可枚举);4)Object.getOwnPropertySymbols()返回自身所有Symbol属性;5)Reflect.ownKeys()返回自身所有属性(包括不可枚举和Symbol),最完整。遍历顺序:数字键按升序、字符串键按创建顺序、Symbol键按创建顺序。日常使用:Object.keys()用于通用遍历,Reflect.ownKeys()用于元编程场景。
Q249: 为什么通常在发送数据埋点请求的时候使用的是 1x1 像素的透明 gif 图片 A: 原因:1)跨域支持,img标签不受同源限制,可发往任意域名;2)兼容性好,所有浏览器支持Image对象;3)不阻塞页面,图片请求异步,不影响渲染;4)体积最小,1x1透明GIF仅42字节;5)无需处理响应,埋点只关心发送成功;6)GIF支持透明。实现:new Image().src = 'https://track.example.com/collect?event=click'。或使用navigator.sendBeacon()在页面卸载时也能可靠发送数据。sendBeacon是更现代的替代方案,它确保数据在页面关闭时也会发送,且不阻塞页面卸载。
Q250: 在输入框中如何判断输入的是一个正确的网址 A: 判断网址是否合法:1)URL构造函数(最可靠)function isValidUrl(str) { try { new URL(str); return true; } catch { return false; } }。缺协议前缀(如"example.com")会抛异常,可按需自动补https://前缀检测。2)正则表达式检测格式:/^https?://[\w-]+(.[\w-]+)+[/#?]?.*$/i.test(str)。更严格的正则需校验域名合法性(如顶级域名长度)。3)HTML5输入类型:<input type="url">提供基础格式验证。推荐使用URL构造函数 + try-catch,兼顾准确性和简洁性。实际业务中还需考虑国际化域名(IDN)等特殊情况。
Q251: 常用设计模式有哪些并举例使用场景 A: 设计模式在前端中的典型应用:1)单例模式,全局状态管理(Pinia/Vuex store)、全局弹窗、Logger,实现static getInstance()保证全局唯一;2)工厂模式,根据不同配置创建不同UI组件(如按钮类型、图表类型);3)观察者模式,Vue响应式系统(Dep收集Watcher)、EventBus、自定义事件;4)策略模式,表单验证规则(验证器可替换组合)、动画缓动函数、排序算法可切换;5)装饰器模式,高阶组件HOC(withAuth、withLogging)、Python装饰器类似概念;6)适配器模式,统一不同API数据格式(兼容旧接口)、React Native桥接;7)代理模式,图片懒加载虚拟代理、缓存代理、防抖节流代理。
Q252: 原型链判断 A: 判断对象与原型关系的方法:1)instanceof运算符,obj instanceof Constructor判断构造函数的prototype是否在obj原型链上。限制:跨iframe失效(不同全局执行环境,构造函数引用不同)。2)isPrototypeOf方法,Parent.prototype.isPrototypeOf(obj),判断原型对象是否在obj的原型链上。3)Object.getPrototypeOf(obj)获取对象直接原型。4)__proto__属性(非标准)直接访问原型。5)Object.prototype.toString.call(obj)返回Class标记(如'[object Array]')。创建无原型的对象:Object.create(null),其__proto__为undefined,instanceof始终返回false,适合做纯字典对象(没有toString等继承属性干扰)。
Q253: RAF 和 RIC 是什么 A: requestAnimationFrame(rAF):在下次重绘前执行回调,与屏幕刷新率同步(60Hz约16.7ms一次)。最适合动画循环,页面不可见时自动暂停节省性能。用法:function animate() { update(); requestAnimationFrame(animate); } requestAnimationFrame(animate)。requestIdleCallback(RIC):在浏览器空闲时执行回调,利用deadline.timeRemaining()判断剩余时间。适合执行非紧急任务(数据上报、预加载、日志记录)。用法:requestIdleCallback((deadline) => { while (deadline.timeRemaining() > 0) { processChunk(); } }, { timeout: 3000 })。区别:rAF保证视觉流畅(高优先级),RIC利用空闲时间(低优先级),两者配合实现帧率和后台任务的最佳平衡。
Q254: js自定义事件 A: 自定义事件实现组件/模块间解耦通信。方式:1)new Event('myEvent', { bubbles: true }) + element.dispatchEvent(event);2)new CustomEvent('myEvent', { detail: { data: 123 } })(CustomEvent可携带数据)。监听:element.addEventListener('myEvent', handler)。事件对象属性:type(事件名)、detail(CustomEvent传递的数据)、bubbles(是否冒泡)。应用:组件通信(兄弟或跨层级)、发布订阅模式、解耦业务逻辑。注意:自定义事件可冒泡到父元素,在document上监听可实现全局事件通知。使用dispatcheEvent触发同步执行监听器。
Q255: 前端性能定位、优化指标以及计算方法 A: 核心性能指标:1)FP(First Paint),首次绘制。performance.getEntriesByType('paint')[0].startTime。2)FCP(First Contentful Paint),首次内容绘制。performance.getEntriesByType('paint')[1].startTime。目标<1.8s。3)LCP(Largest Contentful Paint),最大内容绘制。PerformanceObserver监听largest-contentful-paint。目标<2.5s。4)FID(First Input Delay),首次输入延迟。目标<100ms。5)CLS(Cumulative Layout Shift),累计布局偏移。计算每次偏移得分之和。目标<0.1。6)TTFB(Time to First Byte),首字节时间。目标<800ms。7)TBT(Total Blocking Time),总阻塞时间。工具:Lighthouse(自动化审计)、Chrome DevTools Performance面板(手动分析)、web-vitals库(RUM真实用户监控)、自定义performance.mark/measure打点。
Q256: 谈谈你对函数是一等公民的理解 A: "函数是一等公民"指函数与其他数据类型地位相同:1)可赋值给变量(const fn = () => {});2)可作为参数传递(arr.map(x => x * 2)中的回调);3)可作为返回值(闭包中函数返回函数);4)可存储在数据结构中(对象的方法、数组中的函数);5)支持动态创建(箭头函数、匿名函数、new Function())。JS函数集"对象"(有属性和方法)、"可调用"(()执行)、"一等公民"三重身份于一身。这意味着JS支持高阶函数(函数操作函数)、闭包(函数捕获环境)、函数式编程(纯函数、不可变数据)。这种灵活性使得JS能同时支持面向对象、函数式、命令式多种编程范式。
微信小程序
Q257: 微信小程序有几个文件 A: 小程序一个页面由四个文件组成:.wxml(页面结构,类似HTML)、.wxss(页面样式,类CSS但有扩展)、.js(页面逻辑,生命周期、事件、数据)、.json(页面配置,导航栏、窗口样式)。App级别的文件:app.js(全局逻辑,App生命周期)、app.json(全局配置,页面注册、窗口、tabBar等)、app.wxss(全局样式)。此外还有project.config.json(项目工具配置)、sitemap.json(搜索引擎索引)。小程序的组件结构与页面相似,也由四个文件组成(.wxml/.wxss/.js/.json)。文件命名需与页面路径一致。
Q258: 微信小程序怎样跟事件传值 A: 小程序事件传值方式:1)通过data-*属性传值,在组件上绑定<view data-user-id="123" bindtap="handleTap">,事件函数中通过e.currentTarget.dataset.userId获取(注意data-属性名自动转驼峰)。2)自定义组件通过triggerEvent向父组件传递数据:this.triggerEvent('myevent', { id: 123 }),父组件bind:myevent="onMyEvent"监听,使用e.detail获取传递的数据。3)全局数据共享:通过App实例的globalData或getApp()获取全局数据。4)使用第三方状态管理库(如mobx-miniprogram)。推荐:父子组件通信用triggerEvent,跨页面传参用URL参数或全局数据。
Q259: 小程序的 wxss 和 css 有哪些不一样的地方? A: WXSS与CSS的主要差异:1)尺寸单位,WXSS引入rpx(responsive pixel),以屏幕宽度750rpx为基准自适应,CSS无此单位;2)选择器限制,WXSS不支持通配符*、不支持:visited/:hover等伪类(部分支持:focus)、不支持父子选择器>(微信开发者工具支持但真机有限制);3)样式隔离,WXSS组件样式默认隔离(类似scoped),外部样式不影响组件内部,CSS需通过CSS Modules或scoped实现类似效果;4)全局样式,WXSS通过app.wxss定义全局样式,其他页面或组件wxss只影响自身;5)@import语法两者都支持。WXSS还支持一些特有的选择器(如:host选择自定义组件根节点)。
Q260: 小程序关联微信公众号如何确定用户的唯一性 A: 通过UnionID机制确定用户唯一性。前提:小程序和公众号绑定到同一个微信开放平台(Open Platform)账号。UnionID是用户在微信开放平台下的唯一标识,同一开放平台下的小程序、公众号、网站应用的unionid相同。获取方式:1)用户在小程序中登录(wx.login()获取code),后端调用https://api.weixin.qq.com/sns/jscode2session接口,返回数据中包含openid和unionid(需用户在公众号已授权或有绑定关系)。2)用户通过公众号网页授权(OAuth 2.0)也能获取unionid。使用unionid作为用户唯一标识,即可打通小程序和公众号的用户体系。如果不需要跨应用统一标识,用openid即可(同一应用内唯一)。
Q261: 微信小程序与vue区别 A: 差异点:1)数据绑定,Vue用和v-bind指令;小程序用和Mustache语法;2)事件处理,Vue用@click;小程序用bindtap/catchtap(catchtap阻止冒泡);3)条件渲染,Vue用v-if/v-show;小程序用wx:if/hidden;4)列表渲染,Vue用v-for :key;小程序用wx:for wx:key;5)组件化,Vue单文件组件(.vue),小程序四文件结构(wxml/wxss/js/json);6)生命周期,Vue有created/mounted等;小程序有onLoad/onShow/onReady/onHide等;7)运行环境,Vue在浏览器DOM环境;小程序在双线程架构(逻辑层与渲染层隔离,无完整DOM API);8)路由,Vue Router控制;小程序通过app.json注册页面,wx.navigateTo跳转。两者设计思想有共通之处,但技术实现差异较大。
Webpack/工程化
Q262: 优化 webpack 打包体积的思路 A: 减包策略:1)Tree Shaking移除未引用代码,需ES Module(静态导入),mode:'production'自动启用,配合package.json sideEffects:false声明无副作用模块。2)代码分割,splitChunks提取公共依赖(vendors/common),路由级懒加载使用import()动态导入。3)压缩,TerserPlugin压缩JS,CssMinimizerPlugin压缩CSS,HtmlMinifier压缩HTML。4)图片优化,小图base64内联(asset/inline),大图压缩(image-webpack-loader)。5)按需引入,lodash-es替代lodash,UI框架用babel-plugin-import按需加载。6)externals将库外置(如React通过CDN加载不打包)。7)BundleAnalyzerPlugin分析产物,针对性优化大模块。
Q263: 优化 webpack 打包效率的方法 A: 提速策略:1)开启持久化缓存,Webpack 5内置cache: { type: 'filesystem' },二次编译秒开;2)Loader开启缓存(babel-loader cacheDirectory、eslint-loader cache);3)多进程构建,thread-loader(耗时Loader后添加),eslint/terser插件支持parallel多进程;4)减少Loader处理范围,include/exclude限定目录(排除node_modules);5)resolve优化,extensions限制常用后缀、alias减少搜索路径、modules指定node_modules路径;6)开发环境使用eval-cheap-module-source-map减少SourceMap开销;7)升级Webpack 5 + 最新Node.js + yarn PnP;8)使用webpack-bundle-analyzer分析优化。对于新项目,考虑Vite(基于ESM,开发启动速度极快)。
Q264: 编写Loader A: Loader本质是导出函数的模块,接收源文件内容返回处理结果。基础Loader:module.exports = function(source) { return source.replace(/console.log/g, '// console.log'); };。异步Loader:module.exports = function(source) { const callback = this.async(); fs.readFile(path, (err, data) => { callback(null, source + data); }); };。pitch方法在Loader链中按序执行(pitch从右到左,normal从左到右)。获取options:通过this.query或schema-utils校验(配合loader-utils.getOptions)。配置:{ test: /.js$/, use: ['babel-loader', { loader: 'my-loader', options: { flag: true } }] }。常见Loader类型:转换Loader(ts->js)、校验Loader(eslint)、资源Loader(file-loader)。
Q265: 编写plugin A: Plugin是具有apply方法的类,通过Webpack生命周期钩子注入逻辑。基本结构:class MyPlugin { constructor(options) { this.options = options; } apply(compiler) { compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => { // 操作compilation.assets修改输出资源 compilation.assets['new-file.json'] = { source: () => JSON.stringify(this.options), size: () => JSON.stringify(this.options).length }; callback(); }); } }。关键hook:run(开始运行)、compile(开始编译)、thisCompilation(创建compilation对象)、emit(输出assets到output前)、done(编译完成)。compiler代表整个Webpack配置,compilation代表当前一次构建。Plugin可以访问compiler和compilation,实现Loader无法做到的操作(文件操作、资源注入、环境变量定义等)。
Q266: 说一下webpack的一些plugin,怎么使用webpack对项目进行优化 A: 常用优化Plugin:HtmlWebpackPlugin,自动生成HTML并注入资源链接,支持模板定制。MiniCssExtractPlugin,将CSS提取为独立文件(替代style-loader),并行加载CSS。TerserPlugin,压缩JS(多进程并行),mode:production默认启用。CssMinimizerPlugin,压缩CSS。BundleAnalyzerPlugin,可视化分析包体积。DefinePlugin,定义编译时全局常量(如process.env.NODE_ENV)用于Tree Shaking。IgnorePlugin,忽略特定模块(如moment的locale目录减少体积)。ProvidePlugin,自动加载模块($ = 'jquery',不用手动import)。SpeedMeasurePlugin,测量各Loader/Plugin耗时定位性能瓶颈。组合使用:HtmlWebpackPlugin + MiniCssExtractPlugin + TerserPlugin + BundleAnalyzerPlugin是标准配置。
Q267: webpack Plugin 和 Loader 的区别 A: Loader和Plugin的本质区别:Loader是文件转换器,在模块加载阶段工作,针对单个文件进行转换(如ts->js、sass->css)。在module.rules中配置,通过test匹配文件类型。职责单一,可链式组合。Plugin是生命周期钩子,可以访问Webpack整个构建过程(compiler和compilation),在构建的各个阶段(完成、输出前、优化等)注入自定义行为。在plugins数组中实例化配置,可以做更广泛的操作(资源注入、文件生成、环境定义)。类比:Loader相当于"处理器"处理单个文件,Plugin相当于"调度员"控制整个构建流程。更本质的区别:Loader操作文件内容,Plugin操作构建过程。
Q268: tree shaking 的原理是什么 A: Tree Shaking原理:基于ES Module的静态语法分析(import/export在编译时确定而非运行时),构建工具解析AST(抽象语法树)识别模块的导出和导入关系,标记未被使用的导出为"dead code",最后由压缩工具(Terser)移除。实现条件:1)ES Module语法(静态导入导出),CommonJS的require()是动态的无法静态分析;2)package.json配置sideEffects: false(告诉Webpack所有模块无副作用,安全移除未用代码)或指定有副作用的文件路径;3)生产模式(mode:'production')自动启用TerserPlugin tree shaking。常见问题:导入但只用了部分的库(如import { debounce } from 'lodash'优化为lodash-es)。
Q269: common.js 和 es6 中模块引入的区别 A: 区别:1)加载时机,CommonJS运行时加载(执行到require才加载);ES Module编译时静态加载(代码解析阶段确定依赖)。2)语法,CommonJS用require()/module.exports;ES Module用import/export。3)值的传递,CommonJS输出值拷贝(模块内部变化不影响已加载值);ES Module输出值引用(模块内部变化反映到已加载的地方,且导入值是只读的)。4)异步性,CommonJS同步加载(适合服务端磁盘读取);ES Module支持import()动态导入(异步,适合浏览器网络加载)。5)顶层this,CommonJS指向module.exports;ES Module是undefined(自动严格模式)。6)循环依赖,CommonJS返回未完成的部分值;ES Module静态分析更可靠。
Q270: babel原理 A: Babel编译流程三步:1)解析(Parse),词法分析将源码拆为token流,语法分析将token转为AST(Abstract Syntax Tree,抽象语法树),使用@babel/parser。2)转换(Transform),遍历AST的节点,应用plugin/preset注册的转换规则(匹配节点类型并替换、插入、删除节点),这是Babel的核心步骤。@babel/traverse负责AST遍历和操作。3)生成(Generate),将修改后的AST重新转为代码字符串,并生成Source Map,使用@babel/generator。核心预设:@babel/preset-env根据browserslist配置自动确定所需转换和polyfill;@babel/preset-react转换JSX;@babel/preset-typescript转换TypeScript。运行时辅助:@babel/plugin-transform-runtime复用helper代码避免重复注入。
框架(Vue/React/路由)
Q271: Vue 响应式原理 A: Vue 2通过Object.defineProperty()递归将data属性转为getter/setter。每个组件有Watcher实例,渲染时访问属性触发getter,Watcher被收集到Dep依赖列表中。属性变化触发setter,Dep通知所有Watcher重新渲染。由于无法检测属性新增/删除,Vue 2提供了Vue.set/Vue.delete。Vue 3改用Proxy,直接代理整个对象,能拦截属性增删、数组索引修改等所有操作,无需特殊API。Vue 3使用WeakMap存储依赖关系(target->key->effect),避免内存泄漏。同时Vue 3编译优化(静态标记、patchFlag、block tree)大幅减少diff范围。Vue 3的响应式API可从vue中单独导出使用(ref、reactive、computed等)。
Q272: Vue nextTick 原理 A: Vue的DOM更新是异步的(批量异步策略)。数据变化后Watcher被推入异步队列,同一事件循环中所有数据变更累积完成后统一执行DOM更新。nextTick将回调延迟到下次DOM更新循环结束后执行。实现原理:利用JS微任务/宏任务机制,按优先级降级使用Promise.then(微任务)-> MutationObserver(微任务)-> setImmediate(宏任务,IE)-> setTimeout(宏任务)。nextTick(callback)在DOM更新完成后执行回调,可获取更新后的DOM状态。使用场景:数据变更后需要立即读取新DOM的状态(如滚动位置、元素尺寸),将操作放在nextTick中。
Q273: Vue diff 原理 A: Vue的diff算法比较新旧虚拟DOM差异,最小化真实DOM操作。Vue 2双端比较(Snabbdom):同时从新旧VNode数组的两端向中间遍历,进行4种对比(新前旧前、新后旧后、新后旧前、新前旧后),通过头尾移动减少DOM操作。Vue 3优化:1)基于patchFlag在编译时标记动态内容(区分静态和动态节点),只对比动态节点;2)使用最长递增子序列算法优化节点移动(找最少移动次数的稳定序列);3)静态提升(hoistStatic)将不变的节点提升到渲染函数外。同层比较(不跨层级),时间复杂度O(n)。key属性帮助diff准确识别VNode身份,建议用稳定id作为key而非index。
Q274: 路由原理 history 和 hash 两种路由方式的特点 A: Hash路由:利用URL #符号后的hash部分(http://example.com/#/home)。hash变化不会触发页面请求,通过window.onhashchange事件监听变化。优点:兼容性好,无需服务端配置,刷新页面不会404。缺点:URL含#不够美观,hash不能用于服务端获取数据。History路由:利用HTML5 History API(pushState/replaceState)改变URL路径而不刷新页面。监听popstate事件处理浏览器前进后退。优点:URL美观(无#),与正常URL无异,SEO更好(服务端渲染时)。缺点:需服务端配置(所有路由都指向index.html),否则刷新页面会404。现代前端应用推荐History路由配合Nginx配置:try_files $uri $uri/ /index.html。
微信小程序
Q257: 微信小程序有几个文件 A: 小程序一个页面由四个文件组成:.wxml(页面结构,类似HTML)、.wxss(页面样式,类CSS但有扩展)、.js(页面逻辑,生命周期、事件、数据)、.json(页面配置,导航栏、窗口样式)。App级别的文件:app.js(全局逻辑,App生命周期)、app.json(全局配置,页面注册、窗口、tabBar等)、app.wxss(全局样式)。此外还有project.config.json(项目工具配置)、sitemap.json(搜索引擎索引)。小程序的组件结构与页面相似,也由四个文件组成(.wxml/.wxss/.js/.json)。
Q258: 微信小程序怎样跟事件传值 A: 小程序事件传值方式:1)通过data-*属性传值,在组件上绑定<view data-user-id="123" bindtap="handleTap">,事件函数中通过e.currentTarget.dataset.userId获取(data-属性名自动转驼峰)。2)自定义组件通过triggerEvent向父组件传值:this.triggerEvent('myevent', { id: 123 }),父组件bind:myevent="onMyEvent"监听,使用e.detail获取传递的数据。3)全局数据共享:通过App实例的globalData或getApp()获取全局数据。推荐:父子组件通信用triggerEvent,跨页面传参用URL参数或全局数据。
Q259: 小程序的 wxss 和 css 有哪些不一样的地方? A: WXSS与CSS的主要差异:1)尺寸单位,WXSS引入rpx(responsive pixel),以屏幕宽度750rpx为基准自适应;2)选择器限制,WXSS不支持通配符*,不支持:visited/:hover等大部分伪类,不支持父子选择器>;3)样式隔离,WXSS组件样式默认隔离(类似scoped),外部样式不影响组件内部;4)全局样式,WXSS通过app.wxss定义全局样式,其他页面或组件wxss只影响自身;5)@import语法两者都支持。WXSS还支持:host选择自定义组件根节点。
Q260: 小程序关联微信公众号如何确定用户的唯一性 A: 通过UnionID机制确定唯一性。前提:小程序和公众号绑定到同一个微信开放平台账号。UnionID是用户在开放平台下的唯一标识,同一开放平台下的小程序、公众号、网站应用的unionid相同。获取方式:用户在小程序中登录(wx.login()获取code),后端调用jscode2session接口。如果用户已在公众号或开放平台授权过,返回数据中会包含unionid。使用unionid作为用户唯一标识可打通小程序和公众号的用户体系。如果不需要跨应用统一标识,用openid即可(同一应用内唯一)。
Q261: 微信小程序与vue区别 A: 差异点:1)数据绑定,Vue用和v-bind指令;小程序用和Mustache语法;2)事件处理,Vue用@click;小程序用bindtap/catchtap(catchtap阻止冒泡);3)条件渲染,Vue用v-if/v-show;小程序用wx:if/hidden;4)列表渲染,Vue用v-for :key;小程序用wx:for wx:key;5)组件化,Vue单文件组件(.vue),小程序四文件结构(wxml/wxss/js/json);6)生命周期,Vue有created/mounted等;小程序有onLoad/onShow/onReady/onHide等;7)运行环境,Vue在浏览器DOM环境;小程序在双线程架构(逻辑层与渲染层隔离,无完整DOM API);8)路由,Vue Router控制;小程序通过app.json注册页面,wx.navigateTo跳转。
Webpack/工程化
Q262: 优化 webpack 打包体积的思路 A: 减包策略:1)Tree Shaking移除未引用代码,需ES Module,mode:'production'自动启用,配合package.json sideEffects:false;2)代码分割,splitChunks提取公共依赖,路由级懒加载使用import();3)压缩,TerserPlugin压缩JS,CssMinimizerPlugin压缩CSS,HtmlMinifier压缩HTML;4)图片优化,小图base64内联,大图用image-webpack-loader压缩;5)按需引入,lodash-es替代lodash,UI框架用babel-plugin-import;6)externals将库外置到CDN;7)BundleAnalyzerPlugin分析产物针对性优化。
Q263: 优化 webpack 打包效率的方法 A: 提速策略:1)开启持久化缓存,Webpack 5内置cache: { type: 'filesystem' };2)Loader开启缓存(babel-loader cacheDirectory);3)多进程构建,thread-loader(耗时Loader后添加),terser-webpack-plugin开启parallel;4)减小Loader处理范围,include/exclude限定目录;5)resolve优化,extensions限制常用后缀、alias减少搜索;6)开发环境用eval-cheap-module-source-map;7)升级Webpack 5 + 最新Node.js;8)使用webpack-bundle-analyzer分析。新项目可考虑Vite(基于ESM,开发启动速度极快)。
Q264: 编写Loader A: Loader是导出函数的模块,接收源文件内容返回处理结果。基础Loader:module.exports = function(source) { return source.replace(/console.log/g, '// console.log'); };。异步Loader:module.exports = function(source) { const callback = this.async(); setTimeout(() => callback(null, source + '/* transformed */'), 1000); };。获取options通过this.query配合schema-utils校验。Loader配置:{ test: /.js$/, use: ['babel-loader', { loader: 'my-loader', options: {} }] }。Loader执行顺序从右到左(从下到上)。常见类型:转换Loader(ts->js)、校验Loader(eslint)、资源Loader(file-loader)。
Q265: 编写plugin A: Plugin是具有apply方法的类,通过Webpack生命周期钩子注入逻辑。基本结构:class MyPlugin { constructor(options) { this.options = options; } apply(compiler) { compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => { compilation.assets['new-file.json'] = { source: () => JSON.stringify(this.options), size: () => JSON.stringify(this.options).length }; callback(); }); } }。关键hook:run、compile、thisCompilation、emit(输出前)、done(完成)。compiler代表整个Webpack配置,compilation代表当前一次构建。Plugin可以访问compiler和compilation实现Loader无法做到的操作(文件操作、资源注入、环境变量定义等)。通过tap/tapAsync/tapPromise注册同步/异步钩子。
Q266: 说一下webpack的一些plugin,怎么使用webpack对项目进行优化 A: 常用优化Plugin:HtmlWebpackPlugin自动生成HTML并注入资源;MiniCssExtractPlugin将CSS提取为独立文件;TerserPlugin压缩JS(多进程);CssMinimizerPlugin压缩CSS;BundleAnalyzerPlugin可视化分析包体积;DefinePlugin定义编译时全局常量用于Tree Shaking;IgnorePlugin忽略特定模块(如moment的locale);ProvidePlugin自动加载模块;SpeedMeasurePlugin测量各Loader/Plugin耗时。标准生产配置:HtmlWebpackPlugin + MiniCssExtractPlugin + TerserPlugin + CssMinimizerPlugin。通过BundleAnalyzerPlugin分析结果针对性优化大模块。
Q267: webpack Plugin 和 Loader 的区别 A: Loader是文件转换器,在模块加载阶段工作,针对单个文件进行转换(如ts->js、sass->css)。在module.rules中配置,通过test匹配文件类型,可链式组合。Plugin是生命周期钩子,可访问Webpack整个构建过程(compiler和compilation),在构建各阶段注入行为。在plugins数组中实例化配置。类比:Loader=处理器(操作文件内容),Plugin=调度员(控制构建流程)。本质区别:Loader在文件级别操作,Plugin在构建过程级别操作,能做更广泛的事情。
Q268: tree shaking 的原理是什么 A: Tree Shaking基于ES Module的静态语法分析,构建工具解析AST识别模块导出/导入关系,标记未使用的导出为dead code,由压缩工具(Terser)移除。实现条件:1)ES Module语法(import/export静态),CommonJS的require()动态无法静态分析;2)sideEffects: false声明模块无副作用;3)生产模式自动启用。注意:导入但只用了部分的库建议用子路径导入(如import debounce from 'lodash/debounce'),或用lodash-es替代lodash以获得更好的tree-shaking效果。
Q269: common.js 和 es6 中模块引入的区别 A: 区别:1)加载时机,CommonJS运行时加载(执行到require才加载);ES Module编译时静态加载(代码解析阶段确定依赖)。2)语法,CommonJS用require()/module.exports;ES Module用import/export。3)值传递,CommonJS输出值拷贝(模块内部变化不影响已加载的值);ES Module输出值引用(模块内部变化反映到已加载处,导入值只读)。4)异步性,CommonJS同步(适合服务端);ES Module支持import()动态异步导入(适合浏览器)。5)顶层this,CommonJS指向module.exports;ES Module为undefined。6)循环依赖,CommonJS可能返回未完成的值,ES Module更可靠。
Q270: babel原理 A: Babel编译流程三步:1)解析,词法分析拆token流,语法分析转AST,使用@babel/parser。2)转换,遍历AST节点,应用plugin/preset规则进行增删改(核心步骤),使用@babel/traverse。3)生成,将修改后的AST转回代码字符串并生成SourceMap,使用@babel/generator。核心预设:@babel/preset-env根据browserslist自动确定转换和polyfill;@babel/preset-react转换JSX;@babel/preset-typescript转换TypeScript。运行时:@babel/plugin-transform-runtime复用helper代码避免重复注入,core-js提供polyfill(Promise、Array.includes等API补丁)。
框架(Vue/React/路由)
Q271: Vue 响应式原理 A: Vue 2通过Object.defineProperty()递归将data属性转为getter/setter。每个组件有Watcher,渲染时访问属性触发getter将Watcher加入Dep,属性变化触发setter通知所有Watcher重新渲染。Vue 3改用Proxy直接代理整个对象,可拦截属性增删、数组索引修改等所有操作,无需Vue.set/Vue.delete等特殊API。Vue 3使用WeakMap存储依赖避免内存泄漏。编译优化:静态标记(patchFlag)、静态提升(hoistStatic)、block tree大幅减少diff范围。Vue 3的响应式API也可单独使用(ref、reactive、computed、watch等)。
Q272: Vue nextTick 原理 A: Vue DOM更新异步的(批量策略)。数据变化后Watcher入异步队列,同一事件循环所有变更累积后统一DOM更新。nextTick回调在DOM更新完成后执行。原理:按优先级使用Promise.then(微任务)-> MutationObserver(微任务)-> setImmediate(宏任务,IE)-> setTimeout(宏任务)。使用场景:数据变更后需立即读取新DOM状态(如滚动位置、元素尺寸),将操作放入nextTick回调。async/await用法:await Vue.nextTick()或使用框架提供的钩子(Vue 3的onUpdated、Vue 2的updated)。
Q273: Vue diff 原理 A: Vue的diff同层比较新旧虚拟DOM差异。Vue 2双端比较(Snabbdom):新旧VNode数组两端向中间遍历,四种对比(新前旧前、新后旧后、新后旧前、新前旧后),头尾移动减少DOM操作。Vue 3优化:基于patchFlag编译时标记动态内容只对比动态节点;最长递增子序列算法减少移动次数;静态提升将不变节点提升到渲染函数外。key属性帮助diff准确识别VNode身份,建议用稳定id作为key而非index(index作为key可能导致性能问题和状态错乱)。时间复杂度O(n)。
Q274: 路由原理 history 和 hash 两种路由方式的特点 A: Hash路由利用URL #后的hash部分路由切换,通过onhashchange监听变化。优点:兼容性好,无需服务端配置,刷新不404。缺点:URL含#不美观,hash不能传给服务端。History路由利用HTML5 History API(pushState/replaceState)改变URL不刷新页面,通过popstate监听前进后退。优点:URL美观无#,支持SSR。缺点:需服务端配置(所有路由指向index.html),否则刷新404。现代前端应用推荐History路由,配合Nginx配置try_files $uri $uri/ /index.html。
手写代码
Q275: 写一个通用的事件侦听器函数 A: 通用事件绑定:function addEvent(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, function(e) { handler.call(element, e); }); } else { element['on' + type] = handler; } }。移除事件类似(removeEventListener/detachEvent/置null)。现代浏览器全面支持addEventListener,attachEvent仅需兼容IE8-。实际开发直接用addEventListener即可,无需兼容封装。使用options参数可传入{ once: true }让事件只执行一次自动解绑。
Q276: 如何判断一个对象是否为数组 A: 方法:1)Array.isArray(obj)(ES6,推荐,跨iframe安全);2)Object.prototype.toString.call(obj) === '[object Array]'(最通用,兼容所有环境,跨iframe安全);3)obj instanceof Array(原型链判断,跨iframe失效);4)obj.constructor === Array(跨iframe失效)。推荐Array.isArray,需要兼容IE8-时用toString方式。实现原理:不同全局环境的Array构造函数不同,但Object.prototype.toString返回的Class标记恒定。polyfill:if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }。
Q277: 冒泡排序 A: 重复遍历数组,比较相邻元素交换顺序错误的。平均/最坏O(n^2),最好O(n)。空间O(1)。稳定排序。代码:function bubbleSort(arr) { const len = arr.length; for (let i = 0; i < len - 1; i++) { let swapped = false; for (let j = 0; j < len - 1 - i; j++) { if (arr[j] > arr[j + 1]) { [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; swapped = true; } } if (!swapped) break; } return arr; }。优化:swapped标志检测本轮是否交换(未交换则已有序提前退出)。冒泡排序性能差,不用于生产数据排序,主要用于教学理解排序过程。
Q278: 快速排序 A: 分治策略,选基准值,小于基准放左,大于放右,递归排序。平均O(n log n),最坏O(n^2)(已排序+固定基准),空间O(log n)(递归栈)。不稳定。实现:function quickSort(arr) { if (arr.length <= 1) return arr; const pivot = arr[Math.floor(arr.length / 2)]; const left = [], right = [], mid = []; for (const val of arr) { if (val < pivot) left.push(val); else if (val > pivot) right.push(val); else mid.push(val); } return [...quickSort(left), ...mid, ...quickSort(right)]; }。优化:随机选基准避免最坏情况、三数取中法、小数组切插入排序。原地快排用双指针交换节省内存。V8 Array.sort用TimSort(归并+插入),稳定O(n log n)。
Q279: 编写一个方法 求一个字符串的字节长度 A: UTF-8编码下:英文字母1字节,中文3字节。实现:1)function byteLength(str) { let len = 0; for (let i = 0; i < str.length; i++) { const code = str.charCodeAt(i); if (code <= 0x007f) len += 1; else if (code <= 0x07ff) len += 2; else if (code <= 0xffff) len += 3; else len += 4; } return len; }。2)简洁实现:new Blob([str]).size。3)new TextEncoder().encode(str).length。推荐Blob.size或TextEncoder,准确且简洁。
Q280: bind的用法,以及如何实现bind的函数和需要注意的点 A: bind创建新函数绑定this和预设参数。用法:fn.bind(context, ...args)。实现:Function.prototype.myBind = function(context, ...bindArgs) { const fn = this; return function(...callArgs) { return fn.apply(context, [...bindArgs, ...callArgs]); }; }。注意:1)bind返回新函数不立即执行;2)用new调用bind返回的函数时this指向新实例而非绑定的context,需处理:function boundFn(...args) { return this instanceof boundFn ? new fn(...bindArgs, ...args) : fn.apply(context, [...bindArgs, ...args]); };3)支持柯里化(预设参数);4)箭头函数的bind无效(箭头函数this不可变)。
Q281: 实现一个函数clone A: 深拷贝实现:function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (obj instanceof Map) { const m = new Map(); obj.forEach((v, k) => m.set(deepClone(k), deepClone(v))); return m; } if (obj instanceof Set) { const s = new Set(); obj.forEach(v => s.add(deepClone(v))); return s; } if (hash.has(obj)) return hash.get(obj); const clone = Object.create(Object.getPrototypeOf(obj)); hash.set(obj, clone); for (const key of Reflect.ownKeys(obj)) { clone[key] = deepClone(obj[key], hash); } return clone; }。关键:WeakMap处理循环引用、Reflect.ownKeys获取所有属性(含Symbol)、保留原型链、处理Date/RegExp/Map/Set等特殊类型。
Q282: 下面这个ul,如何点击每一列的时候alert其index A: 事件委托方式(推荐):document.querySelector('ul').addEventListener('click', (e) => { const li = e.target.closest('li'); if (li) { const index = Array.from(li.parentElement.children).indexOf(li); alert(index); } })。闭包方式:const lis = document.querySelectorAll('ul li'); lis.forEach((li, index) => { li.addEventListener('click', () => alert(index)); })。事件委托只需一个监听器,性能好,支持动态添加的li。注意不要用for+var(闭包问题导致所有点击alert最后一个索引),要用let或forEach。
Q283: 定义一个log方法,让它可以代理console.log的方法 A: 方式:1)function log(...args) { console.log(
[${new Date().toISOString()}], ...args); }。2)function log() { console.log.apply(console, ['[App]', ...arguments]); }。3)const log = console.log.bind(console, '[App]')。扩展:增加日志级别,生产环境可禁用:const logger = { debug: (...args) => process.env.NODE_ENV !== 'production' && console.debug('[DEBUG]', ...args), info: (...args) => console.info('[INFO]', ...args), warn: console.warn.bind(console, '[WARN]'), error: console.error.bind(console, '[ERROR]') }。统一日志方法便于控制输出、添加时间戳和日志级别过滤。Q284: 输出今天的日期 A: 方法:1)手动格式化:function getToday() { const d = new Date(); const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return
${y}-${m}-${day}; }。2)toISOString切片:new Date().toISOString().slice(0, 10) -> "2026-06-09"。3)toLocaleDateString:new Date().toLocaleDateString('zh-CN') -> "2026/6/9"。4)Intl.DateTimeFormat:new Intl.DateTimeFormat('zh-CN').format(new Date())。推荐padStart手动格式化为YYYY-MM-DD格式,代码清晰可控。Q285: 用js实现随机选取10-100之间的10个数字,存入一个数组,并排序 A: 实现:function getRandomArray(count, min, max) { const set = new Set(); while (set.size < count) { set.add(Math.floor(Math.random() * (max - min + 1)) + min); } return Array.from(set).sort((a, b) => a - b); } const arr = getRandomArray(10, 10, 100);。Math.random()生成[0,1),乘以范围加min得[min,max]闭区间整数。Set自动去重保证数字唯一。sort传比较函数(a,b)=>a-b确保数字升序(默认按字符串Unicode排序,会导致[1,10,2]问题)。边界:count不能超过范围大小(如10-100间最多91个不重复数)。
Q286: 写一段JS程序提取URL中的各个GET参数 A: 推荐使用URLSearchParams:const params = new URLSearchParams(window.location.search); params.get('key') / params.getAll('key') / params.has('key') / params.entries()。手动实现:function getUrlParams(url) { const params = {}; const qs = (url || window.location.href).split('?')[1]; if (!qs) return params; qs.split('&').forEach(pair => { const [k, v] = pair.split('=').map(decodeURIComponent); if (k) { if (params.hasOwnProperty(k)) { params[k] = [].concat(params[k], v); } else { params[k] = v || ''; } } }); return params; }。URLSearchParams是浏览器原生API,应优先使用。注意处理重复参数(转为数组)和中文解码(decodeURIComponent)。
Q287: 写一个function,清除字符串前后的空格 A: 1)原生trim():str.trim()(推荐,IE9+支持)。2)正则Polyfill:function trim(str) { return str.replace(/^\s+|\s+$/g, ''); }。3)trimStart/trimEnd:str.trimStart()去除左空格,str.trimEnd()去除右空格。生产环境直接用str.trim()即可。如果需要兼容IE8-:if (!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }; }。注意:trim只去除前后空格,不去除中间空格。去除所有空格:str.replace(/\s+/g, '')。
Q288: 实现每隔一秒钟输出1,2,3...数字 A: 方法:1)setInterval:let count = 0; const timer = setInterval(() => { console.log(++count); if (count >= 10) clearInterval(timer); }, 1000);。2)setTimeout递归:let count = 0; function fn() { console.log(++count); if (count < 10) setTimeout(fn, 1000); } fn();。3)async/await:const sleep = ms => new Promise(r => setTimeout(r, ms)); (async () => { for (let i = 1; i <= 10; i++) { console.log(i); await sleep(1000); } })();。方案3最可控易扩展,方案2比方案1更精确(避免执行时间累积误差)。注意清除定时器防止内存泄漏。
Q289: 实现一个函数,判断输入是不是回文字符串 A: 双指针法(推荐):function isPalindrome(s) { const str = s.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '').toLowerCase(); let l = 0, r = str.length - 1; while (l < r) { if (str[l] !== str[r]) return false; l++; r--; } return true; }。反转比较法:return str === str.split('').reverse().join('');。支持中文、忽略非字母数字字符。时间复杂度O(n),双指针空间O(1),反转比较空间O(n)。测试:isPalindrome('A man, a plan, a canal: Panama') -> true;isPalindrome('上海自来水来自海上') -> true。
Q290: 数组扁平化处理 A: 数组扁平化方法:1)arr.flat(Infinity)(ES6,最简洁,支持指定层数);2)递归reduce:function flatten(arr) { return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []); };3)迭代+栈:function flatten(arr) { const res = []; const stack = [...arr]; while (stack.length) { const item = stack.pop(); Array.isArray(item) ? stack.push(...item) : res.unshift(item); } return res; };4)toString+split(仅限数字):arr.toString().split(',').map(Number)。推荐flat(Infinity)或递归reduce。
Q291: 实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制 A: 基础版本深拷贝,覆盖基本类型和Object/Array:function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); const clone = Array.isArray(obj) ? [] : {}; for (const key of Object.keys(obj)) { clone[key] = deepClone(obj[key]); } return clone; }。完整版还需处理:Map/Set/Symbol属性/循环引用(WeakMap缓存)。5种类型说明:Number/String/Boolean为基本类型直接返回,Object/Array递归拷贝。Date/RegExp特殊处理。实际上JS还有更多类型(Map/Set/Symbol/BigInt等),完整深拷贝应覆盖所有。
Q292: 手写 promise.all 和 race(京东) A: Promise.all实现:function promiseAll(promises) { return new Promise((resolve, reject) => { const results = []; let count = 0; if (promises.length === 0) resolve([]); promises.forEach((p, i) => { Promise.resolve(p).then(val => { results[i] = val; count++; if (count === promises.length) resolve(results); }).catch(reject); }); }); }。Promise.race:function promiseRace(promises) { return new Promise((resolve, reject) => { promises.forEach(p => Promise.resolve(p).then(resolve, reject)); }); }。注意:Promise.resolve(p)确保非Promise值也能处理;all保持传入顺序;race以第一个完成的结果为准(不论resolve或reject)。
Q293: 手写-实现一个寄生组合继承 A: 寄生组合继承是最理想的继承方式:function inheritPrototype(child, parent) { const prototype = Object.create(parent.prototype); prototype.constructor = child; child.prototype = prototype; } function Parent(name) { this.name = name; } Parent.prototype.say = function() { console.log(this.name); }; function Child(name, age) { Parent.call(this, name); this.age = age; } inheritPrototype(Child, Parent); Child.prototype.run = function() { console.log('running'); };。特点:调用一次父类构造函数、原型链正常、constructor正确。ES6 class extends本质即此实现。
Q294: 手写-new 操作符 A: 实现new:function myNew(fn, ...args) { const obj = Object.create(fn.prototype); const result = fn.apply(obj, args); return result instanceof Object ? result : obj; }。原理:1)Object.create(fn.prototype)创建新对象并链接原型;2)fn.apply(obj, args)绑定this执行构造函数;3)如果构造函数返回了对象则返回该对象,否则返回新建的对象。使用:const p = myNew(Person, 'Alice', 25);。注意:箭头函数不能用作构造函数(没有prototype属性),new会抛出错误。
Q295: 手写-setTimeout 模拟实现 setInterval(阿里) A: 模拟setInterval:function mySetInterval(fn, delay) { let timer = null; function loop() { timer = setTimeout(() => { fn(); loop(); }, delay); } loop(); return { cancel: () => clearTimeout(timer) }; }。使用:const interval = mySetInterval(() => console.log('tick'), 1000); interval.cancel();。区别:setTimeout递归版在上一次回调执行完delay后才开始下一次,而setInterval不管回调执行时间固定间隔触发。setTimeout版避免了setInterval可能出现的回调堆积问题(回调执行时间超过间隔时)。更精确实现可使用递归setTimeout。
Q296: 手写-发布订阅模式(字节) A: 发布订阅模式:class EventEmitter { constructor() { this.events = {}; } on(event, listener) { if (!this.events[event]) this.events[event] = []; this.events[event].push(listener); return () => this.off(event, listener); } off(event, listener) { if (!this.events[event]) return; this.events[event] = this.events[event].filter(l => l !== listener); } emit(event, ...args) { if (!this.events[event]) return; this.events[event].forEach(listener => listener(...args)); } once(event, listener) { const wrapper = (...args) => { listener(...args); this.off(event, wrapper); }; this.on(event, wrapper); } }。使用:const bus = new EventEmitter(); const unsub = bus.on('login', (user) => console.log(user)); bus.emit('login', { id: 1 }); unsub();。
Q297: 手写-防抖节流(京东) A: 防抖:function debounce(fn, delay, immediate = false) { let timer; return function(...args) { if (immediate && !timer) fn.apply(this, args); clearTimeout(timer); timer = setTimeout(() => { if (!immediate) fn.apply(this, args); timer = null; }, delay); }; }。节流:function throttle(fn, limit) { let inThrottle = false; return function(...args) { if (!inThrottle) { fn.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }。或用时间戳版:function throttle(fn, limit) { let last = 0; return function(...args) { const now = Date.now(); if (now - last >= limit) { last = now; fn.apply(this, args); } }; }。防抖用于"结束"(输入完成),节流用于"过程"(滚动中)。
Q298: 将虚拟 Dom 转化为真实 Dom(类似的递归题-必考) A: 虚拟DOM转真实DOM:function render(vnode) { if (typeof vnode === 'string' || typeof vnode === 'number') return document.createTextNode(vnode); const el = document.createElement(vnode.tag); if (vnode.props) { Object.entries(vnode.props).forEach(([key, val]) => { if (key.startsWith('on')) { el.addEventListener(key.slice(2).toLowerCase(), val); } else { el.setAttribute(key, val); } }); } if (vnode.children) { vnode.children.forEach(child => el.appendChild(render(child))); } return el; }。vnode结构:{ tag: 'div', props: { id: 'app', onClick: handler }, children: ['text', { tag: 'span', props: {}, children: [] }] }。递归遍历vnode树,处理组件、事件绑定、属性设置。
Q299: 手写-实现一个对象的 flatten 方法(阿里) A: 将嵌套对象扁平化为单层结构:function flattenObject(obj, prefix = '', result = {}) { for (const key of Object.keys(obj)) { const newKey = prefix ?
${prefix}.${key}: key; if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { flattenObject(obj[key], newKey, result); } else { result[newKey] = obj[key]; } } return result; }。示例:flattenObject({ a: { b: 1, c: { d: 2 } }, e: 3 }) -> { 'a.b': 1, 'a.c.d': 2, 'e': 3 }。数组处理可选:对数组索引处理为[0]、[1]形式。反向(unflatten):function unflattenObject(obj) { const result = {}; for (const key of Object.keys(obj)) { key.split('.').reduce((acc, part, i, arr) => acc[part] = i === arr.length - 1 ? obj[key] : (acc[part] || {}), result); } return result; }。Q300: 手写-判断括号字符串是否有效(小米) A: 判断括号是否匹配:function isValid(s) { const stack = []; const map = { '(': ')', '[': ']', '{': '}' }; for (const char of s) { if (map[char]) { stack.push(map[char]); } else if (stack.length === 0 || stack.pop() !== char) { return false; } } return stack.length === 0; }。原理:遇到左括号将对应右括号入栈;遇到右括号弹出栈顶检查是否匹配。时间复杂度O(n),空间O(n)。测试:'()[]{}' -> true;'([)]' -> false;'({[]})' -> true。扩展:可处理多种括号混合。如果LeetCode第20题,经典栈应用。
Q301: 手写-查找数组公共前缀(美团) A: 查找字符串数组最长公共前缀:function longestCommonPrefix(strs) { if (!strs.length) return ''; let prefix = strs[0]; for (let i = 1; i < strs.length; i++) { while (strs[i].indexOf(prefix) !== 0) { prefix = prefix.slice(0, -1); if (!prefix) return ''; } } return prefix; }。时间复杂度O(S)(S为所有字符串总字符数)。另一种方法:纵向扫描,比较每个字符串相同位置的字符。function longestCommonPrefix(strs) { if (!strs.length) return ''; for (let i = 0; i < strs[0].length; i++) { for (let j = 1; j < strs.length; j++) { if (i >= strs[j].length || strs[j][i] !== strs[0][i]) return strs[0].slice(0, i); } } return strs[0]; }
Q302: 手写-字符串最长的不重复子串 A: 滑动窗口法:function lengthOfLongestSubstring(s) { const map = new Map(); let max = 0, left = 0; for (let right = 0; right < s.length; right++) { const char = s[right]; if (map.has(char) && map.get(char) >= left) { left = map.get(char) + 1; } map.set(char, right); max = Math.max(max, right - left + 1); } return max; }。时间复杂度O(n),空间O(min(m,n))(m为字符集大小)。原理:right指针扩展窗口,遇到重复字符则将left移到上次出现位置+1,Map记录字符最近位置。如"abcabcbb" -> 3("abc"),"bbbbb" -> 1("b"),"pwwkew" -> 3("wke")。
开放问题/HR
Q303: 谈谈你对重构的理解 A: 重构是在不改变代码外部行为的前提下,优化内部结构的过程。目的:提升代码可读性、可维护性、可扩展性,降低技术债务。常见重构场景:1)函数过长拆分为小函数;2)重复代码抽取为公共方法;3)复杂条件表达式简化;4)类/模块职责重新划分;5)命名规范化;6)消除魔法数字。重构原则:1)小步迭代,每次只做一个小改动确保不破坏功能;2)有充分的测试覆盖作为安全保障;3)不改变外部行为(输入输出一致)。重构与重写的区别:重构是渐进式改进,重写是推倒重来。推荐Martin Fowler的《重构》作为方法论指导,利用IDE的提取方法、重命名、移动等重构功能提高效率。
Q304: 什么样的前端代码是好的 A: 好的前端代码标准:1)可读性强,命名清晰(变量/函数/组件名见名知意),代码自注释(好代码本身就是文档),适当的注释说明复杂逻辑;2)可维护性,遵循单一职责原则,模块化/组件化程度高,低耦合高内聚;3)可复用性,公共逻辑抽取为工具函数、自定义Hook、通用组件;4)性能考虑,合理使用缓存、懒加载、防抖节流,避免不必要的渲染;5)健壮性,充分处理边界情况、错误捕获(try-catch、ErrorBoundary)、TypeScript类型约束;6)一致性,遵循团队编码规范(ESLint + Prettier)、统一的代码风格和目录结构;7)测试覆盖,关键逻辑有单测保障;8)安全意识,防范XSS/CSRF,不信任用户输入。
Q305: 对前端工程师这个职位是怎么样理解的?它的前景会怎么样 A: 前端工程师是连接用户界面与后端服务的桥梁,负责实现Web/移动端/桌面端的用户交互界面。核心职责:将设计稿转化为可交互的界面,确保性能、兼容性、可访问性,与后端协作完成数据展示和交互。现代前端已远不止切页面,而是涵盖工程化构建、性能优化、架构设计、跨平台开发的全栈方向。前景:1)随着移动互联网和IoT发展,前端领域持续扩展(React Native/Flutter跨端、小程序、桌面端Electron、SSR/SSG);2)WebAssembly(Wasm)打开了前端在图像处理、视频编解码、游戏等高性能计算领域的大门;3)AI与前端结合(智能代码生成、设计稿转代码、辅助测试)提升开发效率。前端工程师需要持续学习,保持对新技术栈的敏感度。
Q306: 你觉得前端工程的价值体现在哪 A: 前端工程的价值:1)用户体验,前端直接面向用户,页面加载速度、交互流畅度、界面美观度直接影响用户留存和转化率。合理的前端架构能显著提升用户体验指标(Core Web Vitals)。2)业务效率提升,组件化/模块化开发减少重复工作,脚手架和CLI工具标准化项目初始化流程,自动化测试和CI/CD保证代码质量。3)跨平台能力,一套代码可运行在Web/小程序/移动App/桌面端(React Native、Taro、Flutter、Electron),降低多端开发成本。4)技术创新驱动,前端技术快速演进(微前端、Serverless、SSR/SSG、低代码、Web3D),推动整个Web生态进步。5)数据可视化,前端将复杂数据转化为直观的图表和交互式仪表盘,辅助业务决策。
Q307: 平时如何管理你的项目 A: 项目管理方法:版本控制,使用Git进行代码管理,遵循Git Flow或Trunk Based分支策略,commit信息保持清晰(type(scope): message)。任务管理,使用Jira/Notion/Trello等工具跟踪需求进度,需求拆分为可交付的子任务,每1-2天有明确的产出。代码规范,通过ESLint + Prettier + Husky(pre-commit钩子)确保代码质量。文档维护,关键设计决策记录在README或Confluence,API文档使用Swagger,组件文档使用Storybook。协作流程,Code Review确保代码质量,Feature Branch开发完成后提PR,需要至少一位同事审核。发布部署,遵循灰度发布策略,监控发布后的错误率和性能指标,有回滚预案。定期复盘总结迭代问题。
Q308: 组件封装 A: 组件封装原则:1)单一职责,一个组件只做一件事,功能拆分到合适的粒度(过粗难复用,过碎维护成本高);2)接口清晰,通过props定义组件API,使用TypeScript或PropTypes声明类型,使用defaultProps提供默认值;3)关注点分离,UI表现与业务逻辑分离,纯展示组件只负责渲染,容器组件负责数据获取和状态管理;4)插槽/children支持动态内容,提供足够灵活性;5)受控与非受控模式支持,组件可在受控(外部控制value)和非受控(内部维护state)间切换;6)样式隔离,使用CSS Modules / styled-components / scoped styles;7)错误边界,React ErrorBoundary包裹捕获渲染错误。好的组件API应当符合开发者直觉,使用时不需要看文档就能猜出大部分用法。
Q309: Web 前端开发的注意事项 A: Web前端开发注意事项:1)性能,首屏加载时间、图片体积优化、减少HTTP请求、代码分割、CDN加速、合理缓存策略;2)兼容性,利用CanIUse查询特性支持情况,配置browserslist,使用Autoprefixer处理CSS前缀,Babel转译JS;3)安全,防范XSS(输出转义、CSP)、CSRF(Token、SameSite Cookie)、点击劫持(X-Frame-Options);4)可访问性,语义化HTML、ARIA属性、键盘导航、颜色对比度达标;5)SEO,语义化结构、meta标签、SSR/SSG、sitemap、结构化数据(JSON-LD);6)用户体验,加载状态、空状态、错误状态、边界情况处理,移动端适配、动画流畅度;7)工程化,代码规范、自动化测试、CI/CD、监控告警。
Q310: 在设计 Web APP 时,应当遵循以下几点 A: Web App设计要点:1)响应式设计,Mobile-First原则,使用CSS媒体查询/Grid/Flexbox布局适配不同屏幕;2)离线支持,Service Worker缓存关键资源,实现离线访问能力;3)渐进增强,基础功能在所有浏览器可用,高级功能在支持的环境增强;4)性能优先,首屏加载时间控制在3秒内,使用Lazy Loading、虚拟滚动等技术处理大量数据;5)安全性,HTTPS强制、CSP策略、输入校验、认证鉴权;6)可访问性,遵循WCAG标准,确保键盘操作和屏幕阅读器支持;7)状态管理,合理管理加载态、空态、错误态、成功态;8)SEO优化,预渲染或SSR让搜索引擎爬虫抓取内容;9)监控与日志,前端错误监控(Sentry)、性能监控(RUM数据)、用户行为分析。
Q311: 你怎么看待 Web App/hybrid App/Native App?(移动端前端 和 Web 前端区别?) A: 三种形式各有优劣。Web App:通过浏览器访问的响应式网站。优势:跨平台、无需安装、更新即时、开发成本低。劣势:功能受限(访问原生能力)、性能不如原生、离线能力有限。Hybrid App(混合App):Web页面运行在原生WebView中,通过JSBridge调用原生API。优势:跨平台复用代码、可调用原生能力(相机、定位等)、可热更新。代表:Cordova、Ionic、小程序。Native App(原生应用):使用平台原生语言(Swift/Kotlin)开发。优势:最佳性能、完整原生功能、流畅体验。劣势:多平台独立开发成本高。移动端前端与Web前端差异:移动端更关注触摸交互、性能优化(网络、渲染)、屏幕适配(视口、rpx/rem)、离线策略。
Q312: 页面重构怎么操作 A: 页面重构步骤:1)评估现状,分析当前页面存在的问题(JS耦合、CSS冗余、性能瓶颈、可维护性差等)。2)制定方案,确定重构目标和范围,灰度策略,评估风险点。3)基础重构,CSS模块化(BEM/CSS Modules)、提取公共样式变量(CSS自定义属性)、移除已废弃代码。4)JS重构,从jQuery过渡到原生/框架、拆分大函数为小模块、添加TypeScript类型。5)性能优化,压缩/合并资源、图片格式升级(WebP/AVIF)、代码分割、懒加载、CDN配置。6)测试验证,前后对比性能指标(Lighthouse分数、FCP/LCP/CLS),回归测试确保功能正常。7)灰度上线,逐步切量,监控错误率和用户反馈。重构原则:小步迭代,每次重构一小部分,不引入大规模一次性变更。
Q313: 常见问题 A: 前端面试常见问题方向:HTML语义化和SEO优化、CSS布局(Flex/Grid/居中/响应式)、JavaScript核心(闭包/原型/this/Event Loop/Promise/async await)、ES6+新特性、浏览器渲染机制和性能优化、安全(XSS/CSRF/CORS)、前端框架(Vue响应式原理/React Hooks/Fiber)、工程化(Webpack/Vite/模块化)、HTTP协议(缓存/HTTPS/HTTP2/3)、算法(排序/去重/数组操作)、设计模式。准备建议:深入理解原理而非死记硬背,结合项目实践举例说明,对不了解的领域坦诚说明但展现学习意愿。面试是双向选择的过程,既要展示技术能力也需评估团队是否匹配。
Q314: 你觉得你有哪些不足之处 A: 回答建议:选择真实的、可通过努力改进的不足,而非虚假的"完美答案"。避坑:不说致命缺点(沟通差、不爱学习、不写测试),不说"我太追求完美"等虚伪套话。正面示范:1)"在技术深度方面还有提升空间,某些底层原理(如V8引擎优化、浏览器渲染细节)理解还不够透彻,正在通过源码阅读和系统学习加强。"2)"跨端开发经验不够丰富,只在Web和小程序领域有深入实践,计划学习React Native补充移动端经验。"3)"在大型项目的架构设计上还在成长中,正在阅读开源项目源码学习优秀架构。"展现出的态度:认识到不足 -> 正在改进 -> 有明确计划。
Q315: 你觉得你最大的缺点是什么 A: 同Q314,这是HR面试经典问题。回答策略:选择真实但不致命的缺点,重点突出改进行为。模板:1)"我有时过于关注代码质量,会在细节上花费超出预期的时间。后来通过设定时间盒(timeboxing)来约束自己,优先保证核心功能交付,在允许的范围内追求高质量代码。"2)"过去我在公众演讲方面比较欠缺,导致技术方案分享效果不佳。最近我有意识地在团队内多做技术分享,参加内部的演讲俱乐部来锻炼表达能力。"3)"我对新技术比较热衷,有时会过早引入未经充分验证的方案。现在我养成了评估期(POC验证兼容性/稳定性/团队接受度)的习惯后再决定是否采用。"
Q316: 你还有其他公司的Offer吗? A: 回答策略:诚实但不失策略。如果有其他Offer,可以说"是的,目前收到了XX公司的Offer,但贵公司这个岗位与我的职业规划更契合,所以很期待能加入"。没有其他Offer也不用担心,可以说"目前正在面试几家感兴趣的公司,贵公司是我的首选,因此我会优先考虑这边的机会"。给面试官传递的信息:1)你是有市场价值的人选(如果有其他Offer);2)你对贵公司有真诚的兴趣(不仅是随便投投)。面试官问此问题主要是判断你的市场竞争力以及接受Offer的可能性。不用编造不存在的情报,也不用透露具体薪资数字。
Q317: 为什么从上一家公司离职? A: 回答策略:保持积极正面,不抱怨前公司(不吐槽加班、不批评领导、不贬低同事)。正面原因举例:1)业务发展空间有限,希望投身更具挑战性的项目;2)希望接触更主流的的技术栈(如从小程序转向React/Vue全栈方向);3)职业规划调整,希望从纯Web端转向跨端/全栈方向;4)公司业务方向调整,个人技术栈与新的业务方向不匹配(如团队转为维护老旧项目)。避免的原因:与同事关系不和、受不了加班、薪资太低(可以说但显得格局小)、被裁员(需谨慎表达)。总体原则:积极乐观、关注自身成长而非外部环境。
Q318: 如何看待加班(996)? A: 回答策略:展现职业态度但不过分妥协。示例:1)"我理解互联网行业的项目特点,在项目关键期或上线前需要加班来保证交付质量。同时我认为提高工作效率比延长工作时间更重要,合理的时间管理和技术优化可以减少不必要的加班。"2)"我希望能够找到一个工作与生活相对平衡的团队,在正常的工作时间内高效完成工作。如果偶尔遇到紧急项目需要加班可以理解,但长期的996我认为不利于个人成长和技术积累,也难以持续产出高质量代码。"总体原则:展现适度灵活性,不直接拒绝加班,但也表达对健康工作文化的期望。了解公司实际的加班文化再决定是否匹配。
Q319: 你对未来3-5年的职业规划 A: 回答策略:展现清晰的职业方向和成长路径。技术路线:1-2年深耕前端技术基础,掌握框架原理、性能优化、工程化建设;3-5年向技术专家发展,在某一领域(性能/跨端/工程化/可视化)形成核心竞争力,能主导技术方案设计和架构决策。管理路线:1-2年技术积累打下坚实基础;3-5年逐步承担技术负责人职责,带领小团队完成项目交付,培养沟通协调和项目管理能力。表达上:1)短期目标(1-2年):完成当前项目,深化技术栈理解,输出技术文章或开源贡献;2)中期目标(3-5年):在团队中承担更多责任,成为某一领域的专家,能够辅导新人。目标贴实际、有落地计划。
Q320: 如何与HR谈薪资 A: 薪资谈判要点:1)了解市场行情,通过脉脉/猎聘/Boss直聘了解同级别前端岗位的薪资范围,参考城市和行业因素;2)明确自身价值,梳理项目经验和技术能力对应的价值,大厂经验或稀缺技术栈(Wasm/可视化/跨端等)可溢价;3)谈薪时机,不要在初面就谈薪资,等拿到Offer或至少到终面后再谈。回答模板:"我相信公司有完善的薪资体系。我在之前的项目中积累了XX和XX经验,对标市场行情和我的能力,我期望的薪资范围是XX-XX。"4)福利综合考量,除了base薪资,股票期权、年终奖、五险一金基数、年假、学习资源等也是整体薪酬组成部分;5)不给出具体数字的技巧,说一个范围而非固定值,给双方留调整空间。底线:谈判时要真诚,了解自己的底线但也保持灵活度。
Q321: 什么是高阶组件(HOC)? A: 高阶组件(Higher-Order Component)是React中一种复用组件逻辑的模式。本质是一个函数,接收一个组件作为参数,返回一个新组件。用途:1)代码复用,将多个组件共有的逻辑提取到HOC中(如权限校验、日志记录、数据获取);2)渲染劫持,根据条件控制组件是否渲染或修改渲染结果;3)状态抽象,将状态管理逻辑与UI解耦。实现:function withAuth(WrappedComponent) { return function(props) { const isAuth = checkAuth(); return isAuth ? <WrappedComponent {...props} /> : <Redirect to="/login" />; }; }。HOC需要注意:displayName调试、静态方法复制、ref传递(使用React.forwardRef)、避免嵌套过深。React Hooks(自定义Hook)正在逐步替代HOC的复用场景。
Q322: 介绍一下Web Components A: Web Components是一组浏览器原生API,允许创建可复用的自定义HTML元素。三大核心技术:1)Custom Elements(自定义元素),通过class MyElement extends HTMLElement定义新元素,使用connectedCallback/disconnectedCallback等生命周期钩子;2)Shadow DOM(影子DOM),提供样式和DOM隔离,element.attachShadow({ mode: 'open' })创建独立的渲染子树;3)HTML Templates(模板),使用<template>和<slot>定义可复用的HTML片段。优势:浏览器原生支持、框架无关、样式隔离。劣势:兼容性问题(部分浏览器支持不完整)、React/Vue等框架生态更成熟。Web Components适合设计系统、跨框架组件库等场景。
Q323: 说说你对微前端的理解 A: 微前端是将前端应用分解为更小、更简单的独立子应用的架构模式。核心思想:每个子应用可以独立开发、独立测试、独立部署,由主应用负责整体路由和集成。主流方案:1)iframe嵌入,最简单但体验差(URL不同步、通信复杂);2)Single-SPA,路由驱动加载不同子应用,需子应用适配生命周期;3)Module Federation(Webpack 5),运行时加载远程模块,共享依赖;4)qiankun(基于Single-SPA)提供沙箱隔离和应用通信机制。优势:团队自治、技术栈无关(不同子应用可用不同框架)、增量升级。挑战:样式隔离、通信机制、共享依赖、性能优化(重复加载公共库)。
Q324: 什么是SSR?有哪些优缺点? A: SSR(Server-Side Rendering,服务端渲染)是在服务器端生成HTML内容,发送给浏览器直接展示的技术。代表框架:Next.js(React)、Nuxt.js(Vue)。SSR流程:浏览器请求页面 -> 服务端执行组件代码生成完整HTML -> 返回给浏览器直接展示 -> 下载JS后执行注水(hydrate)实现交互。优点:1)首屏加载快,用户无需等待JS下载执行即可看到内容;2)SEO友好,搜索引擎爬虫可直接获取完整HTML内容(对内容型网站至关重要)。缺点:1)服务端负载增加(每次请求都需要服务端渲染);2)开发复杂度提高(需处理Node端与浏览器端环境差异、内存泄漏等问题);3)交互不够即时(页面虽展示但不可交互,需等待注水完成)。SSR适合内容型网站,后台管理类SPA更适合CSR。
Q325: 你还有什么想问的? A: 反问面试官的问题:团队技术栈,当前使用的框架、版本、迁移计划;团队规模和协作方式,前端团队多少人、如何分工、代码Review流程;业务方向,团队负责的业务领域、技术挑战、未来规划;个人成长,培训资源、技术分享、晋升机制。面试进阶问题可展示技术深度:" 贵团队在性能优化方面有哪些具体措施和指标?"或"如果入职,前三个月的重点目标是什么?"。 留意:不要问薪资福利(那是HR环节)、不要问加班情况(显得太关注这个)、不要问网上能查到的基础信息。多问与团队和成长相关的问题,展现你的进取心和对团队的认真考虑。