您现在的位置是:网站首页 > JS工具与调试面试题文章详情
JS工具与调试面试题
陈川 【 JavaScript 】 7353人已围观
1. Chrome DevTools的主要功能有哪些?
Chrome DevTools 是一个强大的开发者工具,它内置于 Google Chrome 浏览器中,用于调试、优化和理解网页应用。以下是 Chrome DevTools 主要功能的一些示例,主要针对 JavaScript:
-
Console(控制台):
- JavaScript Debugging: 你可以设置断点、单步执行代码、查看变量值、检查错误和警告信息。
- Console.log():在控制台输出调试信息,帮助跟踪代码执行过程。
-
Sources(源代码):
- Inspect and Edit Code: 查看和修改 HTML、CSS 和 JavaScript 代码,实时查看更改效果。
- Breakpoints: 设置断点来暂停代码执行,便于查找和修复错误。
-
Debugger(调试器):
- Step Through Code: 单步执行 JavaScript 代码,观察每一步执行后的变量状态。
- Watch Expressions: 监视特定的表达式值的变化,如循环或异步操作中的变量。
-
Performance(性能):
- Performance Profiling: 分析页面加载速度,识别性能瓶颈,如网络请求、渲染、JavaScript 调度等。
- Memory Profiler: 检查内存使用情况,找出可能导致内存泄漏的部分。
-
Network(网络):
- Inspect Network Requests: 查看并分析浏览器发送的所有网络请求,包括响应时间、数据大小等。
- Caching and Prefetching: 管理缓存,预加载资源以提高页面加载速度。
-
Elements(元素):
- DOM Inspection: 查看和修改 HTML 结构,检查样式和布局。
- Styles Editor: 修改 CSS 样式,实时查看样式更改对页面的影响。
-
Lighthouse(灯塔):
- Auditing: 自动评估网站的性能、最佳实践和可访问性,提供改进建议。
-
Workbox(工作坊):
- Service Worker Support: 与 Service Workers 配合,实现离线缓存、推送通知等功能。
-
Application(应用):
- Add New Scripts: 注册自定义脚本,扩展浏览器的功能。
通过这些功能,开发者可以深入了解和优化他们的网页应用,提高开发效率和用户体验。
2. 如何使用Chrome DevTools进行JavaScript断点设置?
在Chrome DevTools中设置JavaScript断点非常简单,以下是步骤:
-
打开Chrome浏览器并访问你想调试的网页。
-
点击右上角的三个垂直点(或者右键点击页面),选择"检查"(Inspect)或者快捷键
Ctrl+Shift+I
(Windows/Linux)或Cmd+Opt+I
(Mac)来打开DevTools。 -
在DevTools窗口中,你会看到一个"Sources"标签,点击它。这会显示你的网站的源代码。
-
在源代码面板中找到你想要设置断点的JavaScript代码行。你可以通过滚动浏览,或者使用搜索框来快速定位。
-
点击你想要设置断点的行号左边。你会看到一个小圆圈出现,表示断点已经设置好了。如果你不想让断点立即暂停执行,也可以点击 这个圆圈,选择"条件断点",然后输入你的条件。
-
当你的代码运行到这个断点时,浏览器会暂停执行,然后你可以查看变量值、调用堆栈等信息,进行单步调试。
-
要删除断点,只需再次点击那个圆圈即可。
-
如果你想查看所有已设置的断点,可以点击顶部菜单的"Toggle Breakpoints"(切换断点)按钮,或者按
F9
键。
以上就是在Chrome DevTools中设置JavaScript断点的基本步骤。
3. 解释Elements、Console、Sources、Network面板的作用。
-
Elements面板:在Web开发者工具中,Elements面板是最重要的一个,它允许你查看和修改网页的HTML结构。你可以在这里看到网页的所有元素,包括CSS样式和JavaScript代码的效果。例如,你可以检查元素的属性,编辑CSS样式,或者在JavaScript上下文中查找并修改变量。对于JavaScript,如果你有一个点击事件,你可以在这个面板中找到对应的事件处理器函数,查看其代码逻辑。
-
Console面板:Console面板主要用于浏览器的调试,你可以在这里输出日志,执行JavaScript代码,查看错误信息等。例如,当你在JavaScript中使用
console.log()
时,控制台会显示你传递的消息。如果遇到错误,如语法错误或运行时错误,也会在Console中显示详 细的错误堆栈信息,帮助你定位问题。 -
Sources面板:这个面板主要用于查看和管理你的源代码,包括HTML、CSS和JavaScript文件。你可以在这里查看和编辑你的JavaScript代码,设置断点进行单步调试,查看函数调用堆栈,以及查看和修改变量值。例如,如果你想查看某个函数的实现,可以在Sources面板中搜索该函数名,然后点击行号就可以跳转到相应的代码行。
-
Network面板:在开发过程中,Network面板用于监控网络请求。当你访问网页时,所有的HTTP请求(包括GET、POST等)都会被记录在这里。你可以查看每个请求的响应状态码,请求头,响应头,以及响应体。这对于调试网络问题,优化性能,或者理解API调用流程非常 有用。比如,你可以检查一个AJAX请求的返回数据,或者查看一个图片加载的时间。
4. 使用DevTools的Performance面板进行性能分析。
DevTools(开发者工具)是浏览器内置的一种强大的开发和调试工具,其中Performance面板是一个非常重要的部分,用于分析网页的性 能,包括CPU使用情况、内存使用、网络请求等。以下是如何使用Performance面板进行JavaScript性能分析的一个简单示例:
-
打开Performance面板:在Chrome或Firefox中,按F12或右键点击页面并选择"检查",然后在开发者工具窗口中找到"Performance"标签。
-
触发事件:在你想要分析的JavaScript代码执行前,先确保你有一个触发点。例如,你可以点击一个按钮或者滚动页面。
-
开始记录:在Performance面板中,点击顶部的"Record"或"Start"按钮,开始录制性能数据。此时,所有浏览器活动都会被记录 下来。
-
执行JavaScript代码:现在执行你的JavaScript代码,比如调用一个函数或者执行一段复杂的逻辑。
-
停止录制:当你的代码执行完毕后,停止录制,通常可以通过点击"Stop"按钮或者按Ctrl+Shift+P(Windows/Linux)或Cmd+Option+P(Mac)并输入"Stop"来实现。
-
查看性能报告:停止录制后,Performance面板会显示一个详细的性能报告。在这个报告中,你可以看到各个阶段的CPU使用率、 内存使用情况,以及网络请求等信息。你还可以通过点击各个事件查看详细的堆栈跟踪,找出可能的性能瓶颈。
-
分析结果:根据报告中的数据,你可以分析哪些操作花费了大量时间,可能是由于计算密集型操作、DOM操作过频繁、网络请求延迟等原因。然后针对这些情况进行优化。
这只是一个基本的使用步骤,实际使用时可能需要根据具体的需求和问题进行更深入的分析。
5. 利用DevTools的Memory面板诊断内存泄漏。
在浏览器的开发者工具(DevTools)中,Memory面板是一个非常有用的工具,可以帮助我们检测和诊断JavaScript应用中的内存泄漏问题。以下是如何使用它来诊断内存泄漏的步骤:
-
打开Memory面板:在Chrome或Firefox等现代浏览器中,按F12或右键点击页面并选择"检查"(Inspect)以打开开发者工具。然后在工具栏中找到并点击"Memory"或者"Memory"标签。
-
触发内存泄漏:在你的JavaScript代码中执行可能会导致内存泄漏的操作,比如创建大量未释放的对象、循环引用等。确保你有 足够的时间让内存泄漏发生,因为有些内存泄漏可能需要一段时间才会显现。
-
观察Memory面板:在Memory面板中,你会看到一个叫做"Allocated"的区域,它显示了当前浏览器进程占用的总内存。随着时间的推移,如果内存泄漏存在,这个值应该会持续增长。
-
触发垃圾回收:为了更准确地检测内存泄漏,你可以尝试手动触发JavaScript的垃圾回收。在Chrome的Memory面板中,点击"Take Heap Snapshot"按钮,然后再次运行你的代码。这样可以生成一个新的内存快照,你可以比较前后两次的内存使用情况。
-
对比内存快照:查看"Objects"部分,这里列出了所有已分配的对象及其大小。如果你发现某个对象的实例数量持续增加,而没有相应的
delete
或release
操作,那么可能存在内存泄漏。记住,你应该关注那些不会自动被垃圾回收的对象。 -
定位内存泄漏源:根据对象的类型和路径,尝试找出是哪个函数或对象引起了内存泄漏。你可能需要查看代码,找出可能的循环 引用或其他可能导致内存无法释放的地方。
-
修复内存泄漏:一旦找到内存泄漏的原因,修复它并再次测试,看看内存使用是否恢复正常。
请注意,虽然Memory面板是一个很好的工具,但它并不能总是100%确定内存泄漏的确切位置。在某些情况下,你可能需要结合其他调试技术,如Chrome的console.time()
和console.timeEnd()
,以及性能分析工具进行排查。
6. 如何在Firefox Developer Tools中调试JavaScript?
在Firefox Developer Tools中调试JavaScript非常直观和强大。以下是一些基本步骤:
-
打开开发者工具:在Firefox中,按F12或者右键点击页面,然后选择"检查"(Inspect)或"开发者工具"(Developer Tools), 这将打开一个侧边栏,其中包括各种工具,包括JavaScript控制台。
-
选择JavaScript面板:在开发者工具的顶部,你会看到一个标签页列表,选择"Console"标签,这就是JavaScript控制台,你可以在其中运行、查看和调试JavaScript代码。
-
设置断点:在你想要暂停执行的代码行上点击,Firefox会自动在那里设置一个断点。当你运行到这个断点时,代码会暂停,你可以查看此时的变量值、调用堆栈等信息。
-
执行代码:在控制台中,你可以直接输入JavaScript代码并执行。例如,如果你想查看某个变量的值,可以输入
console.log(myVariable)
,然后回车。如果你想运行某个函数,也可以直接输入函数名。 -
使用Step Over, Step Into, Step Out:在控制台下方,有三个按钮分别表示"步过(Step Over)"(单步执行当前行直到遇到下一个可执行语句)、"步进(Step Into)"(进入函数内部)和"步出(Step Out)"(退出当前函数)。这对于理解代码执行流程非常有 用。
-
检查错误:如果你的代码有错误,控制台会显示错误信息,包括错误类型、错误消息以及错误发生的位置。这可以帮助你快速定 位问题。
-
使用Watch表达式:在控制台的右侧,你可以创建一个Watch表达式来实时监视特定变量的值。当这个变量的值改变时,控制台会 自动更新。
-
使用Console API:Firefox的开发者工具还提供了丰富的Console API,如
debugger
关键字(在代码中插入该关键字会在控制台显示一个暂停点)、assert
用于测试条件等。
通过这些步骤,你可以有效地在Firefox Developer Tools中调试JavaScript代码。
7. 如何利用debugger
语句进行代码调试?
debugger
语句是JavaScript中的一种内置工具,用于在代码执行过程中设置断点。当你在浏览器的开发者工具中运行带有debugger
的脚本时,它会在遇到这个语句时暂停代码执行,让你能够查看和修改变量的值,检查调用栈,以及单步执行代码。
以下是如何在JavaScript中使用debugger
进行调试的步骤:
-
设置断点:在你想要暂停执行的代码行前添加
debugger
。例如:function myFunction() { debugger; // 这里会设置一个断点 console.log('Hello, World!'); }
-
运行代码:在浏览器的开发者工具(通常是F12或者右键选择“检查”)中打开你的JavaScript文件,找到
myFunction
函数并运行它。 -
进入调试模式:当执行到
debugger
语句时,浏览器会自动暂停代码执行,并显示一个控制台面板,这就是调试器界面。在这里 ,你可以看到当前执行的代码行、变量的值、调用堆栈等信息。 -
单步执行:在调试器中,你可以使用以下快捷键或菜单选项进行单步执行:
F8
:逐行执行Step Over
:执行当前行并跳过下一行(如果下一行是函数调用则进入函数)Step Into
:执行当前行并进入下一行所在的函数Step Out
:从当前函数返回上一级函数
-
检查变量:在调试器的Scope面板或Watch视图中,你可以查看和修改变量的值。也可以添加新的Watch表达式来监控特定的计算结果。
-
继续执行:当你完成了对某部分代码的调试后,可以使用
Resume script execution
或按F9
键继续执行直到下一个断点,或者直接点击右下角的绿色箭头。
通过使用debugger
语句,你可以更有效地定位和修复代码中的错误,理解代码的执行流程。
8. 解释并演示如何使用条件断点。
条件断点是编程调试工具中的一种功能,它允许你设置一个只在满足特定条件时停止执行的断点。这对于跟踪复杂的逻辑或者特定代码块的执行路径非常有用。
在JavaScript中,我们可以使用浏览器的开发者工具(如Chrome DevTools)来设置条件断点。以下是步骤:
-
打开你的JavaScript文件,并在你想要设置断点的行号上点击。大多数IDE和浏览器会自动为这一行添加一个红色的圆圈,表示有一个断点。
-
现在,我们需要设置条件。在Chrome DevTools中,点击断点旁边的下拉箭头(在红点旁边),然后选择"Edit Breakpoint"(编辑断 点)。在弹出的对话框中,你会看到一个文本框,用于输入你的条件。
-
在文本框中输入你的条件。例如,如果你想在数组
myArray
的长度大于5时暂停,你可以输入myArray.length > 5
。记住,这里的 条件必须是JavaScript可以评估的表达式。 -
点击"Add"或"OK"保存你的条件。现在,当
myArray.length
大于5时,代码会在那一行暂停执行。 -
你可以通过运行你的代码来测试这个条件断点。当条件满足时,浏览器会暂停在你设置的断点处,你可以查看此时的变量值,单步执 行,或者继续执行直到下一个断点。
这只是一个基本的示例,实际上,你可以设置更复杂的条件,比如基于对象属性、函数返回值等。这在处理异步操作或者需要深入理解代码逻辑时非常有用。
9. 什么是事件监听断点?何时使用?
事件监听断点是一种在编程中设置的特殊点,它允许开发者在特定事件发生时暂停程序执行,以便检查当前状态、查看变量值或调试代码。这是一种强大的调试工具,特别是在处理用户交互(如点击、滚动、输入等)或者复杂的时间触发事件时非常有用。
在JavaScript中,我们可以使用浏览器的开发者工具(如Chrome DevTools或Firefox Developer Tools)来设置事件监听断点。以下是一个简单的示例:
// 假设我们有一个按钮元素,我们想在点击时暂停执行
const button = document.getElementById('myButton');
// 我们可以为这个按钮的click事件设置一个断点
debugger; // 这行代码会在事件触发时暂停执行
button.addEventListener('click', function() {
console.log('Button clicked!');
});
在这个例子中,当你在浏览器中点击带有id="myButton"
的按钮时,代码会立即停止在debugger;
这一行,你可以查看此时的变量值、调用栈等信息,然后继续执行或单步调试。
记住,事件监听断点通常用于开发阶段,当你需要深入理解代码在特定事件触发时的行为时。在生产环境中,你可能更倾向于使用日志记录或者性能分析工具,而不是在每个事件上设置断点。
10. 如何追踪异步调用堆栈?
在JavaScript中,由于其单线程的特性,异步操作通常通过回调、Promise或async/await来处理。追踪异步调用堆栈可能会有些复杂,但可以通过一些技巧来实现。以下是一些方法:
- 使用Promise链:
当使用Promise时,你可以使用.then()
和.catch()
方法,它们会创建一个新的Promise实例,使得每个步骤都在一个新的堆栈帧中执 行。例如:
function asyncFunction1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Step 1");
}, 1000);
});
}
asyncFunction1()
.then(result => {
console.log(result); // "Step 1"
return asyncFunction2();
})
.then(result => {
console.log(result); // 在asyncFunction2的结果
})
.catch(error => {
console.error(error);
});
- 使用async/await:
async/await是ES7引入的一种更简洁的异步编程方式,它本质上还是Promise链。你可以使用console.trace()
或者new Error().stack
来获取堆栈信息:
async function asyncFunction1() {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log("Step 1");
return asyncFunction2();
}
async function asyncFunction2() {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log("Step 2");
}
(async () => {
try {
const result = await asyncFunction1();
console.log(result); // "Step 2"
} catch (error) {
console.error(error.stack);
}
})();
- 使用第三方库:
有些库如debug
或console-trace
可以帮助你更好地追踪异步堆栈。例如debug
:
const debug = require('debug')('my-app:async-stack');
async function asyncFunction1() {
debug('Step 1');
// ...
}
asyncFunction1();
这些方法可以帮助你在控制台看到异步调用的堆栈,但请注意,对于非常复杂的异步代码,这可能不是一种完全精确的方法,因为异步操作可能在多个地方并发执行,而console.trace()
或Error.stack
只会在特定时间点捕获堆栈。
11. 使用console.log
、console.warn
、console.error
的最佳实践。
在JavaScript中,console.log
、console.warn
和console.error
是开发者工具中最常用的三个方法,它们用于输出调试信息、警告和错误。以下是一些使用这些方法的最佳实践:
-
console.log
:- 用于记录应用的常规信息,如变量值、函数返回结果等。
- 通常在开发阶段使用,因为它们不会影响生产环境的性能。
- 示例:
console.log('Current date:', new Date());
-
console.warn
:- 当遇到可能影响用户体验但不会立即崩溃的问题时,使用warn。例如,用户输入了无效的数据或选择了某个可能导致不理想结果的 选项。
- 示例:
console.warn('Invalid input provided:', input);
-
console.error
:- 用于记录严重错误,这些错误可能会导致应用崩溃或者无法继续执行。例如,网络请求失败、未定义的变量引用等。
- 在生产环境中,错误会被记录并发送给错误跟踪系统,以便快速定位和修复问题。
- 示例:
console.error('Error fetching data:', error.message);
-
避免滥用:
- 不要在生产代码中过度使用
console
方法,因为它们在生产环境下的运行效率较低,并且可能会干扰用户的浏览体验。 - 对于日志记录,应使用专门的日志库(如 Winston、Log4js 等),它们提供了更好的控制和可配置性。
- 不要在生产代码中过度使用
-
格式化输出:
- 使用
console.log
时,可以使用模板字符串或对象来提供更易读的输出,如console.log({ key: 'value', anotherKey: 'anotherValue' });
- 对于复杂的错误对象,可以使用
JSON.stringify()
进行格式化输出,如console.error(JSON.stringify(error, null, 2));
- 使用
-
清理日志:
- 在部署到生产环境后,确保移除所有调试日志,以减少不必要的服务器负载和带宽消耗。
-
测试工具支持:
- 有些测试框架(如Jest)提供了对
console
方法的模拟,以便在单元测试中更好地控制和断言输出。
- 有些测试框架(如Jest)提供了对
-
遵循团队约定:
- 如果你的团队有特定的命名规范或日志级别策略,确保遵循这些约定,这有助于保持代码的一致性和可维护性。
12. 解释并使用console.table
来优化数组或对象的查看。
console.table
是JavaScript中的一个内置函数,它允许你在浏览器的开发者工具的控制台中以表格的形式展示数据。这对于查看和分 析数组或对象的数据结构非常有用,特别是当数据量较大或者需要快速浏览和比较数据时。
以下是一个简单的例子,我们将创建一个数组和一个对象,然后使用console.table
来展示它们:
// 创建一个数组
const arrayData = [
{ name: 'John', age: 30, city: 'New York' },
{ name: 'Jane', age: 28, city: 'Chicago' },
{ name: 'Mike', age: 35, city: 'Los Angeles' },
{ name: 'Sarah', age: 26, city: 'San Francisco' }
];
// 创建一个对象
const objectData = {
students: [
{ id: 1, name: 'Alice', grade: 'A' },
{ id: 2, name: 'Bob', grade: 'B' },
{ id: 3, name: 'Charlie', grade: 'C' },
{ id: 4, name: 'Dave', grade: 'D' }
]
};
// 使用console.table展示数组
console.table(arrayData);
// 使用console.table展示对象
console.table(objectData.students);
当你在浏览器的开发者工具中运行这段代码,你会看到如下输出:
name | age | city
--------|-----|-----
John | 30 | New York
Jane | 28 | Chicago
Mike | 35 | Los Angeles
Sarah | 26 | San Francisco
id | name | grade
-------|------|------
1 | Alice| A
2 | Bob | B
3 | Charlie| C
4 | Dave | D
console.table
自动处理了数据的排序和格式化,使得复杂的数据结构更易于阅读和理解。
13. Webpack的基本配置与核心概念。
Webpack是一个模块打包工具,它将你的应用的静态资源(如CSS、图片、JavaScript等)打包成一个或多个文件,以优化浏览器的加载速度和性能。以下是Webpack的基本配置和核心概念:
1. 安装Webpack
首先,你需要在项目中安装Webpack。如果你使用的是Node.js,可以使用npm(Node Package Manager)进行安装:
npm install webpack --save-dev
2. 创建Webpack配置文件
Webpack通过一个名为webpack.config.js
的配置文件来定义如何处理你的模块。这是基本的配置示例:
const path = require('path');
module.exports = {
// 输出的打包文件名称
output: {
filename: 'bundle.js',
// 输出文件的路径
path: path.resolve(__dirname, 'dist')
},
// 模块的入口点
entry: './src/index.js',
// 规则:用于处理不同类型的模块
module: {
rules: [
// JavaScript模块
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 编译ES6+代码
options: {
presets: ['@babel/preset-env'] // 使用环境相关的Babel配置
}
},
exclude: /node_modules/ // 忽略node_modules中的文件
},
// CSS模块
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
output
:定义了打包后的文件名和输出路径。entry
:指定应用的入口点,即开始执行的地方。module.rules
:定义了处理不同文件类型的规则。在这个例子中,我们处理了.js
和.css
文件。
3. Webpack的核心概念
- 模块(Modules):Webpack将你的代码分割成一个个小的、可重用的部分。
- 加载器(Loaders):负责处理特定类型的模块,例如
babel-loader
用于编译ES6代码,css-loader
用于处理CSS。 - 插件(Plugins):用于扩展Webpack的功能,比如代码压缩、错误报告等。
- 模块解析(Module Resolution):Webpack如何查找和解析模块。
- 模块热替换(Hot Module Replacement, HMR):在不刷新页面的情况下更新模块。
以上是Webpack的基本配置和核心概念,实际使用时可能需要根据项目需求进行更复杂的配置。
14. Babel的作用及如何配置它进行ES6+语法转译。
Babel是一个JavaScript编译器,它的主要作用是将ES6(ECMAScript 2015)及以后的版本的JavaScript代码转换为ES5(早期版本的JavaScript),使得这些新特性的代码能够在旧版浏览器中运行。Babel支持的不仅仅是ES6,还包括ES7、ES8等更新的JavaScript特性,如箭头函数、let和const、模板字符串、模块系统等。
以下是如何配置Babel进行ES6+语法转译的基本步骤:
-
安装Babel:首先,你需要在你的项目中安装Babel。如果你使用npm,可以在命令行中输入以下命令:
npm install --save-dev @babel/core @babel/cli @babel/preset-env
这里安装了Babel的核心库,CLI工具(用于在命令行中运行Babel),以及一个环境相关的preset,它会自动处理浏览器兼容性问题。
-
配置Babel:在你的项目中,通常会在
package.json
文件中添加一个scripts
字段,用于定义Babel的转换命令。例如:"scripts": { "build": "babel src --out-dir dist" }
这个配置表示,当你运行
npm run build
时,Babel会将src
目录下的所有JavaScript文件转换为ES5语法,并输出到dist
目录。 -
使用Babel:你可以在
.babelrc
文件或者babel.config.js
(如果是ES6+)中进一步配置Babel,比如选择要转译的语言版本,添加插件等。例如,以下是一个简单的.babelrc
配置:{ "presets": ["@babel/preset-env"] }
这个配置会根据目标环境自动选择需要的转译规则。
-
在你的JavaScript代码中,你可以直接使用ES6+的语法,Babel会在编译时将其转换为ES5的语法。
注意:Babel不会自动运行,你需要在构建流程中调用它,比如在webpack、Gulp或Rollup等构建工具中集成。
15. 使用Gulp或Grunt自动化任务的示例。
Gulp和Grunt都是流行的前端构建工具,它们可以帮助你自动化常见的开发任务,如编译Sass,压缩CSS和JS,图片优化,HTML文件合并等。以下是一个使用Gulp的基本示例:
首先,你需要安装Gulp和一些插件。在你的项目目录下,打开终端并运行以下命令:
npm init -y
npm install --save-dev gulp gulp-sass gulp-concat gulp-uglify imagemin imagemin-mozjpeg imagemin-pngquant
这会创建一个package.json
文件,并安装了Gulp和几个常用的Gulp插件。
然后,创建一个名为gulpfile.js
的文件,添加以下代码:
const gulp = require('gulp');
const sass = require('gulp-sass');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const imagemin = require('gulp-imagemin');
const pngquant = require('imagemin-pngquant');
const mozjpeg = require('imagemin-mozjpeg');
// Sass编译任务
gulp.task('sass', function() {
return gulp.src('src/scss/**/*.scss')
.pipe(sass())
.pipe(gulp.dest('dist/css'));
});
// JS合并和压缩任务
gulp.task('scripts', function() {
return gulp.src(['src/js/*.js', 'src/js/**/*.js'])
.pipe(concat('main.js'))
.pipe(uglify())
.pipe(gulp.dest('dist/js'));
});
// 图片优化任务
gulp.task('images', function() {
return gulp.src('src/images/**/*')
.pipe(imagemin([
pngquant({ quality: [0.6, 0.8] }),
mozjpeg({ quality: 75 }),
]))
.pipe(gulp.dest('dist/images'));
});
// 启动默认任务
gulp.task('default', gulp.parallel('sass', 'scripts', 'images'));
在这个例子中,我们定义了三个任务:sass
用于编译Sass,scripts
用于合并和压缩JavaScript,images
用于优化图片。gulp.parallel
用于并行执行这些任务,而gulp.series
则会按照任务的顺序执行。
现在,你可以通过在终端中运行gulp
来执行这些任务。例如,gulp sass
将只编译Sass,gulp
或gulp default
将执行所有任务。
16. Rollup与Webpack相比的优缺点。
Rollup和Webpack都是现代JavaScript开发中的重要构建工具,它们在处理模块打包和优化方面都有自己的特点和适用场景。
Rollup的优点:
- 更小的体积:Rollup的核心目标是生成最小化的代码,它专注于模块树的静态分析,而不是像Webpack那样动态解析模块。
- 更快的构建速度:由于其静态分析的特性,Rollup通常比Webpack更快,特别是在处理大型项目时。
- 更好的tree shaking(按需加载):Rollup能够更有效地进行模块分割,支持ES6模块语法,能更好地进行模块优化。
- 更好的模块导入/导出:Rollup对动态导入和动态导出有更好的支持,这对于服务器端渲染和模块化的异步加载非常有用。
Rollup的缺点:
- 插件生态相对较小:虽然Rollup的社区正在增长,但其插件生态系统不如Webpack丰富,特别是对于一些高级功能可能需要自定义编写或寻找第三方解决方案。
- 配置复杂度:对于一些复杂的项目,Rollup的配置可能会比Webpack更复杂,特别是对于初学者来说。
- 社区支持和文档:尽管Rollup在不断进步,但其社区规模和文档质量可能不如Webpack成熟。
Webpack的优点:
- 大量的插件和生态系统:Webpack有庞大的插件库,几乎可以实现所有你想要的功能,如热更新、懒加载、CSS处理等。
- 动态导入和模块解析:Webpack通过loader机制支持动态导入和各种类型的文件处理。
- 支持多种模块系统:Webpack不仅支持ES6模块,还支持CommonJS和AMD等其他模块系统。
- 更广泛的社区和资源:Webpack是业界最流行的构建工具之一,拥有丰富的文档和教程。
Webpack的缺点:
- 性能问题:对于大型项目,Webpack的启动时间可能会比较长,尤其是在处理大型依赖库时。
- 学习曲线较陡峭:Webpack的配置文件可以相当复杂,对于新手来说可能需要花费更多的时间去理解和学习。
- 静态分析有限:Webpack更倾向于动态解析,这可能导致在某些情况下无法进行有效的tree shaking。
17. 实现一个简单的Webpack加载器(Loader)或插件(Plugin)。
在Webpack中,加载器(Loader)用于转换文件内容,如将ES6模块转换为CommonJS模块,或者将CSS文件转换为CSS模块。插件(Plugin)则是在Webpack运行时执行额外任务,如代码分割、压缩等。以下是一个简单的Webpack插件示例,它会在编译时添加一个全局变量:
首先,我们需要创建一个名为MyWebpackPlugin.js
的插件文件:
// MyWebpackPlugin.js
class MyWebpackPlugin {
apply(compiler) {
compiler.hooks.done.tap('MyWebpackPlugin', (stats) => {
if (stats.hasErrors()) {
console.error('Webpack build failed:', stats.toString());
} else {
console.log('Webpack build successful!');
}
});
}
}
module.exports = MyWebpackPlugin;
在这个插件中,我们使用了Webpack的hooks
API,done
钩子会在构建完成后被触发。如果构建成功,我们会打印一条成功的消息;如果有错误,我们会打印错误信息。
然后,在你的Webpack配置文件webpack.config.js
中,你可以像这样使用这个插件:
const MyWebpackPlugin = require('./MyWebpackPlugin');
module.exports = {
// ...其他配置
plugins: [
new MyWebpackPlugin()
]
};
现在,每次你运行webpack
命令时,MyWebpackPlugin
都会在构建结束时执行相应的操作。这是一个非常基础的插件示例,实际使用中你可能会根据需要添加更复杂的逻辑。
18. 解释并配置Webpack的Code Splitting。
Code Splitting是Webpack的一项重要功能,它允许我们将大型应用分割成多个小的、可加载的部分,而不是一次性加载整个应用。这样 可以显著提高首屏加载速度和用户体验,特别是在处理大型前端项目时。
当用户访问一个页面时,Webpack会根据模块的大小和使用情况,动态地将代码分割成多个小块(chunk)。这些小块可以在需要的时候再进行加载,而不是一开始就全部加载到内存中。这对于SEO友好,因为搜索引擎爬虫不需要等待整个应用加载完毕就可以抓取部分内容。
以下是使用JavaScript和Webpack配置Code Splitting的基本步骤:
- 安装必要的插件:首先,你需要安装
webpack
和webpack-cli
,以及用于代码分割的react-loadable
或dynamic-import
插件。 你可以使用npm或yarn来安装:
npm install --save webpack webpack-cli react-loadable
# 或者
yarn add webpack webpack-cli react-loadable
- 配置Webpack:在你的
webpack.config.js
文件中,设置代码分割的相关选项。这里我们使用react-loadable
作为示例:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const LoadablePlugin = require('loadable/webpack-plugin');
module.exports = {
// ...其他配置
optimization: {
splitChunks: {
cacheGroups: {
async: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// 指定每个chunk的名称,通常包含模块的名称
const chunksName = module.resourcePath.match(/\\/g).reduce((chunk, path, index) => {
return `${chunk}${index > 0 ? '-' : ''}${path.replace(/\\/g, '_')}`;
}, '');
return `async-${chunksName}`;
},
priority: 10, // 设置优先级,数值越大优先级越高
enforce: true,
chunks: 'all', // 所有chunk都进行分割
},
},
},
},
plugins: [
new LoadablePlugin({
filename: 'loadable-stats.json', // 生成的统计文件名
statsFilename: 'loadable-stats.json', // 用于分析的文件名
}),
new BundleAnalyzerPlugin(), // 可选:用于生成bundle分析报告
],
};
- 使用
react-loadable
:在React组件中,我们可以使用loadable-components
库来实现代码分割。例如:
import Loadable from 'loadable-components';
// 创建一个可延迟加载的组件
const LazyComponent = Loadable({
loader: () => import('./LazyComponent.js'), // 要加载的组件路径
loading: () => <div>Loading...</div>, // 加载状态
fallback: null, // 错误状态
});
function App() {
return (
<div>
<button onClick={() => LazyComponent.load()}>Load Lazy Component</button>
{/* 当组件加载完成后,这里会显示组件 */}
{LazyComponent.render()}
</div>
);
}
export default App;
当你点击"Load Lazy Component"按钮时,LazyComponent
组件就会开始加载。注意,import
语句被包装在Loadable
函数内,这使得Webpack能够识别并将其分割为独立的chunk进行加载。
19. npm与yarn的区别和选择依据。
npm
(Node Package Manager)和yarn
都是JavaScript开发中常用的包管理器,它们的主要区别和选择依据如下:
-
速度和效率:
- Yarn: Yarn的设计目标之一是提高安装速度和性能。它使用了tarball缓存和并行下载,可以显著减少依赖包的安装时间。特别是在大规模项目中,Yarn的加载速度通常比npm更快。
- Npm: 虽然npm在早期版本中存在一些性能问题,但随着npm5及后续版本的改进,其速度也有了显著提升。不过对于大型项目,Yarn 的优势仍然明显。
-
锁定文件:
- Yarn: Yarn有一个.lock文件,它可以确保在任何机器上安装的依赖包版本都是一致的,这对于团队协作非常有帮助,避免因环境差异导致的问题。
- Npm: npm也有一个package-lock.json文件,但从npm 5开始,它默认不启用,需要手动创建。这可能导致团队成员之间的版本不一 致。
-
更新策略:
- Yarn: 更新时,Yarn会使用semver规范来决定是否自动升级,提供了更细粒度的控制。它还支持自动锁定锁定文件中的依赖。
- Npm: npm的更新策略更为直接,如果新版本满足兼容性要求,就会自动升级。
-
社区支持:
- Npm: 由于npm的使用更加广泛,因此社区资源和插件库可能更多,尽管Yarn也在不断追赶。
-
生态系统:
- Npm: 因为npm的历史悠久,所以大部分现有的JavaScript库和工具都是基于npm构建的,直接使用npm可能会更容易找到相关的插件 和库。
- Yarn: 尽管如此,Yarn的生态系统也在迅速扩大,尤其是在企业级开发中,Yarn逐渐被采用。
-
命令一致性:
- Npm: npm的命令相对简单,对于已经习惯npm的开发者来说,学习成本较低。
- Yarn: Yarn的命令结构更清晰,但在初次接触时可能会觉得有些复杂。
综上所述,选择npm还是yarn主要取决于你的项目需求和个人偏好。如果你的团队对依赖版本控制有较高要求,或者项目较大且追求性能 ,Yarn可能是一个更好的选择。而对于小型项目或者个人开发者,npm可能更方便。
20. 使用npm script进行项目构建和任务运行。
在Node.js项目中,我们可以使用npm(Node Package Manager)的scripts特性来定义和运行各种任务。这些任务可以是任何你想要执行 的JavaScript代码,例如编译、打包、测试、部署等。以下是一个简单的示例:
首先,你需要在你的项目根目录下创建一个package.json
文件,这是npm管理项目配置的地方。如果你还没有创建,可以使用npm init
命令来初始化。
{
"name": "my-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js", // 启动服务器
"build": "webpack", // 使用webpack构建
"test": "jest", // 运行单元测试
"lint": "eslint . --ext .js", // 代码格式检查
"deploy": "npm run build && ssh user@server 'cd /var/www/my-project && git pull && npm install && npm run build'" // 部署到服务器
},
"author": "",
"license": "ISC"
}
在这个例子中:
"start"
:启动你的应用,假设它是一个Node.js服务器,通过运行index.js
。"build"
:使用webpack进行构建,具体的命令取决于你的配置。"test"
:运行Jest(或其他测试框架)进行单元测试。"lint"
:使用ESLint检查代码风格。"deploy"
:先构建项目,然后通过SSH连接到远程服务器,切换到项目目录,拉取最新的代码,安装依赖,然后再次构建并部署。
你可以通过npm run
命令来执行这些任务,例如npm run build
、npm test
或npm run deploy
。
注意:deploy
脚本中的ssh
命令需要在你的系统上设置好SSH密钥,以避免每次都需要输入密码。这只是一个基本示例,实际的脚本可能会根据你的项目需求和工具链有所不同。
21. 解释package.json
文件的各个字段含义。
package.json
是Node.js项目中的一个重要文件,它包含了关于项目的元数据和依赖信息。这个文件是由npm(Node Package Manager)创建并维护的。以下是一些主要字段的含义:
-
name: 项目的名称,例如 "express" 或 "my-app"。这是在npm上识别你的包的关键标识符。
示例:"name": "my-project"
。 -
version: 包的版本号。遵循语义化版本号(SemVer)规则,如1.0.0、2.3.4等。
示例:"version": "1.0.0"
。 -
description: 简短描述项目或包的作用。
示例:"description": "A simple Node.js web server"
。 -
author: 创建者或主要开发者的姓名或组织名。
示例:"author": "John Doe <john.doe@example.com>"
。 -
license: 项目使用的开源许可协议,如MIT、GPL、Apache等。
示例:"license": "MIT"
。 -
main: 指定主模块或入口文件,通常是index.js。
示例:"main": "index.js"
。 -
dependencies: 包依赖的其他npm包及其版本。键是依赖的包名,值是版本号。
示例:"dependencies": { "express": "^4.17.1", "body-parser": "^1.19.0" }
。 -
devDependencies: 开发时依赖的包,如测试框架、构建工具等。
示例:"devDependencies": { "jest": "^26.6.3" }
。 -
scripts: 定义了项目的脚本任务,如启动应用、测试、打包等。
示例:"scripts": { "start": "node index.js", "test": "jest" }
。 -
repository: 项目仓库的URL,通常指向GitHub或其他代码托管平台。
示例:"repository": { "type": "git", "url": "https://github.com/user/repo.git" }
。 -
bugs: 提供问题报告或错误报告的链接。
示例:"bugs": { "url": "https://github.com/user/repo/issues" }
。 -
keywords: 用于搜索和分类的关键词,方便他人找到你的项目。
示例:"keywords": ["node", "web", "server"]
。
这些字段可以根据项目的需要进行扩展,但以上是最常见的。package.json
是npm安装、升级、管理包以及生成包发布信息的基础。
22. 使用npm install
时的--save
、--save-dev
区别。
npm install
是一个命令,用于在Node.js项目中安装依赖包。当你在项目中安装一个包时,可以使用--save
或--save-dev
选项来管理这些依赖。
--save
:当你使用npm install <package-name>
(例如,npm install express
)并且加上--save
选项时,这个包会被添加到项目的package.json
文件的dependencies
字段中。dependencies
是你的应用程序运行所必需的依赖。例如:
{
"dependencies": {
"express": "^4.17.1"
}
}
这表示你的项目需要Express v4.17.1或更高版本。
--save-dev
:当你安装的是开发工具或者用于构建的包(例如,npm install --save-dev eslint
),它们会被添加到package.json
的devDependencies
字段中。devDependencies
是项目开发过程中使用的工具,不包含在生产环境中的应用代码中。例如:
{
"devDependencies": {
"eslint": "^7.32.0"
}
}
这表示你的项目在开发阶段使用ESLint v7.32.0或更高版本。
总结来说,--save
用于安装项目运行时需要的库,而--save-dev
用于安装开发环境和构建过程所需的工具。
23. 如何解决npm依赖冲突?
在Node.js中,npm(Node Package Manager)可能会遇到依赖冲突,特别是当你在一个项目中安装了多个包,它们之间又有相互依赖的情况。以下是一些解决npm依赖冲突的方法:
-
明确版本号:在安装依赖时,可以指定特定的版本号,例如
npm install package-name@version
。这样可以确保你安装的是预期的版本,避免与其他包的版本冲突。 -
锁定依赖:使用
npm shrinkwrap
或yarn.lock
(对于Yarn)文件来锁定你的依赖树到特定版本。这样在后续的安装过程中 ,npm或yarn会优先使用锁定的版本,而不是全局或项目的默认版本。 -
升级或降级依赖:如果冲突是因为某个依赖的版本过旧或新,你可以尝试升级或降级这个依赖。使用
npm update package-name
或npm install package-name@lower-version
。 -
查看依赖关系:使用
npm ls
或npm tree
命令查看项目的依赖关系,找出可能引起冲突的部分。 -
使用
npm dedupe
:这个命令可以尝试在项目中找到重复的依赖,并将其移到一个单独的文件夹中,以减少依赖冲突。 -
创建并管理多个工作区:使用 npm v7 及以上版本,你可以创建一个工作区,每个子目录都有自己的依赖包版本。这有助于隔离 不同项目的依赖。
-
手动编辑 package.json:在极端情况下,你可能需要手动编辑
package.json
文件,移除或替换冲突的依赖。但这是最后的手段,因为可能会破坏其他功能。
记得在进行任何修改后,都要确保你的项目仍然能够正常运行。如果问题依然存在,可能需要查看包的文档或者在相关社区寻求帮助。
24. Yarn的工作空间(Workspaces)功能及其应用场景。
Yarn工作空间(Workspace)是Yarn 2的一个重要特性,它提供了一种更高级的方式来管理大型项目中的依赖和模块结构。在传统的模块 管理中,每个项目都有自己的node_modules
目录,这可能导致文件重复、版本冲突等问题。而工作空间则将多个项目共享的依赖抽取出来,统一管理,提高了项目的可维护性和开发效率。
工作空间的主要特点包括:
- 共享依赖:在一个工作空间下,所有子项目都可以共享相同的依赖,避免了每个项目都安装同一份依赖的情况。
- 全局状态:工作空间有一个全局的
yarn.lock
文件,确保所有子项目使用的是同一套依赖版本,解决了版本冲突问题。 - 项目分隔:每个子项目都有自己的
package.json
文件,可以定义自己的依赖和配置,保持项目的独立性。
应用场景:
- 大型多模块项目:如大型企业级应用,可能包含多个模块或子项目,如前端、后端、移动端等,这些部分可能有共同的依赖,使用工作空间可以简化管理和维护。
- 微前端架构:在微前端架构中,多个小的独立应用共享一部分通用库,使用工作空间可以方便地管理这些共享的库。
- 模块化工具链:例如构建工具、测试框架等,它们可能被多个项目所共享,工作空间可以更好地组织和管理这些工具。
在JavaScript中,使用Yarn工作空间的基本步骤如下:
- 初始化一个新的工作空间:
yarn workspace init
- 创建子项目:
yarn create my-sub-project
- 在子项目中,添加依赖:
cd my-sub-project
yarn add <dependency>
- 共享依赖:
在工作空间的顶层目录下,添加共享依赖:
yarn add --shared <dependency>
- 使用依赖:
在子项目中,可以通过@workspace/dependency
的形式引用共享依赖。
通过Yarn工作空间,你可以更有效地组织和管理大型JavaScript项目。
25. Git基本命令及其在日常开发中的应用。
Git是一种分布式版本控制系统,它在日常开发中起着至关重要的作用,尤其是在协作开发和版本控制方面。以下是一些基本的Git命令及其在JavaScript开发中的应用:
git init
:这是最基本的命令,用于在本地创建一个新的Git仓库。在开始一个新项目或为现有项目初始化Git时,你通常会使 用这个命令。
// 在项目目录下运行
git init
git add
:将更改添加到暂存区,以便提交。在JavaScript开发中,当你修改了代码、创建了新的文件或删除了文件后,可以使用这个命令添加这些更改。
// 添加所有更改
git add .
// 或者添加特定文件
git add filename.js
git commit -m "commit message"
:提交暂存区的更改到仓库。在这个命令中,-m
后面的是提交信息,描述你的更改。
// 提交更改
git commit -m "Fixed bug in utils.js"
git branch
:查看当前分支,或者创建新的分支。在JavaScript项目中,你可以创建新的功能分支来进行开发,避免影响主分 支。
// 查看所有分支
git branch
// 创建新分支
git checkout -b new-feature
-
git checkout master
:切换到主分支(通常是master
)。在完成新功能或修复后,你需要将更改合并回主分支。 -
git merge branch-name
:将指定分支的更改合并到当前分支。例如,如果你想将new-feature
分支的更改合并到master
分 支:
git merge new-feature
-
git pull
:从远程仓库拉取最新的代码更新到本地。这对于团队合作非常重要,确保每个人都在使用最新版本的代码。 -
git push
:将本地的更改推送到远程仓库。当你的工作完成后,需要将更改推送到GitHub或其他托管服务,以便其他人可以查 看和审查。
git push origin master
git log
:查看提交历史,了解代码的演变过程。
以上就是一些基本的Git命令及其在JavaScript开发中的应用。当然,Git还有许多其他高级功能,如分支管理、冲突解决等,但这些都是基础操作。
26. 解释Git分支策略和合并冲突处理。
Git分支策略和合并冲突处理是Git版本控制系统中两个重要的概念,它们帮助团队协作开发并保持代码的完整性。
-
Git分支策略:
- 创建分支:在Git中,开发新功能或修复问题通常在一个新的分支上进行,而不是直接在主分支(通常是
main
或master
)上。这样可以避免直接修改主分支,导致其他开发者的工作受到影响。 - 频繁提交:每个小的代码更改都应在一个新的提交中,这样便于跟踪每个更改的历史。
- 合并策略:当一个分支开发完成后,会通过
git merge
命令将其合并回主分支。这可能需要解决可能的合并冲突,因为同一时间可能有多个开发者在不同的分支上做出了修改。
- 创建分支:在Git中,开发新功能或修复问题通常在一个新的分支上进行,而不是直接在主分支(通常是
-
合并冲突处理:
- 合并冲突:当两个或更多的分支对同一行代码进行了修改时,Git无法自动决定应该保留哪一种修改,这就产生了冲突。Git会 在合并后生成一个冲突文件,显示被修改但未解决的代码片段。
- 解决冲突:开发者需要手动打开这些冲突文件,查看并选择要保留的修改。可以选择保留其中一个版本,或者合并两者,或者 删除冲突的部分。解决完冲突后,需要使用
git add
命令标记已解决的冲突,然后用git commit
提交更改。 - 使用文本编辑器:大多数情况下,Git会提供一个文本编辑器让你直接修改冲突文件,比如
vim
、emacs
或默认的文本编辑器。
以下是一个简单的JavaScript示例,展示如何在Git中创建分支、提交更改以及处理合并冲突:
# 创建一个新的分支
$ git checkout -b feature-branch
# 在feature-branch上做更改
// ... (编写代码)
$ echo "This is my new feature" >> src/new-feature.js
# 提交更改
$ git add src/new-feature.js
$ git commit -m "Add new feature"
# 在另一个分支上做更改,产生冲突
$ git checkout master
// ... (修改src/old-feature.js)
$ echo "This is a change in master" >> src/old-feature.js
# 合并feature-branch到master
$ git merge feature-branch
# 发现冲突
$ git status # 看到src/new-feature.js有冲突提示
# 打开冲突文件,解决冲突
$ nano src/new-feature.js # 使用文本编辑器
// ... (选择要保留的修改,删除冲突部分)
# 提交解决冲突后的更改
$ git add src/new-feature.js
$ git commit -m "Merge feature branch and resolve conflicts"
在这个例子中,开发者需要手动检查冲突,并根据项目需求决定保留哪个分支的更改。
27. 使用ESLint进行代码风格检查和自动格式化。
ESLint是一个流行的JavaScript代码质量工具,它可以帮助你检查代码风格、潜在的错误和编写最佳实践。以下是如何在项目中设置和使用ESLint进行代码风格检查和自动格式化的步骤:
-
安装ESLint:
首先,你需要在你的项目中安装ESLint。打开终端(或命令提示符),然后运行以下命令:npm install eslint --save-dev
这将安装ESLint并将其添加到你的项目的devDependencies。
-
配置ESLint:
ESLint需要一个配置文件来定义规则和选项。在项目根目录下创建一个.eslintrc
文件(如果没有的话),或者在已有的.eslintrc
文件中进行配置。你可以创建一个基本的配置,例如:{ "extends": "eslint:recommended", "rules": { // 可以在这里添加或修改特定的规则 "indent": ["error", 2], // 指定缩进为2个空格 "linebreak-style": ["error", "unix"] // 使用Unix行尾换行符 } }
这里我们使用了
eslint:recommended
配置,这是ESLint推荐的标准配置。 -
运行ESLint:
安装完成后,你可以通过运行以下命令来检查代码风格:npx eslint your_file.js
如果你想检查整个项目,可以使用:
npx eslint .
-
自动格式化:
ESLint本身并不直接提供代码格式化的功能,但你可以配合其他工具如prettier
一起使用。首先,安装prettier
:npm install prettier --save-dev
然后,在
.eslintrc
中添加prettier
配置:{ "extends": "eslint:recommended", "plugins": ["prettier"], "rules": { // ... }, "settings": { "prettier": { "printWidth": 80, // 设置最大行宽 "tabWidth": 2, // 设置tab宽度 "singleQuote": true, // 使用单引号 "trailingComma": "all" // 强制所有对象和数组结束时有逗号 } } }
现在,当你运行
npx eslint --fix .
时,ESLint会尝试自动修复代码格式问题。 -
集成到构建流程:
为了使ESLint成为持续集成的一部分,你可以在package.json
的scripts
部分添加一个脚本,例如:"scripts": { "lint": "eslint .", "format": "prettier --write \"src/**/*.js\"" }
这样,你可以通过
npm run lint
来检查代码风格,通过npm run format
来自动格式化代码。
以上就是使用ESLint进行代码风格检查和自动格式化的基本步骤。你可以根据项目需求调整配置,ESLint提供了丰富的规则和插件,以适应各种编码风格和最佳实践。
28. 配置Prettier进行代码格式化。
Prettier是一个流行的JavaScript代码格式化工具,它可以帮助你保持一致的代码风格。以下是如何在项目中配置Prettier的步骤:
-
安装Prettier:
在你的项目根目录下运行以下命令(假设你已经安装了Node.js):npm install --save-dev prettier
或者,如果你使用Yarn:
yarn add --dev prettier
-
配置Prettier:
Prettier默认的配置文件是.prettierrc
,你可以创建这个文件或者在已有项目中找到它。如果找不到,Prettier会查找package.json
中的"prettier"
字段来获取配置。创建一个
.prettierrc
文件并添加以下内容(这是一个基本的配置示例,你可以根据需要自定义):{ "tabWidth": 2, "semi": true, // 使用分号 "singleQuote": true, // 使用单引号 "trailingComma": "all", // 所有逗号后都加逗号 "arrowParens": "always", // 箭头函数括号总是存在 "bracketSpacing": true, // 代码块和数组/对象的括号之间有空格 "jsxBracketSameLine": false, // JSX的括号是否在同一行 "printWidth": 80, // 每行的最大字符数 "parser": "babel" // 使用Babel解析器(如果你的项目使用ES6+) }
-
配置 ESLint:
如果你的项目使用ESLint进行代码检查,你可能还需要配置它来忽略Prettier的更改。在.eslintrc.js
或.eslintrc.yaml
文件中 添加以下规则:module.exports = { plugins: ['prettier'], rules: { 'prettier/prettier': 'off', // 关闭Prettier的自动修复 }, };
-
使用Prettier:
在你的开发环境中,你可以通过运行以下命令来格式化整个项目:npx prettier --write **/*.js
或者,如果你使用VS Code、WebStorm等IDE,可以安装相应的插件,它们通常会提供一键格式化的功能。
-
自动格式化:
为了在每次保存文件时自动格式化,你可以在package.json
中添加一个脚本,如:"scripts": { "format": "npx prettier --write \"src/**/*.{js,jsx,json,yml,yaml}\"" },
然后在编辑器中设置快捷键或使用命令行
npm run format
来格式化代码。
现在,每次你保存代码时,Prettier都会自动应用配置的格式。
29. 使用Jest或Mocha进行单元测试的示例。
以下是一个使用Jest进行单元测试的基本示例。我们将测试一个简单的JavaScript函数,该函数接收两个数字并返回它们的和。
首先,我们有一个要测试的函数:
// 你的代码文件(假设名为add.js)
export function add(a, b) {
return a + b;
}
然后,我们创建一个测试文件来测试这个函数(假设名为add.test.js):
// 使用Jest进行单元测试
import { add } from './add';
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
test('adds 0 + 0 to equal 0', () => {
expect(add(0, 0)).toBe(0);
});
test('throws an error when non-numeric arguments are provided', () => {
expect(() => add('a', 'b')).toThrow('Both arguments must be numbers');
});
在这个例子中:
test
函数是Jest提供的用于定义测试的方法。每个test
函数都会执行一次独立的测试。expect
函数用于断言实际的结果是否符合预期。toBe
是其中一个断言方法,用于检查两个值是否相等。toThrow
是一个断言方法,用于检查函数是否抛出了预期的错误。
运行这个测试文件,你可以使用Jest命令行工具(npm test
或yarn test
),Jest会自动运行所有测试并显示结果。如果所有测试都 通过,你将看到一个绿色的“PASS”消息。如果有任何失败的测试,你会看到详细的错误信息。
30. 介绍并使用代码覆盖率工具分析测试覆盖度。
代码覆盖率(Code Coverage)是一种衡量软件测试质量的指标,它描述了测试用例覆盖了多少代码。高代码覆盖率意味着你的测试用例 覆盖了更多的代码路径,从而提高了软件的质量和可靠性。
在JavaScript中,我们可以使用一些开源的代码覆盖率工具来测量我们的测试覆盖率。其中最常用的是 Istanbul(以前称为 Icovia,现在是 Istanbul.js 的一部分)和 Jest 的内置覆盖率报告。
以下是一个使用Istanbul的简单示例:
- 首先,你需要安装Node.js和Istanbul。在终端或命令行中运行以下命令:
npm install --save-dev istanbul cover _mocha
- 然后,创建一个简单的JavaScript文件,比如
add.js
:
function add(a, b) {
return a + b;
}
module.exports = add;
- 编写一个测试文件,比如
test.js
,使用Mocha进行测试:
const add = require('./add');
describe('Add function', () => {
it('should add 1 and 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
it('should add 5 and 7 to equal 12', () => {
expect(add(5, 7)).toBe(12);
});
});
-
在你的项目根目录下运行
istanbul cover _mocha --report lcovonly -- -R spec
。这将运行测试并生成覆盖率报告。 -
最后,你可以使用
istanbul report html
命令生成HTML覆盖率报告,或者使用istanbul check-coverage --statements 100%
检查是否达到100%的语句覆盖率。
注意:在实际项目中,你可能需要在package.json
中添加脚本来自动化这个过程,并且在每次代码提交前运行覆盖率检查。
这只是使用Istanbul的基本示例,实际的覆盖率工具可能会提供更详细的报告和配置选项。
31. 如何使用VSCode或WebStorm提高开发效率?
VSCode和WebStorm都是非常强大的代码编辑器,它们提供了许多功能来帮助开发者提高开发效率。以下是一些使用这些工具提高JavaScript开发效率的方法:
-
**智能代码提示(IntelliSense):**这两个编辑器都具有强大的代码补全功能。当你输入一个函数、变量或对象名时,它们会自动 列出可能的选项,节省了查找文档的时间。
-
**自动格式化(Code Formatting):**通过设置,你可以一键格式化代码,保持代码风格的一致性,减少手动格式化的工作量。例如,Prettier在VSCode中是一个很好的插件,而WebStorm也有内置的格式化工具。
-
**代码片段(Snippets):**编写重复的代码块时,可以使用预定义的代码片段,只需输入简短的触发关键字即可。比如,你可以在WebStorm中创建自定义JS模板。
-
**调试工具:**VSCode和WebStorm都有强大的调试工具,包括断点、单步执行、查看变量值等,这对于查找和修复错误非常有帮助。
-
**代码检查(Linting):**它们都有内置的ESLint或其他类似工具,实时检查代码质量,避免常见的语法错误和编码规范问题。
-
**版本控制集成:**与Git或其他版本控制系统无缝集成,方便你管理代码版本,协作开发。
-
**扩展支持(Extensions):**VSCode和WebStorm都有丰富的扩展市场,可以根据需求安装特定的插件,如TypeScript支持、React/Vue/Angular等框架的特定插件、Node.js工具等。
-
**多语言支持:**不仅限于JavaScript,它们还支持多种编程语言,可以在同一个项目中轻松切换。
-
**自动完成和文档查找:**通过快捷键或者搜索框,你可以快速找到函数、类、API的文档信息。
-
**项目管理和任务管理:**对于大型项目,可以利用它们的项目管理功能,如任务列表、依赖管理等。
总之,要充分利用这些工具提高效率,关键是熟悉其快捷键和设置,根据自己的开发习惯定制工作区,以及定期更新和学习新的功能。
32. 实现代码重构的步骤和工具辅助。
代码重构是一种改进代码质量的过程,它不改变代码的行为,但通过改进其结构、设计和实现,使其更易于理解和维护。以下是使用JavaScript进行代码重构的一些步骤和可能的工具:
-
**理解代码:**首先,你需要完全理解你正在重构的代码。这包括了解其功能、如何工作以及任何相关的业务逻辑。这可以通过阅读 和测试代码来完成。
-
**识别问题:**寻找代码中的重复、冗余、复杂性或不良设计。这可能是由于过度耦合、过长的方法、不必要的全局变量等引起的。
-
**制定计划:**确定重构的目标。例如,你可能想要将一个大函数分解为多个小函数,或者将一个模块化的结构更好地组织起来。
-
**编写测试:**在重构之前,确保有充分的测试覆盖。这样可以确保你在修改代码时不会破坏原有的功能。
-
**重构:**使用工具(如ESLint、Prettier等)进行代码格式化和优化。然后,按照你的计划逐步修改代码,每次只修改一小部分, 确保每一步都能通过测试。
-
**测试和审查:**在每次重构后,都要运行所有测试以确保代码仍然按预期工作。如果可能,让同事审查你的代码,他们可能会发现 你未注意到的问题。
-
**持续集成/持续部署(CI/CD):**使用工具如Jenkins、Travis CI等,可以在每次提交后自动运行测试,确保代码质量。
-
**记录更改:**使用版本控制系统(如Git)记录每一次的重构,以便于回溯和审计。
一些常用的JavaScript重构工具包括:
- ESLint:用于检查代码风格和潜在错误。
- Prettier:自动格式化代码,保持一致的代码风格。
- JSHint或TypeScript:类似ESLint,用于静态代码分析。
- React Hooks:对于React开发,可以帮助你重构状态管理和副作用处理。
- TSLint:TypeScript特定的代码风格检查器。
记住,重构是一个迭代过程,需要时间和耐心,但最终结果会是更清晰、更可维护的代码。
33. 代码审查的最佳实践和工具(如GitHub PRs)。
代码审查是软件开发过程中的一项重要活动,它有助于提高代码质量,确保团队间的理解和协作。以下是一些代码审查的最佳实践和常用的工具,以JavaScript为例:
-
明确的审查准则:制定一套清晰的编码规范和风格指南,例如Airbnb的JavaScript风格指南或Google的JavaScript编码风格。这 将帮助团队成员了解期望的代码格式。
-
使用Pull Requests (PR):在GitHub等平台上,通过创建PR来发起代码审查。这使得每个人都可以查看、讨论和提供反馈,而不 仅仅是代码作者。
-
定期审查:不要等到代码完成才开始审查,而是尽早进行。这样可以及时发现并修复问题。
-
小而频繁的提交:鼓励开发者将大改动分解成多个小的PR,这样更容易理解和讨论。
-
详细且具体的反馈:提供具体的改进建议,而不是笼统的评价。例如,指出代码哪里可以优化,或者为什么要这样做。
-
代码质量检查工具:
- ESLint:JavaScript的静态代码分析工具,可以自动检测代码中的潜在问题。
- JSCS或Prettier:格式化工具,确保代码风格的一致性。
- SonarQube:更全面的代码质量管理平台,包括单元测试覆盖率、复杂度等指标。
-
代码评审工具:
- GitHub内置的Pull Request功能:可以直接在评论区进行代码审查。
- GitLab CI/CD:可以在合并请求时自动运行测试和代码质量检查。
- CodeClimate:提供了在线代码审查工具,支持多种语言,包括JavaScript。
-
保持尊重:在审查过程中,要尊重他人的工作,避免贬低或过度批评。
-
持续学习和改进:定期回顾和调整审查流程,寻找提高效率和质量的方法。
通过遵循这些最佳实践和使用适当的工具,可以帮助团队建立一个高效、高质量的代码审查过程。
34. 使用Lerna管理多包项目的场景与实践。
Lerna是一个流行的JavaScript库,它专为管理和发布大型、依赖性复杂的JavaScript项目而设计。它允许你在一个单一的Git仓库中管理多个npm包,每个包都有自己的版本控制,但共享一个公共的依赖树。以下是使用Lerna管理多包项目的常见场景和实践:
-
场景:
- 模块化应用:如果你有一个大型的应用程序,由多个独立的功能模块组成,每个模块都可以作为一个单独的npm包发布。
- 库或框架开发:当你在构建一个包含多个库或组件的框架时,每个库或组件可以有自己的版本。
- 共享代码库:如果你有多个项目需要使用相同的代码库,使用Lerna可以避免重复的工作。
-
实践:
创建多包项目:
- 初始化一个新的Lerna项目:
lerna init
- 创建新的包:
lerna add <package-name>
- 对于每个包,你可以编写自己的代码,并在每个包的
package.json
中定义其名称、描述、依赖等。
版本管理:
- 更新所有包的版本:
lerna version <type>
(例如,lerna version patch
用于发布小版本更新) - 发布到npm:
lerna publish
命令行脚本:
- 通过
.lernarc.js
文件,你可以定义全局脚本,如npm run build
,它将在所有包中运行。
依赖管理:
- Lerna自动处理依赖项,确保所有包都使用相同的依赖版本。如果某个包升级了依赖,Lerna会自动更新其他依赖此包的包。
工作流集成:
- 与GitHub Actions、Travis CI或CircleCI等CI/CD工具集成,自动化构建、测试和发布流程。
问题解决:
- 如果遇到冲突,Lerna提供了
lerna resolve
命令来解决版本号冲突。
- 初始化一个新的Lerna项目:
-
注意事项:
- Lerna适用于大规模项目,对于小型项目可能显得过于复杂。
- 需要定期同步所有包的版本,以保持一致性。
- 在大型团队中,良好的沟通和文档是关键,确保所有人都了解如何正确地使用和维护Lerna项目。
35. Service Worker的调试方法和工具。
Service Worker是一种浏览器内置的离线缓存技术,它可以在用户与网络断开连接时提供服务。调试Service Worker可以帮助我们理解其行为,优化性能,解决可能的问题。以下是一些常见的调试Service Worker的方法和工具:
-
浏览器开发者工具:
- Chrome浏览器:在开发者工具中,选择"Application"标签页,然后点击"Service Workers"。在这里,你可以看到所有已注册 的服务工人,以及它们的状态(如"Installing", "Activating", "Waiting", "Running"等)。点击一个worker,可以看到其控制的scope、script URL和事件日志。
- Firefox浏览器:在开发者工具中,选择"Performance"标签页,然后点击"Service Workers"。你可以看到类似Chrome的界面。
-
console.log()
:
在Service Worker的JavaScript代码中,使用console.log()
打印信息,可以帮助你跟踪代码执行过程。这些信息会在浏览器的开发者工具的Console面板中显示。 -
self.registration
对象:
这个对象提供了对Service Worker注册的信息,包括安装状态、更新状态等。你可以使用它来检查服务工人是否已经正确安装和激活 。 -
navigator.serviceWorker
API:
使用这个API,你可以监听特定的事件,如install
,activate
,fetch
等,以便在事件发生时进行调试。 -
Service Worker DevTools:
Chrome浏览器有Service Worker DevTools插件,可以提供更深入的调试功能,如查看请求和响应的详细信息,设置断点等。 -
workbox
库:
Workbox是一个强大的库,用于开发Service Worker。它提供了一系列的工具和API,方便开发者创建自定义的离线策略。Workbox还提供了workbox-dev
模块,用于模拟网络环境,方便调试。 -
sw-toolbox
库:
这是另一个用于简化Service Worker开发的库,它提供了一些预定义的策略,如缓存策略、路由策略等。在开发过程中,你可以使用 它的debug
模式来查看详细的日志。
以上就是一些常用的Service Worker调试方法和工具,具体使用哪种取决于你的需求和所用的浏览器。
36. 如何使用Lighthouse进行网页性能审计?
Lighthouse 是一个由 Google 开发的开源工具,用于评估网站的性能、可访问性、最佳实践等多个方面。它是一个浏览器扩展,可以直 接在 Chrome 或 Firefox 的开发者工具中运行。以下是如何使用 Lighthouse 进行网页性能审计的步骤,以 JavaScript 为例:
-
安装 Lighthouse 扩展:
- 对于 Chrome:在 Chrome Web Store 中搜索 "Lighthouse",然后点击 "Add to Chrome" 安装。
- 对于 Firefox:在 Firefox Add-ons 网站上搜索 "Lighthouse",然后点击 "Add to Firefox"。
-
打开你要审计的网页:
- 在浏览器中打开你想要检查的网页。
-
启动 Lighthouse 分析:
- 右键点击页面,选择 " audits"(Chrome)或 "Lighthouse"(Firefox),或者直接在地址栏输入
chrome://lighthouse
(Chrome)或about:devtools#lighthouse
(Firefox)并回车。
- 右键点击页面,选择 " audits"(Chrome)或 "Lighthouse"(Firefox),或者直接在地址栏输入
-
配置审计参数(可选):
- 在 Lighthouse 页面,你可以选择不同的审计类型(如 "Auditing"、"Best Practices"、"Performance" 等)和特定的配置选项(如网络环境、设备类型等)。
- 如果需要,也可以上传一个文件来分析其性能,而不是当前页面。
-
运行审计:
- 点击 "Run" 或 "Analyze" 按钮开始审计。Lighthouse 会分析页面并生成报告。
-
查看审计结果:
- Lighthouse 会生成一个详细的报告,包括评分、问题列表以及改善建议。报告分为几个部分:
Categories
(类别)、Audits
(审计)、Details
(详细信息)和Score
(评分)。 - JavaScript 性能相关的审计可能包括
First Contentful Paint
、Cumulative Layout Shift
、Time to Interactive
等关键指标。
- Lighthouse 会生成一个详细的报告,包括评分、问题列表以及改善建议。报告分为几个部分:
-
解决问题:
- 根据 Lighthouse 提供的问题和建议,优化你的 JavaScript 代码,例如减少 HTTP 请求、优化代码结构、压缩资源等。
-
再次运行审计:
- 修复问题后,再次运行 Lighthouse 以查看性能是否有提升。
通过以上步骤,你可以有效地使用 Lighthouse 来评估和改进你的网页性能,特别是 JavaScript 相关的部分。
37. 实施代码拆分和懒加载的策略。
在JavaScript中,代码拆分和懒加载是一种优化性能的技术,特别是对于大型应用或那些在用户需要时才加载的组件。以下是一些实现这些策略的方法:
-
代码拆分(Code Splitting):
-
Webpack:Webpack 4及更高版本提供了动态导入(
import()
)功能,可以让我们在运行时按需加载模块。例如,我们可以这 样使用:// main.js import('./chunk1.js'); import('./chunk2.js');
Webpack会根据入口文件的需求,将相关的模块打包成不同的chunk(小块),然后在需要的时候再下载。
-
Rollup:Rollup也支持代码分割,通过
rollup-plugin-code-splitting
插件可以实现。例如:import dynamic from 'rollup-plugin-dynamic-import-async'; export default { ... plugins: [ dynamic({ loader: 'my-loader', name: 'dynamic-module' }) ] };
这样,只有当
my-loader
被实际使用时,才会进行加载。
-
-
懒加载(Lazy Loading):
-
Intersection Observer API:这是一种原生的浏览器API,可以监听元素是否进入视口,一旦进入,就异步加载对应的资源。 例如:
const lazyLoad = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; // 加载实际图片URL } }); }); const lazyImage = document.querySelector('.lazy'); lazyImage.dataset.src = 'https://example.com/lazy-image.jpg'; lazyLoad.observe(lazyImage);
-
Preload 和 Prefetch:预加载(
preload
)和预获取(prefetch
)标签可以提前请求资源,但不会阻塞页面渲染。例如:<link rel="preload" href="chunk2.js" as="script"> <link rel="prefetch" href="chunk3.js">
-
通过以上方法,你可以有效地减少初始加载时间,提高用户体验。
38. 使用Chrome Performance Monitor监控页面性能。
Chrome Performance Monitor是一个强大的工具,可以帮助你分析网页的性能瓶颈,包括JavaScript执行时间、CPU使用率、内存使用情 况等。以下是如何使用它来监控JavaScript性能的步骤:
-
打开Chrome浏览器,然后右键点击页面,选择"检查"(或者按F12)打开开发者工具。
-
在开发者工具的底部,你会看到一个标签页列表,找到并点击"Performance"或者"Timeline"标签。
-
点击右上角的"Record"按钮开始录制性能数据。此时,你可以滚动页面或者执行一些操作,Chrome会记录下这些操作的性能数据。
-
当你想要停止录制时,点击"Stop"按钮。Chrome会立即显示一个性能面板,其中包括了你的操作的详细时间线。
-
在时间线上,你可以看到每个事件的时间点,包括JavaScript的执行时间。找到JavaScript相关的部分,通常在"Script"或"JS"类别 下。
-
你可以点击每个脚本事件,查看详细的性能信息,包括执行时间、CPU使用率、内存使用情况等。这可以帮助你找出可能的性能问题,比如某个函数执行过慢,或者内存泄漏。
-
如果你想比较不同版本或不同操作的性能,可以在"Presences"选项卡中创建新的记录,然后对比它们。
记住,性能优化是一个持续的过程,通过反复测试和调整,你可以不断改进你的网页性能。
39. 解释并应用Critical CSS。
Critical CSS(Critical Rendering Path,关键渲染路径)是指在网页首次加载时,浏览器为了渲染页面内容所需加载的最小、最必要 的CSS样式。这些CSS样式直接影响到页面上可见内容的布局和显示,因此被称为"critical"。优化Critical CSS可以显著提高网站的首屏渲染速度,提升用户体验。
当用户打开一个网页时,浏览器首先会下载HTML、JavaScript和图片等资源,然后解析并应用Critical CSS来构建基本的结构和布局。如果CSS文件过大或者CSS中的非关键样式过多,这将导致页面在初始加载时出现空白或部分加载的情况,直到CSS完全加载和应用。
以下是一个简单的JavaScript示例,用于动态生成并注入Critical CSS到HTML中:
// 假设我们有一个CSS文件,其中包含了一些关键样式
const criticalStyles = `
/* 这里是你的关键CSS */
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
header {
background-color: #333;
color: white;
}
`;
// 当页面加载完成时执行此函数
window.addEventListener('DOMContentLoaded', function() {
// 获取HTML的head元素
const head = document.head;
// 创建一个style元素
const styleElement = document.createElement('style');
styleElement.type = 'text/css';
// 将Critical CSS插入到style元素中
styleElement.innerHTML = criticalStyles;
// 将style元素添加到head中
head.appendChild(styleElement);
// 如果你想实时更新Critical CSS,例如从服务器获取动态数据
fetch('/path/to/critical-styles.js')
.then(response => response.text())
.then(criticalStyles => {
styleElement.innerHTML = criticalStyles;
});
});
在这个例子中,我们首先定义了Critical CSS,然后在DOMContentLoaded
事件触发后将其添加到HTML文档的<head>
部分。如果需要,还可以通过JavaScript从服务器获取最新的Critical CSS并动态更新。
请注意,实际应用中通常会使用专门的工具(如Critical、Autoprefixer、CSSNano等)来自动化这个过程,它们能分析CSS并提取出关键部分。
40. 使用Sourcemaps进行错误跟踪和调试。
Sourcemaps是一种将源代码映射到编译后的代码的工具,这对于开发者在浏览器的开发者工具中进行错误跟踪和调试非常有用。当你的代码经过压缩、混淆或转换(如Babel)后,原始的源代码可能变得难以阅读。Sourcemaps提供了原始源代码的信息,使得开发者可以在浏 览器的开发者工具中看到未被修改的源代码,而不是实际运行的代码。
以下是一个简单的JavaScript示例,演示如何使用Sourcemaps进行错误跟踪:
- 首先,我们有一个简单的JavaScript文件(source.js):
// source.js
function add(a, b) {
return a + b;
}
console.log(add(2, '3')); // 这里会抛出错误,因为add函数期望两个数字作为参数
- 然后,我们使用Babel等工具将这个文件转换为ES5或者更旧的版本,并生成一个新的文件(transformed.js),同时创建一个sourcemap文件(source.map):
babel source.js -o transformed.js --source-maps inline
- 在transformed.js中,源代码已经被转换,但原始的代码仍然是可读的:
// transformed.js
(function() {
"use strict";
function _add(a, b) {
return a + b;
}
console.log(_add(2, '3'));
})();
- 当我们在浏览器的开发者工具中打开transformed.js,查看错误时,它会指向source.js中的原始位置:
- 如果我们在transformed.js的
_add(2, '3')
行抛出错误,开发者工具会显示:
Uncaught TypeError: Cannot read property 'toString' of number
at _add (transformed.js:5)
at eval (transformed.js:10)
在这个例子中,开发者工具告诉我们错误发生在transformed.js:5
,但实际上这是Sourcemap帮助我们定位到source.js:3
,即console.log(add(2, '3'))
这行。
通过Sourcemaps,即使你的代码经过了复杂的转换,也能保持错误信息的准确性和可读性,极大地提高了调试效率。
站点信息
- 建站时间:2017-10-06
- 网站程序:Koa+Vue
- 本站运行:
- 文章数量:
- 总访问量:
- 微信公众号:扫描二维码,关注我