面试官:你真的懂模块化?那么这段代码输出什么?

404 阅读1分钟

前言

本文是在node环境下运行,考察到模块化、以及导入导出问题及相关知识

问题

下面这行代码输出结果是什么

//aModule.js
this.m = 3 ;
exports.c = 4;
module.exports = {
    a:1,
    b:2
}
//bModule.js
const result = require("./aModule")
console.log(result)

答案:{a:1,b:2}

转换一下

//aModule.js
exports.c = 4;
module.exports.a=1;
module.exports.b=2;
this.m = 3 ;
//bModule.js
const result = require("./aModule")
console.log(result)

答案:{ c: 4, a: 1, b: 2, m: 3 }

这是为什么呢?不是说在模块化中没有 this吗?为什么最后还能导出m呢?直接蒙了

这就涉及到当我们使用require时,它到底做了什么事来讲起了,下面就用 伪代码简单说一下这个require

require的"伪"实现

function require(modulePath){
    //1.将modulePath转换为绝对路径 : D:\modejs\aModule.js
    //2.判断是否该模块已有缓存 通过打印module可以通过cache对象查看
    if(require.cache["D:\modejs\aModule.js"]){
        //如果有直接就返回结果
        return require.cache["D:\modejs\aModule.js"].result
    }
    //3.如果没有缓存则读取文件内容
    //4.读取文件将其包裹在函数中(以上面例子作为栗子)
    function __temp(module,exports,require,__dirname,__filename{
     // exports.c = 4;
     // module.exports.a=1;
     // module.exports.b=2;
     // this.m = 3 ;
    }
    //5.创建module对象
    module.exports ={};
    const exports = module.exports;
    //6.调用函数
    __temp.call(module.exports,module,exports,require,module.path,module.filename)
}

通过上面伪代码就能看出问题了,__temp函数通过call来调用,那么我们正常调用call是怎么调用的呢?

aaa.call(this,a)

call第一个函数传入的就是this,那么来看看此this是不是彼this?

01.png

通过打印对比 此时的this就是为module的exports,所以真相也浮出水面了,当this.m = 3 ;就是为module赋值,导致最终输出结果有m:3

总结

使用exports导出时不要混合使用,更不要使用this来赋值属性,避免不必要的错误发生

文章有错误的理解可以指出~~~