node.js

Node程序传递参数

在某些情况下执行node程序的过程中,我们可能希望给node传递一些参数:

node index.js env=development xiaoming

我们可以通过process内置对象中获取参数,如果我们直接打印这个内置对象,它里面包含很多信息,比如版本、操作系统等。

process {
  version: 'v14.15.0',
  versions: {
    node: '14.15.0',
    v8: '8.4.371.19-node.17',
    uv: '1.40.0',
    zlib: '1.2.11',
    brotli: '1.0.9',
    ares: '1.16.1',
    modules: '83',
    nghttp2: '1.41.0',
    napi: '7',
    llhttp: '2.1.3',
    openssl: '1.1.1g',
    cldr: '37.0',
    icu: '67.1',
    tz: '2020a',
    unicode: '13.0'
  },
  arch: 'x64',
  platform: 'win32',
  release: {
    name: 'node',
    lts: 'Fermium',
    sourceUrl: 'https://nodejs.org/download/release/v14.15.0/node-v14.15.0.tar.gz',
    headersUrl: 'https://nodejs.org/download/release/v14.15.0/node-v14.15.0-headers.tar.gz',
    libUrl: 'https://nodejs.org/download/release/v14.15.0/win-x64/node.lib'
  },
  _rawDebug: [Function: _rawDebug],
  moduleLoadList: [
    'Internal Binding stream_wrap',
    'Internal Binding tcp_wrap',
    'Internal Binding pipe_wrap',
    'NativeModule internal/stream_base_commons',
    ... 9 more items
  ],
  binding: [Function: binding],
  _linkedBinding: [Function: _linkedBinding],
  _events: [Object: null prototype] {
    newListener: [Function: startListeningIfSignal],
    removeListener: [Function: stopListeningIfSignal],
    warning: [Function: onWarning],
    SIGWINCH: [Function (anonymous)]
  },
  _eventsCount: 4,
  _maxListeners: undefined,
  domain: null,
  _exiting: false,
  config: {
    target_defaults: {
      cflags: [],
      default_configuration: 'Release',
      defines: [],
      include_dirs: [],
      libraries: []
    },
    variables: {
      asan: 0,
      build_v8_with_gn: false,
      coverage: false,
      v8_trace_maps: 0,
      v8_use_siphash: 1,
      want_separate_host_toolset: 0
    }
  },
  dlopen: [Function: dlopen],
  uptime: [Function: uptime],
  _getActiveRequests: [Function: _getActiveRequests],
  _getActiveHandles: [Function: _getActiveHandles],
  reallyExit: [Function: reallyExit],
  _kill: [Function: _kill],
  hrtime: [Function: hrtime] { bigint: [Function: hrtimeBigInt] },
  cpuUsage: [Function: cpuUsage],
  resourceUsage: [Function: resourceUsage],
  memoryUsage: [Function: memoryUsage],
  kill: [Function: kill],
  exit: [Function: exit],
  openStdin: [Function (anonymous)],
  allowedNodeEnvironmentFlags: [Getter/Setter],
  assert: [Function: deprecated],
  features: {
    inspector: true,
    debug: false,
    uv: true,
    ipv6: true,
    tls_alpn: true,
    tls_sni: true,
    tls_ocsp: true,
    tls: true,
    cached_builtins: true
  },
  _fatalException: [Function (anonymous)],
  setUncaughtExceptionCaptureCallback: [Function: setUncaughtExceptionCaptureCallback],
  hasUncaughtExceptionCaptureCallback: [Function: hasUncaughtExceptionCaptureCallback],
  emitWarning: [Function: emitWarning],
  nextTick: [Function: nextTick],
  _tickCallback: [Function: runNextTicks],
  _debugProcess: [Function: _debugProcess],
  _debugEnd: [Function: _debugEnd],
  _startProfilerIdleNotifier: [Function (anonymous)],
  _stopProfilerIdleNotifier: [Function (anonymous)],
  stdout: [Getter],
  stdin: [Getter],
  stderr: [Getter],
  abort: [Function: abort],
  umask: [Function: wrappedUmask],
  chdir: [Function: wrappedChdir],
  cwd: [Function: wrappedCwd],
  env: {
    ALLUSERSPROFILE: 'C:\\ProgramData',
    APPDATA: 'C:\\Users\\hp\\AppData\\Roaming',
  },
  title: 'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe',
  argv: [
    'D:\\nodejs\\node.exe',
    'D:\\qdcode\\node.js\\node传递参数\\01-dome.js'
  ],
  execArgv: [],
  pid: 14472,
  ppid: 18452,
  execPath: 'D:\\nodejs\\node.exe',
  debugPort: 9229,
  argv0: 'D:\\nodejs\\node.exe',
  _preload_modules: [],
  mainModule: Module {
    id: '.',
    path: 'D:\\qdcode\\node.js\\node传递参数',
    exports: {},
    parent: null,
    filename: 'D:\\qdcode\\node.js\\node传递参数\\01-dome.js',
    loaded: false,
    children: [],
    paths: [
      'D:\\qdcode\\node.js\\node传递参数\\node_modules',
      'D:\\qdcode\\node.js\\node_modules',
      'D:\\qdcode\\node_modules',
      'D:\\node_modules'
    ]
  },
  [Symbol(kCapture)]: false
}

找到其中的argv属性:我们发现他是一个数组,里面包含我们传递的参数。
console.log(process.argv);

[
  'D:\\nodejs\\node.exe',
  'D:\\qdcode\\node.js\\node传递参数\\01-dome.js',
  'env=development',
  'xiaoming'
]

全局对象

Node中给我们提供了一些全局对象,方便我们进行一些操作
node.js

特殊的全局对象

其中有一些特殊的全局变量,这些全局对象实际上是模块中的变量,只是每个模块都有,看起来像是全局变量;

但是在命令交互中是不可以使用的;
包括:__dirname、__filename、exports、module、require()

__dirname:获取当前文件所在的路径(不包括后面的文件名)
__filename:获取当前文件所在的路径和文件名称(包括后面的文件名称)

console.log(__dirname); //D:\qdcode\node.js\node传递参数
console.log(__filename); //D:\qdcode\node.js\node传递参数\01-dome.js

常见的全局对象

process对象:提供了Node进程中相关的信息:

  • 比如Node的运行环境、参数信息;
  • 将一些环境变量读取到process的env中;

console对象:提供了简单的调试控制台

定时器参数:在Node中使用定时器有好几种方式:

  • setTimeout(callback,delay[,…args]):callback在delay毫秒后执行一次;
  • setInterval(callback,delay[,…args]):callback每delay毫秒重复执行一次;
  • setImmediate(callback[,…args]):callback I/O事件后的回调的立即执行;
  • process.nextTick(callback[,…args]):添加到下一次tick队列中

global和window的区别

在浏览器中,全局变量都是window上的,比如document、setInterval、alert、console等。
在Node中也有一个global属性,看起来它里面也有很多其他对象。

但是在浏览器中执行js代码,如果我们在*范围内通过var定义一个属性,默认会被添加到window对象上

var name = 'zhangsan'
console.log(window.name) //zhangsan

但是在node中,我们通过var定义一个变量,他只是当前模块中有一个变量,不会放到全局中

var name = 'zhangsan'
console.log(window.name) //undefined

模块化开发

事实上模块化开发最终目标是将程序划分成一个个小的结构,这个结构中编写属于自己的逻辑代码,有自己的作用域,不会影响到其他的结构。

这个结构可以将自己希望暴露的变量、函数、对象导出给其他结构使用。

也可以通过某种方法,导入另外结构中的变量、函数、对象等。

上面提到的结构就是模块;安装这种那个结构划分开发程序的过程,就是模块化开发的过程。

模块化已经是js一个非常迫切的需求:

  • 但是js本身,知道es才推出了自己的模块化方案;
  • 在此之前,为了让js支持模块化,涌现了很多不同的模块化规范:AMD、CMD、CommentJS等。

没有模块化的问题

小明编写的xiaoming.js

var name = '小明'

小红编写的xiaohong.js也使用的name

var name = '小红'

小明又在sayName.js中调用了name变量

console.log(name);

这样的顺序引入js会导致小明的代码被小红的代码覆盖。从而输出错误的信息。

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./xiaoming.js"></script>
  <script src="./xiaohong.js"></script>
  <script src="./sayName.js"></script>
</head>

这种情况我们可以采用立即执行函数结果(IIFE)

xiaoming.js

var xiaoming = (function(){
  var name = 'xiaoming';
  return{
    name
  }
})()

xiaohong.js

var xiaohong =(function(){
  var name = 'xiaohong'
  return {
    name
  }
})()

sayName.js

console.log(xiaoming.name); //xiaoming
console.log(xiaohong.name); //xiaohong

使用立即执行函数我们不必关注js引入的顺序

但是这样也有新的问题:

  • 我们必须记住每一个模块中返回对象的命名,才能在其他模块使用过程中正确的使用;
  • 每个文件中的代码都需要包裹在一个匿名函数中
  • 没有合适的规范中,每个人都可能会任意命名、甚至出现模块名称相同的情况。

CommonJS

我们需要知道CommonJS是一个规范,最初提出来是在浏览器以外的地方使用,并且当时被命名为ServerJS,后来为了体现它的广泛性,修改为CommentJS。

  • Node是CommentJS在服务器端一个具有代表性的实现。
  • Browserify是CommentJS在浏览器中的一种实现;
  • webpack打包工具具备对CommentJS的支持和转换;

所以,Node中对CommentJS进行了支持和实现,让我们在开发node的过程中可以方便的进行模块化开发:

  • 在Node中每一个js文件都是一个单独的模块;
  • 模块中包括CommentJS规范的核心变量:exports、module.exports、require;
  • exports和module.exports可以负责对模块中的内容进行导出;
  • require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容。

基本使用

Bar.js 暴露方法和变量 可以通过module.exports和exports.属性暴露。

const name = 'xiaoming';
const age = 18;
const sayHello = ()=>{
  console.log('hello!!!');
}
console.log(exports) //{} 空对象
//方法一:
module.exports = {
  name,age,sayHello
}
//方法二:
exports.name = name;
exports.age = age;
exports.sayHello = sayHello;

Main.js

const Person = require('./Bar')
console.log(Person.name); //xiaoming
console.log(Person.age);  //18
Person.sayHello(); //hello!!!

node.js
require(’./Bar’)引入的bar其实是Bar.js中暴露出的对象exports的一个浅拷贝(引用赋值)。

当修改bar中的name值时,Bar.js暴露的exports对象中的name也跟着改变。

module.exports和exports的区别

在Node中我们经常使用module.exports导出,这两种方式有什么区别呢?

CommentJS中是没有module.pexorts的概念的,但是为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的示例,也就是module。
所以在Node中真正用于导出的其实根本不是exports,而是module.exports。因为module才是导出的真正实现者。

为什么exports也可以导出呢?
这是因为module对象的exports属性是exports对象的一个引用。
也就是说 module.exports = exports

Bar.js

const name = 'xiaoming';
const age = 18;
const sayHello = ()=>{
  console.log('hello!!!');
}

const car = '奥迪';
const color = 'red';
const sayRun = () =>{
  console.log('红色的奔驰嗖嗖的跑');
}


module.exports = {
  car,color,sayRun
}

exports.name = name;
exports.age = age;
exports.sayHello = sayHello;

Main.js

const bar = require('./Bar')
console.log(bar); //{ car: '奥迪', color: 'red', sayRun: [Function: sayRun] }

node.js
require的值最终取决于module.exports暴露的对象。当设置了module.exports就不带exports玩了。

强调一次:module.exports = exports 。

Bar.js

//module.exports = exports 先执行的
exports = 123

Main.js

const bar = require('./Bar')
console.log(bar); //{}

初始状态,exports默认为{}空对象。module.exports = exports
node.jsexports = 123时,因为123是值传递所以直接把地址改成值。取消了对{}的引用。但是不影响module.exports的指向。
node.js

上一篇:前端模块化简单总结


下一篇:nodejs中的模块系统:exports导出模块