W3C defines web standards such as HTML5, DOM, and event handling. ECMAScript (ES6–ES8) governs JavaScript syntax and behavior. The DOM (Document Object Model) represents the structure of a webpage as a tree of objects, enabling programmatic access and manipulation. The BOM (Browser Object Model) provides APIs for interacting with the browser environment, with window as its primary object. document is a property of window.
Browser engines vary: Chrome uses V8, Safari uses JavaScriptCore, and Firefox uses SpiderMonkey.
URL Encoding
encodeURI()encodes characters that are not valid in URLs, preserving reserved characters like:/?#[]@. For example:
http://www.example.com/q=春节→http://www.example.com/q=%E6%98%A5%E8%8A%82encodeURIComponent()encodes all characters except alphanumeric and-_.~, including reserved ones. For example:
http://www.example.com/q=春节→http%3A%2F%2Fwww.example.com%2Fq%3D%E6%98%A5%E8%8A%82
Use this when encoding query parameters or fragments.
DPI and Pixel Density
DPI (dots per inch) reflects the ratio of physical pixels to CSS pixels:
DPI = physicalPixels / logicalPixels. Higher-resolution displays have more physical pixels per CSS pixel, resulting in a higher DPI. A lower DPI means fewer physical pixels per CSS pixel, leading to less sharp rendering.
Event Handling
Browser events follow a three-phase model: capture → target → bubble.
- Use
addEventListener('click', handler, true)to capture events during the capture phase. - Use
addEventListener('click', handler, false)(default) to handle events during the bubble phase.
Example structure: html → body → div → span. Clicking on span triggers:
- HTML capture
- Body capture
- Div capture
- Span target
- Div bubble
- Body bubble
- Window bubble
Event Control Methods
e.stopPropagation()— Halts propagation in both capture and bubble phases, but does not prevent other handlers on the same element from executing.e.preventDefault()— Cancels the default browser action (e.g., preventing a link from navigating).e.stopImmediatePropagation()— Stops propagation and prevents other event listeners on the same element from being called.
Event Delegation
Instead of attaching listeners to each child, bind one listener to the parent leveraging event bubbling:
<ul id="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
const list = document.getElementById('list');
list.addEventListener('click', function(e) {
if (e.target.tagName.toLowerCase() === 'li') {
const items = Array.from(document.querySelectorAll('li'));
const index = items.indexOf(e.target);
console.log('Clicked item index:', index);
}
});
</script>
Legacy Browser Event Compatibility
class EventManager {
constructor(element) {
this.element = element;
}
add(event, handler) {
if (this.element.addEventListener) {
this.element.addEventListener(event, handler, false);
} else if (this.element.attachEvent) {
this.element.attachEvent('on' + event, handler);
} else {
this.element['on' + event] = handler;
}
}
remove(event, handler) {
if (this.element.removeEventListener) {
this.element.removeEventListener(event, handler, false);
} else if (this.element.detachEvent) {
this.element.detachEvent('on' + event, handler);
} else {
this.element['on' + event] = null;
}
}
}
function stopPropagation(e) {
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
}
function preventDefault(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
Network Status Detection
window.addEventListener('load', () => {
const status = document.getElementById('status');
const log = document.getElementById('log');
function updateStatus(event) {
status.textContent = navigator.onLine ? 'online' : 'offline';
log.insertAdjacentHTML('beforeend', `<div>Event: ${event.type}</div>`);
}
window.addEventListener('online', updateStatus);
window.addEventListener('offline', updateStatus);
});
// Connection type monitoring
const conn = navigator.connection;
let lastType = conn.effectiveType;
function checkConnectionChange() {
if (conn.effectiveType !== lastType) {
console.log(`Network changed from ${lastType} to ${conn.effectiveType}`);
lastType = conn.effectiveType;
}
}
conn.addEventListener('change', checkConnectionChange);
HTTP Requests and Caching
Common HTTP Status Codes
- 200 — GET request succeeded
- 201 — POST request created resource
- 301 — Permanent redirect
- 302 — Temporary redirect
- 304 — Not modified (used for协商缓存)
- 400 — Bad request
- 401 — Unauthorized
- 403 — Forbidden (e.g., CORS)
- 404 — Resource not found
- 405 — Method not allowed
- 500 — Internal server error
- 503 — Service unavailable
- 504 — Gateway timeout
Why Use Separate CDN Domains?
- Security: Browsers enforce same-origin policy; cookies aren’t sent to CDNs, reducing exposure.
- Bandwidth efficiency: Static assets (images, JS, CSS) don’t need cookies — avoiding unnecessary payload.
- Connection limits: Browsers limit concurrent connections per origin. Separating assets avoids hitting this cap.
Caching Strategy for index.html
Use no-cache or no-store for index.html. Evenif script and CSS files use hash-based versioning, a cached index.html prevents new asset references from loading. Since HTML is small, the performance cost of re-fetching is negligible compared to the risk of stale content.
AJAX vs Fetch
AJAX Implementation
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/api');
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.responseText);
}
}
};
xhr.timeout = 1000;
xhr.ontimeout = () => console.log('Request timed out');
xhr.upload.onprogress = (e) => {
console.log(`Progress: ${Math.round((e.loaded / e.total) * 100)}%`);
};
xhr.send();
Fetch Implementation
// No cookies by default
fetch('http://example.com/api')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
// With credentials
fetch('http://example.com/api', {
method: 'GET',
credentials: 'same-origin'
})
.then(res => {
if (!res.ok) throw new Error('Network response failed');
return res.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
// Timeout with AbortController
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetch('http://example.com/api', { signal: controller.signal })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') console.log('Request aborted');
else console.error(err);
});
clearTimeout(timeoutId);
Custom Elements with Web Components
Web Components allow creation of reusable, encapsulated custom HTML elements using:
CustomElements.define()— Register a new tag<template>— Define reusable markupShadow DOM— Isolate styles and DOM from the main document
Each component must extend HTMLElement.
class TextIcon extends HTMLElement {
constructor() {
super();
this._text = '';
}
static get observedAttributes() {
return ['text'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'text') {
this._text = newValue;
this.updateRender();
}
}
connectedCallback() {
this.updateRender();
}
get text() {
return this._text;
}
set text(value) {
this.setAttribute('text', value);
}
updateRender() {
this.textContent = this._text;
}
}
customElements.define('text-icon', TextIcon);
Usage Examples
<!-- In HTML -->
<text-icon text="Hello"></text-icon>
<!-- Programmatically -->
const el1 = document.createElement('text-icon');
el1.setAttribute('text', 'Dynamic');
const el2 = new TextIcon();
el2.text = 'Constructor-based';
document.body.appendChild(el1);
document.body.appendChild(el2);