global
javascript的语言特性决定了,一定会有一个顶层对象(top object),但是根据执行环境的不同,这个顶层对象是不一样的。由执行环境决定,比如在浏览器执行环境中,顶层对象是window。而在node里,顶层对象是global
global里定义了一些全局的对象或函数,在node的任何一个模块里,都可以直接使用,比如console,setTimeout(),require()等,完整的global object document见:node.js global objects
如果想在不同的模块(文件)之间共享变量,有一个可行但是很糟糕的做法,就是借助这个global object,在global上定义的属性和函数,在任何模块里都可以访问到
global.name = "Tony";
然后在a.js里
require("./b");// 执行b.js里的代码
console.log(name);// Tony
另外一种更简单(也更容易引起错误)的做法,是不用var关键字声明变量,也会成为global的属性
name = "Tony";
但是,如果加上了var关键字,声明的变量就只局限在module(当前文件)的作用域中,所以强烈推荐显式地用var来声明变量,以免不小心挂到了global上
var name = "Tony";
为什么依赖global是不好的实践呢?因为所有的模块都可以不受限制地使用global,而且缺少命名空间的约束,非常容易引起冲突,从而引发潜在的BUG。而且这种BUG一旦发生,要定位是极其困难的,不知道是在哪里改变了全局变量而引发的问题
所以javascript的最佳实践,是强烈建议不要修改global object,只使用global上预定义的属性和函数
module
在模块里用var声明的变量,全部都是在module作用域里的,优先于global作用域的属性
global.name = "Tony";
require("./b");// 执行b.js里的代码
var name = "kyfxbl";
console.log(name);// kyfxbl
以上代码会输出"kyfxbl",而不是"Tony",因为module的name比global的name更优先
module.exports vs exports
如果想不借助global,在不同模块之间共享代码,就需要用到exports属性。令人有些迷惑的是,在node.js里,还有另外一个属性,是module.exports。一般情况下,这2个属性的作用是一致的,但是如果对exports或者module.exports赋值的话,又会呈现出令人奇怪的结果
网上关于这个话题的讨论很多,流传最广的是这个帖子:exports vs module.exports,但是这篇帖子里有些说法明显是错误的,却没有人指出来。下面说一下我的理解
首先,exports和module.exports都是某个对象的引用(reference),初始情况下,它们指向同一个object,如果不修改module.exports的引用的话,这个object稍后会被导出
所以不管用exports还是module.exports,给这个object添加属性或函数,都是完全等效的
exports.name = "Tony";
module.exports.age = 33;
var b = require("./b");
console.log(b);// {name:"Tony", age:33}
所以如果只是给对象添加属性,不改变exports和module.exports的引用目标的话,是完全没有问题的
但是有时候,希望导出的是一个构造函数,那么一般会这么写:
module.exports = function (name, age) {
this.name = name;
this.age = age;
}
exports.sex = "male";
var Person = require("./b");
var person = new Person("Tony", 33);
console.log(person);// {name:"Tony", age:33}
console.log(Person.sex);// undefined
这个sex属性是不会导出的,因为引用关系已经改变:
而node导出的,永远是module.exports指向的对象,在这里就是function。所以exports指向的那个object,现在已经不会被导出了,为其增加的属性当然也就没用了
如果希望把sex属性也导出,就需要这样写:
exports = module.exports = function (name, age) {
this.name = name;
this.age = age;
}
exports.sex = "male";
事实上,查看很多module的源代码,会发现就是这么写的,这时的引用关系:
所以我感觉exports根本是多余的,最终只会导出一个object,却设计了2个引用,很多时候反而会造成迷惑。exports的唯一好处就是可以少敲几个字,还不如只保留module.exports就好了
exports的缓存
执行require之后,目标模块的代码会被完整地执行一次,然后module.exports对象被返回
需要注意的是,这个过程只会发生一次,后面重复的require,只会拿到同一个对象
exports.name = "Tony";
exports.age = 33;
var b1 = require("./b");
var b2 = require("./b");
console.log(b1 === b2); // true
console.log(b2.age);// 33
b1.age++;
console.log(b2.age);// 34
var b3=require("./b");
console.log(b3.age);// 34
这个时候的引用关系是这样的:
分享到:
相关推荐
Node.js 模块是构成 Node.js 应用程序的基础组件,它们允许开发者通过导入和导出来组织和重用代码。Node.js 的模块系统是其强大功能之一,它遵循 CommonJS 规范,使得代码可以模块化,提高了代码的可读性和可维护性...
书中会探讨`require`和`module.exports`的使用,以及如何自定义模块。 4. **文件系统(File System,简称FS)**:Node.js提供了丰富的文件系统API,如读写文件、创建删除目录等。书中会详细讲解这些API的用法,以及...
2. **模块系统**:Node.js使用模块化设计,每个`.js`文件都可以视为一个模块,通过`require`和`exports`或`module.exports`来导入和导出模块。 3. **V8引擎**:Node.js使用Google的V8引擎,使得JavaScript的执行速度...
2. **模块系统**:Node.js的模块化设计是其强大之处,学习CommonJS规范,require()和module.exports的使用,以及如何创建和使用自定义模块。 3. **文件系统操作**:Node.js提供了便捷的文件系统API,学习如何读写...
总的来说,Node.js的`module`模块是其模块系统的核心,它使得代码组织和复用变得简单高效,同时也提供了诸如`require()`、`exports`、`module.exports`等工具,以及`__filename`和`__dirname`这样的便利变量,以支持...
前言Node中,每个模块都有一个exports接口对象,我们需要把公共的方法或者字符串挂载在这个接口对象中,其他的模块才可以使用。Node.js中只有模块作用域
对于Vue.js项目,尤其是由`@vue/cli`生成的Vue3项目,`package.json`中的`main`、`module`和`exports`字段用于指定不同环境下的入口文件,这有助于优化加载和打包过程。本文将深入探讨这三种方式的使用以及如何...
`require()`函数用于导入模块,`exports`和`module.exports`用于导出模块内容。理解模块机制是深入学习Node.js的基础。 ### 4. 事件机制 Node.js的事件驱动模型是其高效处理并发的关键。事件循环监听各种事件,并...
Node.js是一款基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript编写程序,从而打破了JavaScript只能在浏览器中运行的传统。Node.js通过事件驱动、非阻塞I/O模型,使其轻量且高效,非常...
了解CommonJS规范,以及如何使用require和module.exports来导入和导出模块,是深入学习Node.js的必经之路。 五、Node.js进阶 1. Express框架:Express是基于Node.js的最流行的Web应用框架,简化了路由、中间件和...
在Node.js中,模块的导出和导入是通过CommonJS规范实现的,而exports和module.exports则是实现模块导出的关键概念。虽然在日常开发中经常使用这两个概念,但很多开发者可能会忽视它们之间的区别,这可能会在模块的...
内置的 `module` 和 `exports` 对象使得模块间的通信变得简单。 3. **V8引擎**:Node.js 基于 Google 的 V8 JavaScript 引擎,使得 JavaScript 代码能够以接近原生速度运行,提高了性能。 4. **文件系统(FS)模块...
Node.js 引入了模块(Module)概念,一个模块可以通过module.exports 或 exports 将函数、变量等导出,以使其它 JavaScript 脚本通过require() 函数引入并使用。 module.exports 初始值为一个空对象 {},所以 ...
在本示例中,我们将探讨如何使用Node.js进行乘法和平方操作。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript,提供了一个高效的开发平台。 首先,我们关注`htutil.js`...
2. **模块系统**: Node.js使用CommonJS模块规范,通过`require`导入模块,`module.exports`或`exports`导出模块。在源代码中,你可以看到如何组织代码并实现模块化。 3. **文件系统操作**: Node.js提供了丰富的文件...
2. **模块系统**:Node.js 采用了 CommonJS 规范,允许代码按需加载模块,通过 `require` 和 `module.exports` 进行导入和导出。此外,npm(Node Package Manager)是其强大的依赖管理工具,拥有海量的第三方模块,...
2. **模块系统**:Node.js 使用CommonJS模块规范,通过`require`引入模块,`module.exports`或`exports`导出模块。 3. **Express框架**:在Node.js中,Express是最流行的Web应用框架,简化了路由、中间件和HTTP...
- **模块系统**:Node.js内置了CommonJS模块规范,通过`require`导入模块,通过`module.exports`或`exports`导出模块。 - **事件驱动模型**:Node.js采用非阻塞I/O和事件驱动模型,使得它可以高效地处理大量并发...
在开始使用这个API之前,开发者需要对Node.js的基础有所了解,包括模块系统(require和module.exports)、异步编程(回调函数、Promise和async/await)、文件系统操作(fs模块)以及HTTP服务器的构建(http或https...