-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Day13 - 如何用闭包完成模块化(Webpack原理) #57
Comments
模块化最重要的有两点,1不能污染全局, 2.需要各自独立的作用域,互不干扰 |
模块化具备两个必要条件:
模块化的目的在于将一个程序按照其功能做拆分,分成相互独立的模块,以便于每个模块只包含与其功能相关的内容,模块之间通过接口调用。 |
|
如果想在所有的地方都能访问同一个变量,并且不使用全局变量,那么就可以使用模块化思维
|
回答(webpack 方向)
|
webpack整体是一个自执行的函数,利用了闭包的特性,保证了内部变量私有化, 同时也不会对全局变量造成污染。 ;(function (modules) {
// 01 定义对象用于将来缓存被加载过的对象
let installedModules = {}
// 02 定义一个 __webpack_require__ 方法替换 import require 加载操作
function __webpack_require__(moduleId) {
// 2-1 判断当前缓存中是否存在要被加载的模块内容,如果存在直接返回
if (installedModules[moduleId]) {
return installedModules[moduleId].exports
}
// 2-2 如果当前缓存中不存在则需要我们自己定义{} 执行被导入的模块内容加载
let module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
})
// 2-3 调用当前 moduleId 对应的函数,然后完成内容的加载
modules[moduleId].call(
modules.exports,
module,
module.exports,
__webpack_require__
)
// 2-4 当上述方法调用完成后,我们就可以修改 l 的值用于表示当前模块内容已经加载完成了
module.l = true
// 2-5 加载工作完成之后,要将拿回来的内容返回至调用的地方
return module.exports
}
// 03 定义 m 属性 用于保存 modules
__webpack_require__.m = modules
// 04 定义 c 属性用于保存 cache
__webpack_require__.c = installedModules
// 05 定义 o 方法用于判断对象上是否存在指定的属性
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty(object, property)
}
// 06 定义 d 方法用于在对象的身上添加指定的属性,同时给该属性提供一个 getter
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter })
}
}
// 07 定义 r 方法用于标识当前模块是 es6 类型
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
}
Object.defineProperty(exports, '__esModule', { value: true })
}
// 08 定义 n 方法用于设置具体的 getter
__webpack_require__.n = function (module) {
let getter =
module && module.__esModule
? function getDefault() {
return module['default']
}
: function getModuleExports() {
return module
}
__webpack_require__.d(getter, 'a', getter)
return getter
}
// 11 定义 t 方法,用于加载指定 value 的模块内容,之后对内容进行处理再返回
__webpack_require__.t = function (value, mode) {
// 01 加载 value 对应的模块内容 ( value 一般就是模块 id)
// 加载之后的内容又重新赋值给value变量
if (mode & 1) {
value = __webpack_require__(value)
}
if (mode & 8) {
// 加载了可以直接返回使用的内容
return value
}
if (mode & 4 && typeof value === 'object' && value && value.__esModule) {
return value
}
// 如果 8 和 4 都没有成立则需要自定义 ns 来通过 default 属性返回内容
let ns = Object.create(null)
__webpack_require__.r(ns)
Object.defineProperty(ns, 'default', { enumerable: true, value: value })
if (mode & 2 && typeof value !== 'string') {
for (var key in value) {
__webpack_require__.d(
ns,
key,
function (key) {
return value[key]
}.bind(null, key)
)
}
}
}
// 09 定义 p 属性,用于保存资源访问路径
__webpack_require__.p = ''
// 10 调用 __webpack_require__ 方法执行模块导入与加载操作
return __webpack_require__((__webpack_require__.s = './src/index.js'))
})({
'./src/c.js': function (module, __webpack_exports__, __webpack_require__) {
'use strict'
__webpack_require__.r(__webpack_exports__)
__webpack_require__.d(__webpack_exports__, 'age', function () {
return age
})
__webpack_exports__['default'] = 'aaaaaa'
const age = 90
},
'./src/index.js': function (
module,
__webpack_exports__,
__webpack_require__
) {
'use strict'
__webpack_require__.r(__webpack_exports__)
var _c_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
/*! ./c.js */ './src/c.js'
)
console.log('index.js')
console.log(
_c_js__WEBPACK_IMPORTED_MODULE_0__['default'],
'----',
_c_js__WEBPACK_IMPORTED_MODULE_0__['age']
)
}
}) 具体流程,当有模块数组作为参数传入立即执行函数时
|
模块化,就是能够实现某一功能的代码,封装成一个函数,只暴露出一个接口来供外部函数调用;被封装好的各模块之间的作用域互不冲突;我们可以通过闭包来实现模块的封装 |
必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。 |
主要的思路是创建一个临时的函数作用域,会在初始化执行完后销毁,不污染全局作用域。
|
模块化封装的过程中使用了闭包。示例代码如下:
模块化具备两个必要条件:
|
模块化就是对某种特定功能的封装,然后在主模块中引入各个模块,从而组建成完整的体系。 |
模块化通过自执行函数和闭包形成。目的是为了每个模块互相独立,不污染全局作用域。 |
库文件首先要保证不能污染全局 打包后最基础版本就是下面这样 (function (modules) {/* 省略函数内容 */})
([
function (module, exports, __webpack_require__) {
/* 模块index.js的代码 */
},
function (module, exports, __webpack_require__) {
/* 模块bar.js的代码 */
}
]); 可以看到,整个打包生成的代码是一个IIFE(立即执行函数) webpack也控制了模块的module、exports和require // 1、模块缓存对象
var installedModules = {};
// 2、webpack实现的require
function __webpack_require__(moduleId) {
// 3、判断是否已缓存模块
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 4、缓存模块
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// 5、调用模块函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 6、标记模块为已加载
module.l = true;
// 7、返回module.exports
return module.exports;
}
// 8、require第一个模块
return __webpack_require__(__webpack_require__.s = 0); 模块数组作为参数传入IIFE函数后,IIFE做了一些初始化工作:
require入口模块时,入口模块会收到收到三个参数 function(module, exports, __webpack_require__) {
"use strict";
var bar = __webpack_require__(1);
bar.bar();
} webpack传入的第一个参数module是当前缓存的模块,包含当前模块的信息和exports;第二个参数exports是module.exports的引用,这也符合commonjs的规范;第三个__webpack_require__ 则是require的实现。 在我们的模块中,就可以对外使用module.exports或exports进行导出,使用__webpack_require__导入需要的模块,代码跟commonjs完全一样。 这样,就完成了对第一个模块的require,然后第一个模块会根据自己对其他模块的require,依次加载其他模块,最终形成一个依赖网状结构。webpack管理着这些模块的缓存,如果一个模块被require多次,那么只会有一次加载过程,而返回的是缓存的内容,这也是commonjs的规范。 原理还是很简单的,其实就是实现exports和require,然后自动加载入口模块,控制缓存模块 |
必须有外部的封闭自调函数函数iife |
模块化原理构建一个自执行的函数,这里就利用了闭包的特性,保证了内部变量私有化, 同时也不会对全局变量造成污染。 |
webpack中是如何使用闭包完成模块化呢?
|
webpack如何利用闭包完成模块化
function bundle(graph) {
let modules = "";
// 源代码需要export require module
graph.forEach((module) => {
module += `${module.id}: [
function(require, module, exports) {
${module.code}
},
${JSON.stringify(module.mapping)},
]`;
});
const result = `
(function(modules) {
funciton require(id) {
const [fn, mapping] = modules[id]
function localRequire(relativePath) {
return require(mapping[relativePath])
}
const module = { exports: {} }
fn(localRequire, module, module.exports)
return module.exports
}
require(0)
})({${modules}})
`;
return result;
} |
webpack如何利用闭包完成模块化?
|
webpack原理是将不同的模块打包成不同的集合 |
webpack模块化其实是通过自执行函数启动,其中的模块文件也是一个个的自执行函数,利用闭包的特性,将各模块的变量和方法与外部隔离开,并自定义exports 和require 方法,将内部的方法或变量导出并记录映射关系,在外部就可以通过一定的id去获取对应的方法或变量 |
如何用闭包完成模块化 |
The text was updated successfully, but these errors were encountered: