资讯专栏INFORMATION COLUMN

前端Tank技能---模块化加载器的简单实现

ShevaKuilin / 2557人阅读

摘要:抛开一直写的那个不讲,我们说的是一个简单的模块加载器的简单实现。非常好实现,忽略不提。是第一个冒出来的,但是,一般提到他都会是弃用的,会有安全的漏洞更好的方案是构造器。

什么是模块化,为什么要模块化

装个b,贴一段English

A beginning programmer writes her programs like an ant builds her hill, one piece at a time, without thought for the bigger structure. Her programs will be like loose sand. They may stand for a while, but growing too big they fall apart.

Realizing this problem, the programmer will start to spend a lot of time thinking about structure. Her programs will be rigidly structured, like rock sculptures. They are solid, but when they must change, violence must be done to them.

The master programmer knows when to apply structure and when to leave things in their simple form. Her programs are like clay, solid yet malleable.

Master Yuan-Ma, The Book of Programming

以上基本上是为什么要模块化的,至于什么是模块化有好多好多种。

比如这样:

function dujia1(){
    //..
}

function dujia2(){
    //...
}

这样简单的放在一起也是模块化,只不过太挫,有些人不承认而已。

再比如这样

var page = {
    init: function(){
        //..
    },
    getData:function(){
        //..    
    },
    bindEvent:function(){
        //...
    },
    __secret:”我不想让让人知道"
}

这个就是我们比价常用的了。所有page相关的功能都作为属性包在page这个模块里面,基本上对全局没有污染。但是也没有保留,也就是对外部来说,所有的东西都是可以看到的。
比如访问 page.__secret 你能获取这个秘密,这样的包装方式是包不住的。

再比如这样:

var page = (function(){
    
    var  __secret = ”我不想让让人知道”;

    var init = function(){
        //..
    };
    var getData = function(){
        //..    
    };
    var bindEvent = function(){
        //...
    };

    return {
        init : init
    }    
})();

这样呢外吐的只有init了。是吧,其他都包住了。

再比如一下这个样子:

var page = (function(mod){
    mod.xxx=yyy;
    return mod
})(module);

好,这样就可以扩展module了。

其实以上都不是本篇的重点,本篇的重点是模块加载工具的简单实现。

模块加载器

以上大家都看到了,要实现模块化,我们要设计,要知道怎么搞好,然后呢用这个方法去实现,啪啪啪写好多代码去实现。

那么换个思路想想,我们为什么不在打包过程中编译过程中或者加载过程中由程序去做这个事情呢。对,fekit是这样实现,好多好多都是这样实现的,实现这样功能的东西就是模块加载器。

先说说,我们已经写的次数和名字差不多的 require是怎么实现的。

抛开一直写的那个require不讲,我们说的是一个简单的模块加载器的简单实现。

定义一下:这个加载器,可以通过require一个文件的方式,把里面的内容添加到require的文件中,并能够执行他。也就是通过传入模块名来取得该模块的调用。

实现一个readFile方法,返回对应文件的内容;

将返回的字符串作为代码进行执行。

readFile非常好实现,忽略不提。

然后就是把字符串转成可以执行的程序代码。eval是第一个冒出来的,但是,一般提到他都会是弃用的,会有安全的漏洞

更好的方案是Function构造器。

var plus = new Function("name", "return name + ‘ bigger"");
console.log(plus("Iphone6")); //Iphone6 bigger

两个参数,第一个是用逗号分隔的参数列表字符串,第二个是函数体字符串

有了这个我们就可以来实现require方法了

//module.js

function require(name){

    //调用一个模块,首先检查这个模块是否已经调用
    if(name in require.cache){
        return require.cache[name];
    }

        //此处生成一个code的函数,参数为  exports 和 module, 函数体为readFile返回的js文件中的代码字符串
    var code = new Function("exports, module", readFile(name));
        
        //定义外吐内容
    var exports = {},
        module = {exports: exports};
        
        //执行函数体,如果有定义外吐,既module.exports 或者  exports.***之类的,会改写上面的外吐内容
    code(exports, module);

    require.cache[name] = module.exports;

        //返回exports
    return module.exports;
}

//缓存对象,为了应对重复调用
require.cache = Object.create(null);

//读文件,返回结果
function readFile(fileName){ ... }

这就是一个简单的CommonJS模块风格的加载方式,也是node和fekit现在使用的加载方式。

实现demo

亲测,不加demo很有可能看不懂

有一个文件 aaa.js,内容如下

function (){
    console.log("this is aaa");
}
exports.aaa = "aaa";

这是var aaa = require("aaa.js")会做以下事情

readFile("aaa.js") 以字符串形式返回aaa的所有函数体,也就是上面的哪些部分代码
通过new Function构造器,创造一个code函数,函数体是aaa.js里面的内容
执行code函数,log出结果,然后扩展了module.exports
返回这个module.exports 改外面的变量 aaa

再思考

我们在吐js模块的时候经常使用的方案是这样两种
# module.exports = a object;
# exports.aaa = function();

如果我们直接写 exports = a object 会怎么样,为什么?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79657.html

相关文章

  • 前端Tank技能---页面load事件分析

    摘要:事件详细研究边界事件外链样式在某些浏览器下面会影响脚本的加载。事件和事件是同时的。这就是要监听页面的事件,当事件为时就可以开始做的事情了。 页面加载状态 $(document).ready() $(function(){}) 这两个是我们在页面初始化时经常使用的监听方案,那么他的实际的执行关系时什么样的呢?在原生js中是什么样的一种表现? 以下我会一而再再而三的写DOMConten...

    silencezwm 评论0 收藏0
  • 前端Tank技能---页面load事件分析

    摘要:事件详细研究边界事件外链样式在某些浏览器下面会影响脚本的加载。事件和事件是同时的。这就是要监听页面的事件,当事件为时就可以开始做的事情了。 页面加载状态 $(document).ready() $(function(){}) 这两个是我们在页面初始化时经常使用的监听方案,那么他的实际的执行关系时什么样的呢?在原生js中是什么样的一种表现? 以下我会一而再再而三的写DOMConten...

    lpjustdoit 评论0 收藏0
  • 前端Tank技能---浏览器嗅探

    摘要:由于那个时候是霸主,这也导致微软推出的时候必须把自己伪装成浏览器,于是他们的也是以开头的。各个版本典型的如下其中之后的就是当前的版本号。的几个版本的其中之后的是版本号提供了专门的浏览器标志,就是属性。目前,的是其中,版本号在之后的数字。 浏览器嗅探 浏览器嗅探不用说了,为了更好的性能,会需要各种各样的兼容性处理,自然就会有针对不同浏览器的判断.一般的代码中,我们都是通过navigato...

    Blackjun 评论0 收藏0
  • 前端相关大杂烩

    摘要:希望帮助更多的前端爱好者学习。前端开发者指南作者科迪林黎,由前端大师倾情赞助。翻译最佳实践译者张捷沪江前端开发工程师当你问起有关与时,老司机们首先就会告诉你其实是个没有网络请求功能的库。 前端基础面试题(JS部分) 前端基础面试题(JS部分) 学习 React.js 比你想象的要简单 原文地址:Learning React.js is easier than you think 原文作...

    fuyi501 评论0 收藏0
  • 设计模式之工厂模式

    摘要:缺点需要慎重考虑是否增加工厂类进行管理,因为会增加代码的复杂度使用场景工厂模式是创建型模式的一种,其实就等价于对象,但是否将对象改造成工厂模式,使我们需要衡量的。 前言 最近北京天气越来越冷了,同在北京的小伙伴大家注意保暖。不扯废话了,让我们直接进入到工厂模式的学习. 什么是工厂模式 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。 UML类图...

    huangjinnan 评论0 收藏0

发表评论

0条评论

ShevaKuilin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<