一、初识 Node.js

(一)浏览器中的 JavaScript

JavaScript 最初是运行在浏览器端的脚本语言,主要用于实现网页的交互效果,比如表单验证、页面元素的动态操作等。浏览器为 JavaScript 提供了诸如 DOM(文档对象模型)操作、BOM(浏览器对象模型)操作等 API,但它的运行环境局限于浏览器。

(二)什么是 Node.js

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。它让 JavaScript 可以脱离浏览器,在服务器端运行。通过 Node.js,开发者可以使用 JavaScript 来构建后端应用程序,实现如文件操作、网络通信等功能,极大地拓展了 JavaScript 的应用场景。

(三)安装 Node.js

  1. 访问 Node.js 官方网站(https://nodejs.org/),根据自己的操作系统(Windows、macOS、Linux 等)下载对应的安装包。
  2. 运行安装包,按照提示进行安装。安装完成后,打开命令行工具(Windows 下为 cmd 或 PowerShell,macOS 和 Linux 下为终端),输入 node -v 和 npm -v 命令,如果能显示出 Node.js 和 npm(Node 包管理器)的版本号,说明安装成功。

(四)使用 Node 运行 JS 代码

  1. 新建一个后缀为 .js 的文件,比如 hello.js,在文件中编写 JavaScript 代码,例如:console.log("Hello, Node.js!");
  2. 打开命令行工具,进入到 hello.js 文件所在的目录,输入 node hello.js 命令,即可在命令行中看到输出的 “Hello, Node.js!”。

二、fs 模块:文件系统操作

(一)读取文件内容

Node.js 中的 fs 模块(文件系统模块)提供了读取文件的方法。以下是使用 fs.readFile() 方法读取文件内容的示例:

const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});
  • require('fs'):引入 fs 模块。
  • fs.readFile():异步读取文件,第一个参数是要读取的文件路径,第二个参数是编码格式(这里用 utf8),第三个参数是回调函数,用于处理读取结果或错误。如果读取成功,data 变量存储文件内容;如果出错,err 变量存储错误信息。   

    (二)写入文件内容

    使用 fs.writeFile() 方法可以向文件中写入内容,示例如下:

    const fs = require('fs');
    fs.writeFile('example.txt', 'Hello, this is written by Node.js!', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('File written successfully!');
    });

  • fs.writeFile():异步写入文件,第一个参数是文件路径,第二个参数是要写入的内容,第三个参数是回调函数,处理写入过程中的错误。如果写入成功,会输出 “File written successfully!”。

    (三)整理成绩的案例

    假设存在一个存储学生成绩的文本文件 scores.txt,内容格式为 “学生姓名 成绩”,每行一个学生。我们需要读取该文件,计算平均成绩,并将结果写入新的文件 result.txt 中。代码示例如下:

    const fs = require('fs');
    fs.readFile('scores.txt', 'utf8', (err, data) => {
      if (err) {
        console.error(err);
        return;
      }
      const lines = data.split('\n');
      let totalScore = 0;
      let studentCount = 0;
      lines.forEach(line => {
        if (line.trim() !== '') {
          const parts = line.split(' ');
          const score = parseInt(parts[1]);
          totalScore += score;
          studentCount++;
        }
      });
      const averageScore = totalScore / studentCount;
      const result = `学生总数:${studentCount}\n总成绩:${totalScore}\n平均成绩:${averageScore}`;
      fs.writeFile('result.txt', result, (err) => {
        if (err) {
          console.error(err);
          return;
        }
        console.log('成绩整理完成,结果已写入 result.txt 文件!');
      });
    });

  • 首先读取 scores.txt 文件内容,按行分割后遍历每一行,提取成绩并计算总和与学生数量。
  • 然后计算平均成绩,将结果组织成字符串,写入 result.txt 文件。

    三、模块化:Node.js 的代码组织方式

    (一)模块作用域和 module 对象

    在 Node.js 中,每个文件都是一个独立的模块,具有独立的作用域。模块内部定义的变量、函数等,默认情况下只能在模块内部访问,这就是模块作用域。module 对象是 Node.js 为每个模块提供的一个对象,它包含了当前模块的相关信息。例如,module.exports 属性用于指定模块对外暴露的内容。

    (二)module.exports 对象的使用

    module.exports 是模块向外暴露接口的主要方式。可以将需要对外提供的变量、函数、对象等赋值给 module.exports。示例如下:

    // 模块文件:math.js
    const add = (a, b) => a + b;
    const subtract = (a, b) => a - b;
    module.exports = {
      add,
      subtract
    };
    
    // 另一个文件中引入 math.js 模块
    const math = require('./math');
    console.log(math.add(1, 2)); // 输出 3
    console.log(math.subtract(5, 3)); // 输出 2

    在 math.js 模块中,通过 module.exports 向外暴露了 add 和 subtract 两个函数。在其他文件中,使用 require('./math') 引入该模块后,就可以调用这两个函数。

    (三)exports 对象

    exports 是 module.exports 的一个引用,在模块内部,exports 初始时指向 module.exports。可以通过给 exports 添加属性或方法来向外暴露内容,示例如下:

    // 模块文件:greet.js
    exports.sayHello = () => {
      console.log('Hello!');
    };
    exports.sayHi = () => {
      console.log('Hi!');
    };
    
    // 引入 greet.js 模块
    const greet = require('./greet');
    greet.sayHello(); // 输出 Hello!
    greet.sayHi(); // 输出 Hi!

    需要注意的是,不能直接给 exports 赋值一个新的对象(如 exports = {}),因为这样会断开 exports 与 module.exports 的引用关系,导致对外暴露失效。如果需要对外暴露一个全新的对象,应该使用 module.exports

    (四)exports 和 module.exports 的关系

  • exports 是 module.exports 的引用,初始时 exports === module.exports
  • 当给 exports 添加属性或方法时,相当于给 module.exports 添加,因为它们指向同一个对象。
  • 当直接给 module.exports 赋值一个新对象时,module.exports 就不再指向原来与 exports 相同的对象,此时 exports 的操作不会影响到 module.exports 对外暴露的内容。所以,为了避免混淆,建议尽量使用 module.exports 来向外暴露模块内容。

    四、包与 npm:Node.js 的包管理生态

    (一)包的概念

    在 Node.js 中,包(package)是一个包含了模块、资源文件等的目录,并且包含一个描述包信息的 package.json 文件。包可以是一个功能完整的模块,也可以是一组相关模块的集合。通过包,开发者可以方便地共享和复用代码。

    (二)格式化时间的两种做法

  • 手动编写代码格式化时间
    const formatTime = (date) => {
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const hours = String(date.getHours()).padStart(2, '0');
      const minutes = String(date.getMinutes()).padStart(2, '0');
      const seconds = String(date.getSeconds()).padStart(2, '0');
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    };
    console.log(formatTime(new Date()));

    通过 JavaScript 内置的 Date 对象和字符串方法,手动编写函数来格式化时间,将日期对象转换为指定格式的时间字符串。

  • 使用 npm 包格式化时间:首先,在项目目录下打开命令行,执行 npm install moment 命令,安装 moment 包(moment 是一个非常流行的处理时间和日期的 npm 包)。然后在代码中使用:
    const moment = require('moment');
    console.log(moment().format('YYYY-MM-DD HH:mm:ss'));

    (三)使用 npm 的其它注意点

  • package.json 文件
    • 每个 Node.js 项目都应该有一个 package.json 文件,它记录了项目的基本信息(如名称、版本、描述等)以及项目所依赖的包。可以通过 npm init 命令来初始化生成 package.json 文件。
  • 依赖的安装
    • 安装包时,使用 npm install <package-name> 会将包安装到项目的 node_modules 目录下,并在 package.json 的 dependencies 字段中记录该依赖(生产环境依赖)。如果是开发环境依赖(如测试框架等),可以使用 npm install <package-name> --save-dev,依赖会记录在 devDependencies 字段中。
  • node_modules 目录
    • 该目录用于存放项目安装的所有依赖包,一般不需要手动修改里面的内容。而且,node_modules 目录通常不会被提交到版本控制系统(如 Git)中,因为可以通过 package.json 和 package-lock.json 重新安装依赖。
  • package-lock.json 文件
    • 该文件用于锁定安装的依赖包的版本,确保在不同的环境中安装的依赖版本一致,避免因版本差异导致的问题。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐