前端commonjs模块化

在学习commonjs模板化规范的时候,看到大家经常在说的一句话,即导出是值的拷贝,无法通过模块内部去改变属性值。
然后给出以下代码块讲解

// a.js
var name = 'morrain'
var age = 18
exports.name = name
exports.age = age
exports.setAge = function(a){
    age = a
}
// b.js
var a = require('a.js')
console.log(a.age) // 18
a.setAge(19)
console.log(a.age) // 18


我不是很明白这边值的拷贝跟无法通过模块内部去改变属性值有什么必然联系
就不懂为什么a.setAge(19)改不了

在 CommonJS 模块化规范中,每个模块都是独立的作用域,可以有自己的变量和函数,但是模块内部的变量和函数都是私有的,外部无法直接访问,需要通过 exports 或 module.exports 导出才能让其他模块使用。

在上面的代码块中,a.js 中导出的 age 变量和 setAge 函数都被存储在 exports 对象中,即 exports.age 和 exports.setAge,它们都是对 age 变量的引用。当其他模块(如 b.js)引用 a.js 时,通过 var a = require('a.js') 获取到的对象 a 中,a.age 和 a.setAge 也都是对 age 变量的引用。

当 a.setAge(19) 执行时,它改变的是 a.js 模块内部的 age 变量,而不是外部通过 require 获取到的 a 对象中的 age 变量。因为在 CommonJS 模块化规范中,每个模块都有自己的作用域,模块内部的变量和函数都是私有的,外部无法直接访问。因此,a.setAge(19) 改变的是 a.js 模块内部的 age 变量,而不是外部通过 require 获取到的 a 对象中的 age 变量。因此,console.log(a.age) 的输出仍然是 18,而不是预期的 19。

总之,虽然变量是通过引用传递的,但是通过 exports 导出的变量只是对原始变量的引用,并不是原始变量本身。在其他模块中对这些变量进行修改时,只是修改了对原始变量的引用,而不是原始变量本身。

在 CommonJS 模块化规范中,当使用 exports 导出一个对象或值时,它实际上是将该对象或值的一个引用赋值给 exports 对象,而不是将该对象或值本身赋值给 exports 对象。

因此,在上面的示例代码中,当我们导入 a.js 模块时,它实际上返回的是一个包含 name 和 age 属性的对象,以及一个 setAge 方法的对象。这些属性和方法都是指向 a.js 模块内部定义的变量和函数的引用。

当我们调用 a.setAge(19) 时,它实际上是在修改 age 变量的值。但是,由于 exports.age 和 a.age 实际上是指向 a.js 模块内部的 age 变量的引用,而不是直接指向 age 变量本身,因此这两个变量的值不会被修改。因此,我们在调用 console.log(a.age) 时仍然会输出 18。

简而言之,虽然在模块内部可以修改导出的对象或值,但由于 exports 对象和其他导入该模块的对象实际上只是对内部变量或函数的引用,所以这些对象或值本身的属性和值是不会被修改的。