window对象是一个全局对象,也可以说是JavaScript中的顶级对象
像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的。
所有通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法
window对象下的属性和方法调用的时候可以省略window
JavaScript 内置的一个用来让代码延迟执行的函数,叫 setTimeout
语法:
setTimeout(回调函数,等待的毫秒数)
setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window
清除延时函数:
let timer = setTimeout(回调函数,等待的毫秒数)
clearTimeout(timer)
注意点
JavaScript 的执行机制是其核心特性之一,涉及单线程、事件循环(Event Loop)、调用栈、任务队列等概念。以下是详细解析:
JavaScript 是单线程语言,但通过异步非阻塞机制处理并发操作(如网络请求、定时器等)。
关键点:
代码执行时的环境,分为:
每个上下文包含:
RangeError
。示例:
function foo() {
console.log("foo");
bar();
}
function bar() {
console.log("bar");
}
foo(); // 调用栈顺序: foo → bar
协调调用栈和任务队列的机制,分为以下步骤:
(1) 任务分类
同步任务:立即执行,进入调用栈。
异步任务
:分为两类:
setTimeout
、setInterval
、DOM 事件、I/O 操作。Promise.then
、MutationObserver
、queueMicrotask
。(2) 执行流程
示例:
console.log("1"); // 同步
setTimeout(() => console.log("2"), 0); // 宏任务
Promise.resolve().then(() => console.log("3")); // 微任务
console.log("4"); // 同步
// 输出顺序: 1 → 4 → 3 → 2
执行顺序:
同步代码 → 微任务 → 宏任务 → (下一轮循环)
特性 | 宏任务 | 微任务 |
---|---|---|
示例 | setTimeout 、setInterval |
Promise.then 、queueMicrotask |
队列优先级 | 低 | 高(当前循环末尾执行) |
触发时机 | 下一次事件循环 | 当前任务结束后立即执行 |
题目 1
setTimeout(() => console.log("A"), 0);
Promise.resolve().then(() => console.log("B"));
console.log("C");
答案:C → B → A
解析:同步代码 C
最先执行;微任务 B
优先于宏任务 A
。
题目 2
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
Promise.resolve().then(() => {
console.log("Promise");
setTimeout(() => console.log("Inner Timeout"), 0);
});
console.log("End");
答案:Start → End → Promise → Timeout → Inner Timeout
解析:
Start
、End
。Promise
执行,其内部的 setTimeout
作为新宏任务加入队列。Timeout
,最后执行 Inner Timeout
。理解这些机制能有效避免异步编程中的常见问题(如执行顺序错误)。
location
对象是浏览器提供的 JavaScript 内置对象,它包含了当前文档的 URL 信息,并提供了操作浏览器地址的方法。
location
对象属性location
对象包含以下属性,这些属性都是可读写的(修改它们会导致浏览器导航到新的 URL):
属性 | 描述 | 示例 |
---|---|---|
href |
完整的 URL | "https://example.com:8080/path/?query=string#hash" |
protocol |
协议部分(包括冒号) | "https:" |
host |
主机名和端口号 | "example.com:8080" |
hostname |
主机名 | "example.com" |
port |
端口号 | "8080" |
pathname |
URL 路径部分 | "/path/" |
search |
查询字符串(包括问号) | "?query=string" |
hash |
锚部分(包括井号) | "#hash" |
origin |
只读属性,返回协议+主机名+端口 | "https://example.com:8080" |
location
对象方法方法 | 描述 | 示例 |
---|---|---|
assign(url) |
加载新文档 | location.assign("https://new.com") |
replace(url) |
替换当前文档(不保留历史记录) | location.replace("https://new.com") |
reload() |
重新加载当前页面 | location.reload() |
reload(forceGet) |
强制从服务器重新加载 | location.reload(true) |
toString() |
返回完整的 URL 字符串 | location.toString() |
获取当前 URL 信息
console.log("完整URL:", location.href);
console.log("协议:", location.protocol);
console.log("主机:", location.host);
console.log("路径:", location.pathname);
console.log("查询参数:", location.search);
console.log("锚点:", location.hash);
修改 URL
// 导航到新页面(会添加到历史记录)
location.href = "https://new.com";
// 替换当前页面(不会添加到历史记录)
location.replace("https://new.com");
// 修改查询字符串
location.search = "?page=2";
// 修改锚点(不会重新加载页面)
location.hash = "#section2";
解析查询参数
function getQueryParams() {
const params = {};
const queryString = location.search.substring(1);
const pairs = queryString.split("&");
pairs.forEach(pair => {
const [key, value] = pair.split("=");
params[decodeURIComponent(key)] = decodeURIComponent(value || "");
});
return params;
}
console.log(getQueryParams());
页面重定向
// 3秒后重定向
setTimeout(() => {
location.href = "https://new.com";
}, 3000);
// 条件重定向
if (!userLoggedIn) {
location.replace("/login");
}
location
属性(除 hash
外)会导致页面重新加载replace()
方法不会在浏览器历史记录中创建新条目reload(true)
会绕过缓存,从服务器强制重新加载location
可能会干扰框架的路由系统window.location
的关系location
对象是 window
对象的属性,因此以下两种写法是等价的:
window.location.href;
location.href;
在大多数情况下,可以省略 window.
前缀直接使用 location
。
navigator
对象是浏览器提供的 JavaScript 内置对象,它包含了有关浏览器的信息,包括浏览器名称、版本、平台、用户代理字符串等。
navigator
对象常用属性属性 | 描述 | 示例值 |
---|---|---|
appName |
浏览器名称 | "Netscape" (大多数现代浏览器返回此值) |
appVersion |
浏览器版本信息 | "5.0 (Windows NT 10.0; Win64; x64)" |
userAgent |
用户代理字符串 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" |
platform |
操作系统平台 | "Win32" |
language |
浏览器主语言 | "zh-CN" |
languages |
浏览器支持的语言数组 | ["zh-CN", "zh", "en-US", "en"] |
cookieEnabled |
是否启用cookie | true |
onLine |
是否联网 | true |
hardwareConcurrency |
CPU核心数 | 8 |
deviceMemory |
设备内存(GB) | 8 |
maxTouchPoints |
最大触摸点数 | 5 |
navigator
对象常用方法方法 | 描述 | 示例 |
---|---|---|
javaEnabled() |
是否启用Java | navigator.javaEnabled() |
sendBeacon() |
异步发送少量数据 | navigator.sendBeacon(url, data) |
vibrate() |
触发设备震动(移动设备) | navigator.vibrate(200) |
getBattery() |
获取电池状态(Promise) | navigator.getBattery().then(...) |
getUserMedia() |
获取媒体设备访问权限 | navigator.mediaDevices.getUserMedia(...) |
share() |
Web分享API | navigator.share({title: '分享标题', url: 'https://example.com'}) |
检测浏览器基本信息
console.log('浏览器名称:', navigator.appName);
console.log('浏览器版本:', navigator.appVersion);
console.log('用户代理:', navigator.userAgent);
console.log('操作系统:', navigator.platform);
console.log('是否在线:', navigator.onLine);
console.log('是否启用cookie:', navigator.cookieEnabled);
检测浏览器类型
function detectBrowser() {
const ua = navigator.userAgent;
if (ua.indexOf('Chrome') > -1) return 'Chrome';
if (ua.indexOf('Firefox') > -1) return 'Firefox';
if (ua.indexOf('Safari') > -1) return 'Safari';
if (ua.indexOf('Opera') > -1) return 'Opera';
if (ua.indexOf('Edge') > -1) return 'Edge';
if (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident/') > -1) return 'IE';
return 'Unknown';
}
console.log('当前浏览器:', detectBrowser());
使用sendBeacon发送数据
// 在页面卸载时可靠地发送数据
window.addEventListener('unload', function() {
const data = JSON.stringify({event: 'page_exit', time: Date.now()});
navigator.sendBeacon('/analytics', data);
});
检测设备特性
console.log('CPU核心数:', navigator.hardwareConcurrency);
console.log('设备内存(GB):', navigator.deviceMemory);
// 检测是否移动设备
const isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
console.log('是否移动设备:', isMobile);
使用Web Share API
if (navigator.share) {
document.getElementById('share-btn').addEventListener('click', async () => {
try {
await navigator.share({
title: 'Web分享示例',
text: '看看这个有趣的网站',
url: 'https://example.com'
});
console.log('分享成功');
} catch (err) {
console.log('分享取消:', err);
}
});
} else {
console.log('Web Share API不支持');
}
userAgent
可以被修改,不应仅依赖它来做关键功能检测deviceMemory
可能涉及隐私,浏览器可能限制访问share()
、getBattery()
等不是所有浏览器都支持现代navigator
对象还包含许多新API:
navigator.mediaDevices
(摄像头/麦克风访问)navigator.geolocation
navigator.clipboard
navigator.bluetooth
navigator.usb
navigator.connection
这些API通常需要用户授权才能使用。
history
对象是浏览器提供的 JavaScript 内置对象,它允许开发者操作浏览器的会话历史记录(即当前标签页访问过的 URL 历史)。
history
对象属性属性 | 描述 | 示例 |
---|---|---|
length |
返回历史记录列表中的 URL 数量(只读) | history.length |
scrollRestoration |
控制页面刷新后是否恢复滚动位置(auto /manual ) |
history.scrollRestoration = 'manual' |
state |
返回当前历史记录条目的状态对象(只读) | history.state |
history
对象方法方法 | 描述 | 示例 |
---|---|---|
back() |
后退到上一个页面(等同于浏览器后退按钮) | history.back() |
forward() |
前进到下一个页面(等同于浏览器前进按钮) | history.forward() |
go(n) |
在历史记录中前进或后退 n 个页面 | history.go(-2) (后退2页) |
方法 | 描述 | 示例 |
---|---|---|
pushState(state, title, url) |
添加新的历史记录条目(不刷新页面) | history.pushState({page: 1}, "Page 1", "?page=1") |
replaceState(state, title, url) |
替换当前历史记录条目(不刷新页面) | history.replaceState({page: 2}, "Page 2", "?page=2") |
// 后退一页
document.getElementById('back-btn').addEventListener('click', () => {
history.back();
});
// 前进一页
document.getElementById('forward-btn').addEventListener('click', () => {
history.forward();
});
// 前进或后退多页
document.getElementById('go-btn').addEventListener('click', () => {
history.go(-2); // 后退2页
});
// 添加新历史记录
function navigateTo(page) {
const state = { page };
const title = `Page ${page}`;
const url = `?page=${page}`;
history.pushState(state, title, url);
updateContent(page);
}
// 替换当前历史记录
function replaceCurrentPage(page) {
const state = { page };
const title = `Page ${page}`;
const url = `?page=${page}`;
history.replaceState(state, title, url);
updateContent(page);
}
// 处理浏览器前进/后退
window.addEventListener('popstate', (event) => {
const page = event.state?.page || 1;
updateContent(page);
});
function updateContent(page) {
document.getElementById('content').textContent = `当前页面: ${page}`;
}
// 保存状态到历史记录
history.pushState({
formData: {
username: 'user123',
progress: 75
}
}, "Form Page", "/form");
// 恢复状态
window.addEventListener('popstate', (event) => {
const savedState = event.state;
if (savedState && savedState.formData) {
console.log('恢复的表单数据:', savedState.formData);
// 填充表单...
}
});
// 禁用页面刷新后的自动滚动恢复
if (history.scrollRestoration) {
history.scrollRestoration = 'manual';
}
pushState
和 replaceState
的 URL 参数必须同源popstate
事件一起使用window.history
的关系history
对象是 window
对象的属性,以下两种写法等价:
window.history.back();
history.back();
在大多数情况下,可以省略 window.
前缀直接使用 history
。
特点:
存储大小约4KB
会随HTTP请求自动发送到服务器
可设置过期时间
使用场景:用户身份验证、会话管理
// 设置Cookie
document.cookie = "username=John; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";
// 读取Cookie
const cookies = document.cookie.split(';');
(1) localStorage
(2) sessionStorage
// localStorage使用
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
// sessionStorage使用
sessionStorage.setItem('tempData', JSON.stringify({id: 1}));
const data = JSON.parse(sessionStorage.getItem('tempData'));
// 打开/创建数据库
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = (event) => {
const db = event.target.result;
// 数据库操作...
};
caches.open('my-cache').then(cache => {
cache.add('/api/data');
});
适用于Web Storage存储对象/数组
const user = {
name: "张三",
preferences: {
theme: "dark",
fontSize: 16
}
};
// 存储
localStorage.setItem('user', JSON.stringify(user));
// 读取
const storedUser = JSON.parse(localStorage.getItem('user'));
直接支持存储JavaScript对象
const transaction = db.transaction('users', 'readwrite');
const store = transaction.objectStore('users');
store.put({
id: 1,
name: "李四",
tags: ["vip", "admin"],
meta: {
lastLogin: new Date()
}
});
(1) Date对象
// 存储
localStorage.setItem('lastUpdated', new Date().toISOString());
// 读取
const date = new Date(localStorage.getItem('lastUpdated'));
(2) Map/Set
const map = new Map([['key1', 'value1'], ['key2', 'value2']]);
// 存储
localStorage.setItem('myMap', JSON.stringify(Array.from(map.entries())));
// 读取
const mapData = new Map(JSON.parse(localStorage.getItem('myMap')));
数据安全:
容量管理:
// 检查localStorage剩余空间
function getLocalStorageRemainingSpace() {
const testKey = 'test';
let data = '';
try {
// 填充数据直到超出限制
while(true) {
data += 'xxxxxxxxxx';
localStorage.setItem(testKey, data);
}
} catch (e) {
localStorage.removeItem(testKey);
return data.length;
}
}
错误处理:
try {
localStorage.setItem('key', largeData);
} catch (e) {
if (e.name === 'QuotaExceededError') {
console.error('存储空间不足');
// 清理旧数据或提示用户
}
}
数据版本控制:
const storageVersion = 'v2.1';
if(localStorage.getItem('version') !== storageVersion) {
localStorage.clear();
localStorage.setItem('version', storageVersion);
}
性能优化:
方案 | 容量 | 持久性 | 数据结构 | 同步/异步 | 适用场景 |
---|---|---|---|---|---|
Cookie | 4KB | 可设置 | 字符串 | 同步 | 小数据、身份验证 |
localStorage | 5-10MB | 持久 | 字符串 | 同步 | 用户偏好设置 |
sessionStorage | 5-10MB | 会话级 | 字符串 | 同步 | 临时数据 |
IndexedDB | ≥250MB | 持久 | 复杂类型 | 异步 | 离线应用、大数据 |
Cache API | 动态 | 持久 | 请求/响应 | 异步 | 网络资源缓存 |
根据应用需求选择合适的存储方案,对于现代Web应用,通常需要组合使用多种存储技术。
正则表达式(Regular Expression,简称 regex)是用于匹配字符串中字符组合的模式,它是一种强大的字符串处理工具,主要用于:
在 JavaScript 中,正则表达式通过 RegExp
对象实现,有两种创建方式:
// 字面量形式
const regex1 = /pattern/flags;
// 构造函数形式
const regex2 = new RegExp('pattern', 'flags');
语法 | 描述 | 示例 |
---|---|---|
literal |
直接匹配字符 | /abc/ 匹配 “abc” |
` | ` | 或操作 |
[] |
字符集合 | [abc] 匹配 “a”、“b” 或 “c” |
[^] |
否定字符集合 | [^abc] 匹配非 “a”、“b”、“c” 的字符 |
() |
分组 | (abc)+ 匹配 “abc” 一次或多次 |
量词 | 描述 | 示例 |
---|---|---|
* |
0次或多次 | a* 匹配 “”, “a”, “aa”, … |
+ |
1次或多次 | a+ 匹配 “a”, “aa”, … |
? |
0次或1次 | a? 匹配 “”, “a” |
{n} |
恰好n次 | a{2} 匹配 “aa” |
{n,} |
至少n次 | a{2,} 匹配 “aa”, “aaa”, … |
{n,m} |
n到m次 | a{2,4} 匹配 “aa”, “aaa”, “aaaa” |
元字符 | 描述 | 等价字符类 |
---|---|---|
. |
匹配除换行符外的任意字符 | [^\n\r] |
\d |
数字字符 | [0-9] |
\D |
非数字字符 | [^0-9] |
\w |
单词字符(字母、数字、下划线) | [A-Za-z0-9_] |
\W |
非单词字符 | [^A-Za-z0-9_] |
\s |
空白字符(空格、制表符、换行等) | [\t\n\v\f\r ] |
\S |
非空白字符 | [^\t\n\v\f\r ] |
\b |
单词边界 | - |
\B |
非单词边界 | - |
^ |
字符串开始 | - |
$ |
字符串结束 | - |
修饰符 | 描述 | 示例 |
---|---|---|
i |
不区分大小写 | /abc/i 匹配 “ABC” |
g |
全局匹配(查找所有匹配) | /a/g 在 “aaa” 中找到3个匹配 |
m |
多行模式(^和$匹配每行的开始/结束) | /^a/gm 在多行中匹配每行开头的a |
s |
允许. 匹配换行符 |
/a.b/s 匹配 “a\nb” |
u |
Unicode模式(正确处理4字节字符) | /\u{1F600}/u 匹配 |
y |
粘性匹配(从lastIndex开始精确匹配) | /a/y 从指定位置匹配 |
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
console.log(emailRegex.test('[email protected]')); // true
console.log(emailRegex.test('invalid.email@')); // false
const url = 'https://www.example.com/path?query=string';
const domainRegex = /^(https?:\/\/)?([^\/\?]+)/i;
const match = url.match(domainRegex);
console.log(match[2]); // www.example.com
// 至少8字符,包含大小写字母和数字
const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/;
console.log(passwordRegex.test('StrongPass1')); // true
console.log(passwordRegex.test('weak')); // false
const phone = '1234567890';
const formatted = phone.replace(/^(\d{3})(\d{3})(\d{4})$/, '($1) $2-$3');
console.log(formatted); // (123) 456-7890
const html = 'Hello World';
const cleanText = html.replace(/<[^>]*>/g, '');
console.log(cleanText); // Hello World
// 使用 (?:...) 表示不捕获的分组
const dateRegex = /(\d{4})-(?:\d{2})-(\d{2})/;
const dateMatch = '2023-05-15'.match(dateRegex);
console.log(dateMatch); // ["2023-05-15", "2023", "15"]
// 匹配重复单词
const repeatRegex = /\b(\w+)\s+\1\b/;
console.log(repeatRegex.test('hello hello')); // true
console.log(repeatRegex.test('hello world')); // false
// 正向肯定预查 (?=...)
const hasNumberRegex = /^(?=.*\d).+$/;
// 正向否定预查 (?!...)
const noSpecialCharRegex = /^(?!.*[@#$%]).+$/;
const greedyRegex = /<.*>/; // 匹配整个 ...
const lazyRegex = /<.*?>/; // 只匹配单个标签
2. 多行匹配
const multiLineText = `Line 1
Line 2
Line 3`;
// 不使用m修饰符
console.log(/^Line/g.test(multiLineText)); // false
// 使用m修饰符
console.log(/^Line/gm.test(multiLineText)); // true
3. Unicode字符匹配
// 不使用u修饰符
console.log(/^.$/.test('')); // false
// 使用u修饰符
console.log(/^.$/u.test('')); // true
正则表达式是JavaScript中非常强大的工具,掌握它可以极大提高字符串处理的效率和灵活性。建议从简单模式开始练习,逐步掌握更复杂的表达式。