Nodejs之require加载机制(模块可以污染全局空间)

以前就觉得Nodejs的MooTools库很奇怪,因为用他的时候,不需要把require的返回值保存起来,今天实在憋不住,就研究了下,对NodeJs的require机制又有了几分深刻的理解。MooTools库的“奇怪”用法:require('mootools'); var QueryCommand = new Class({ initialize: funct
摘要由CSDN通过智能技术生成

以前就觉得Nodejs的MooTools库很奇怪,因为用他的时候,不需要把require的返回值保存起来,今天实在憋不住,就研究了下,对NodeJs的require机制又有了几分深刻的理解。

MooTools库的“奇怪”用法:

require('mootools');

  var QueryCommand = new Class({
        initialize: function (product, week, action) {
            this.product = product;
            this.weeknum = week;
            this.action = action;
        },

        toJsonString: function () {
            return JSON.stringify(this);
        }
    });

看到没,把require当作C++的include用了,之后的代码可以直接使用Class类型了。其实,MooTools的做法是把Class这个类型“附加”到了全局作用域。我觉得MooTools可能就是这么设计的,因为他是一个OO库嘛。

那么,MooTools是怎么把他自己附加到全局作用域的呢?其实很巧妙,是通过函数字面量做的:

(function(){

var Class = this.Class = new Type('Class', function(params){
	if (instanceOf(params, Function)) params = {initialize: params};

	var newClass = function(){
		reset(this);
		if (newClass.$prototyping) return this;
		this.$caller = null;
		var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
		this.$caller = this.caller = null;
		return value;
	}.extend(this).implement(params);

	newClass.$constructor = Class;
	newClass.prototype.$constructor = newClass;
	newClass.prototype.parent = parent;

	return newClass;
});

......

})();

他通过函数字面量定义了一个匿名函数,然后立即执行之。这个是JS的惯用法。有一点要注意的是,在执行这个函数的时候,其实是没有this指针的!那么在函数内部使用this,访问的就是全局对象,就是那个始祖对象!

再看一个更加简单的例子

app.js

require('./a.js')
console.log(a);

a.js

a = 3; //输出3

注意,上面不是var a=3;所以该语句实在全局作用域上附加了a这个属性(注意,也不是this!是始祖对象),然后呢,在app.js模块就能使用了。其实,在其他的模块也能访问了。


接下来说说,为什么会污染到全局作用域,nodejs不是用require来加载每个模块的嘛,模块应该互相独立的呀,其实nodeJs的模块加载顺序是这样的:

Module._load("xxx.js") --> var module = new Module(); --> module.load("xxx.js") --> module._compile() --> 最终调用的是被wrapper的模块代码,上面那个例子的话,最终执行的是:

(function (exports, require, module, __filename, __dirname) { 
    a = 3;
});

看一下module.compile()的代码就清楚了:

// Returns exception if any
Module.prototype._compile = function(content, filename) {
  var self = this;
  // remove shebang
  content = content.replace(/^\#\!.*/, '');

  function require(path) {
    return self.require(path);
  }

  require.resolve = function(request) {
    return Module._resolveFilename(request, self);
  };

  Object.defineProperty(require, 'paths', { get: function() {
    throw new Error('require.paths is removed. Use ' +
                    'node_modules folders, or the NODE_PATH ' +
                    'environment variable instead.');
  }});

  require.main = process.mainModule;

  // Enable support to add extra extension types
  require.extensions = Module._extensions;
  require.registerExtension = function() {
    throw new Error('require.registerExtension() removed. Use ' +
                    'require.extensions instead.');
  };

  require.cache = Module._cache;

  var dirname = path.dirname(filename);

  if (Module._contextLoad) {
    if (self.id !== '.') {
      debug('load submodule');
      // not root module
      var sandbox = {};
      for (var k in global) {
        sandbox[k] = global[k];
      }
      sandbox.require = require;
      sandbox.exports = self.exports;
      sandbox.__filename = filename;
      sandbox.__dirname = dirname;
      sandbox.module = self;
      sandbox.global = sandbox;
      sandbox.root = root;

      return runInNewContext(content, sandbox, filename, true);
    }

 
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值