node.js的global variable,和module.exports

本文介绍了Node.js中的全局对象global及其使用注意事项,并详细解释了如何通过module.exports和exports在不同模块间共享代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

这个时候的引用关系是这样的:


一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值