CommonJS模块规范

CommonJS 是为在网页浏览器之外的JavaScript提供模块化规范的项目。在模块化出现之前,前端引用其他的js文件资源都是通过<script>标签的方式,这种方式有很多的弊端,例如必须有一个html文档,而 Node.js 根本没有html文档;需要根据资源之间的依赖关系衡量引用资源的先后顺序;资源之间要共享变量必须定义为全局变量,造成全局变量污染严重。

随着JavaScript的应用场景越来越广,项目代码越来越多,模块化的需求也就越来越大。闭包是早期实现模块化的一个方式。例如下面代码,

javascript 复制代码
// 闭包
aModule = (function (){
    const hobby = '滑雪'
    return {
        getHobby(){
            return `爱好:${hobby}`
        }
    }
})()

bModule = (function (){
    console.log(aModule.getHobby())
    const lunch = '汉堡包'
    return {
        getLunch() {
            return `午餐:${lunch}`
        }
    }
})()`	

模块内部可以维护自己的私有变量,但是又可以对外暴露接口供其他模块使用。缺点是模块的创建时机依赖于代码执行顺序,aModule 无法调用 bModule 里面的方法
CommonJS 模块化规范可以很好的解决全局变量污染问题以及更适用于资源相互依赖的场景。Node.js 应用 CommonJS 模块规范,将CommonJS 模块规范推而广之。
CommonJS 模块规范要点

① 每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

② 每个模块内部有两个变量可以使用,requiremodule

require 用来加载某个模块;module 代表当前模块,是一个对象,保存了当前模块的信息。

exportsmodule 上的一个属性,保存了当前模块要导出的接口或者变量,使用 require 加载的某个模块获取到的值就是那个模块使用 exports 导出的值,如果不设置就是一个空对象。在模块中可以通过给 exports 变量赋值来给模块挂载属性
a.js

javascript 复制代码
exports.name='张三'
exports.age=18

b.js

javascript 复制代码
const a = require('./a')
console.log(a)

输出:

⑤ 另一种给 exports 赋值的方式如下,会直接丢弃之前所有的属性

javascript 复制代码
exports.name = '张三'
exports.age = 18
module.exports = {
    address:'北京市'
}

输出:

webpack 可以将CommonJS模块的代码转换为浏览器支持的代码,所以我们看一下webpack是怎么转换的。

npm init -y 创建项目

② 安装依赖

webpack 的最新版本对于命令会有更强的校验,我觉得不方便,所以安装的是@4
cnpm install webpack@4 webpack-cli@4 --save-dev

③ 在 package.json 中设置启动命令 "dev": "webpack --devtool none --mode development"

④ 在a.jsb.js 中随便导出一些东西,并且在 index.js 中使用 require 引入
index.js

javascript 复制代码
require('./a.js')
require('./b.js')
console.log('index.js')

⑤ 运行 npm run dev,查看 webpack打包结果,大致结构如下

javascript 复制代码
(function (modules) {
  var installedModules = {}
  function __webpack_require__(moduleId) {
      // moduleId 就是文件名
      if (installedModules[moduleId]) {
          return installedModules[moduleId].exports;
      }
      // Create a new module (and put it into the cache)
      var module = installedModules[moduleId] = {
          i: moduleId,
          l: false,
          exports: {}
      };
      
      modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

      return module.exports;
  }

  return __webpack_require__(__webpack_require__.s = 0);
})({
    "./src/a.js":
        (function (module, exports) {
            exports.name = '张三'
            exports.age = 18
            // 相当于重新给变量指向了一个新的引用地址,所以之前挂载的属性会消失
            module.exports = {
                address: '北京市'
            }
        }),
    "./src/b.js":
        (function (module, exports) {

            exports.address = '北京市'
        }),

    "./src/index.js":
        (function (module, exports, __webpack_require__) {
            __webpack_require__("./src/a.js")
            __webpack_require__("./src/b.js")
            console.log('index.js')
        }),
    0: (function (module, exports, __webpack_require__) {
        module.exports = __webpack_require__("./src/index.js");
    })
});

文件名和模块内容会以键值对的形式存储在一个对象里面,每个模块中的代码都被放在一个函数里面,以形成独立的作用域

call() 方法和 apply()

call() 方法和 apply() 方法是 JavaScript 中用于调用函数的两种方式。它们的主要区别在于参数的传递方式。

call() 方法是函数对象的一个方法,通过该方法可以调用一个函数,并将指定的对象作为函数的上下文(也称为 this 值)来执行函数。call()方法接受的参数是一个对象和一系列的参数。第一个参数是要设置为函数上下文的对象,后面的参数是传递给函数的参数。

示例使用 call() 方法调用函数:

javascript 复制代码
function greet(name) {
  console.log('Hello, ' + name);
}

greet.call(null, 'John'); // 输出: Hello, John

在上面的示例中,call() 方法将 null 作为函数 greet 的上下文对象,并将字符串 'John' 作为参数传递给函数。

apply() 方法也是函数对象的一个方法,它与 call() 方法类似,用于调用一个函数并设置函数的上下文。不同之处在于它接受的参数是一个对象和一个数组,其中数组中的元素将作为参数传递给函数。

示例使用 apply() 方法调用函数:

javascript 复制代码
function greet(name) {
  console.log('Hello, ' + name);
}

greet.apply(null, ['John']); // 输出: Hello, John

在上面的示例中,apply() 方法将 null 作为函数 greet 的上下文对象,并将包含字符串 'John' 的数组作为参数传递给函数。

总结:

call() 方法使用一系列的参数来调用函数,并设置函数的上下文对象。
apply() 方法使用一个数组来调用函数,并设置函数的上下文对象。

两者的作用是相同的,只是传递参数的方式不同。你可以根据具体的需求选择使用哪种方法。

相关推荐
Qrun19 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp19 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.20 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl1 天前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫1 天前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友1 天前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理1 天前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻1 天前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
cdming1 天前
Node.js 解释环境变量的定义、作用及在Node.js中的重要性,区分开发、测试、生产环境配置需求。
node.js
mapbar_front1 天前
在职场生存中如何做个不好惹的人
前端