browserify 的源码解析

(function e(t, n, r) {
    function s(o, u) {
        if (!n[o]) {
            if (!t[o]) {
                var a = typeof require == "function" && require;
                if (!u && a) return a(o, !0);
                if (i) return i(o, !0);
                var f = new Error("Cannot find module '" + o + "'");
                throw f.code = "MODULE_NOT_FOUND",
                f
            }
            var l = n[o] = {
                exports: {}
            };
            t[o][0].call(l.exports,
            function(e) {
                var n = t[o][1][e];
                return s(n ? n: e)
            },
            l, l.exports, e, t, n, r)
        }
        return n[o].exports
    }
    var i = typeof require == "function" && require;
    for (var o = 0; o < r.length; o++) s(r[o]);
    return s
})({
    1 : [function(require, module, exports) {
        module.exports = function() {
            return 'test';
        }
    },
    {}]
},
{},
[1]);



其实很多时候,觉得代码很晦涩难懂,个人觉得很大一部分原因是:

  1. 因为变量名用了一大堆a,b,c,d,看得头昏脑涨,晕头转向。
  2. 用了(function(){})()这类匿名函数写法。
  3. 用了一堆call apply等改变this的方法。

那么我们不妨逐步将代码改造成我们(好吧,也许只是我)比较好阅读的写法。

去除匿名函数

var t = {
    1: [function (require, module, exports) {
        exports.a = function () {
            return b.b();
        }
    }, {}]
}, n = {}, r = [1];

function e(t, n, r) {
    function s(o, u) {
        if (!n[o]) {
            if (!t[o]) {
                var a = typeof require == "function" && require;
                if (!u && a)return a(o, !0);
                if (i)return i(o, !0);
                var f = new Error("Cannot find module '" + o + "'");
                throw f.code = "MODULE_NOT_FOUND", f
            }
            var l = n[o] = {exports: {}};
            t[o][0].call(l.exports, function (e) {
                var n = t[o][1][e];
                return s(n ? n : e)
            }, l, l.exports, e, t, n, r)
        }
        return n[o].exports
    }

    var i = typeof require == "function" && require;
    for (var o = 0; o < r.length; o++)s(r[o]);
    return s
}

e(t, n, r);

这一步后,抛开function s(o, u)先,其实代码几乎可以认为简化成了

var t, n, r;

function e(t, n, r){
	function s(o, u){}
	
	for (var o = 0; o < r.length; o++){
		s(r[o]);
	}
	return s;
}

e(t, n, r);

到了这一步,代码结构已经变得非常清晰,for循环里执行s方法而已。
我们代入变量值,详细分析下function s

代入变量值

var r = [1];
for (var o = 0; o < r.length; o++){
	s(r[o]);
}

在这个例子里,这段代码就相当于执行s(1);而已。
就是这么easy~
再来看function s

var o = 1;
var n = {};
var t = {
    1: [function (require, module, exports) {
        exports.a = function () {
            return b.b();
        }
    }, {}]
};

s(1);
 
function s(o, u) { // o=1, 根本没有传入u这个参数,u=undefined
    if (!n[o]) { //n={}, n[1] = undefined; !n[1]=true
        if (!t[o]) { // !t[1] = true,这段if代码不会执行,跳过 
            var a = typeof require == "function" && require;
            if (!u && a)return a(o, !0);
            if (i)return i(o, !0);
            var f = new Error("Cannot find module '" + o + "'");
            throw f.code = "MODULE_NOT_FOUND", f
        }
        var l = n[o] = {exports: {}};
        t[o][0].call(l.exports, function (e) {
            var n = t[o][1][e];
            return s(n ? n : e)
        }, l, l.exports, e, t, n, r)
    }
    return n[o].exports
}

于是,我们可以先把无关的一大段if代码删掉吧,好看点。

function s(o, u) {
    if (true) {
        
        var l = n[o] = {exports: {}};
        t[o][0].call(l.exports, function (e) {
            var n = t[o][1][e];
            return s(n ? n : e)
        }, l, l.exports, e, t, n, r)
    }
    return n[o].exports
}

到了现在,代码唯一的难点,就是call的用法了。

call的用法

function Man(name){
	this.name = name;
	this.fav = 'charming lady';
	this.love = function(){
		console.log(this.name, 'love', this.fav);
	}
}

var jinceon = new Man('jinceon');
jinceon.love(); //jinceon love charming lady

var love = jinceon.love;
love.call(jinceon); //jinceon love charming lady

//可以看到 jinceon.love() 和 love.call(jinceon) 是等价的

var xiaoMing = {name:'小明', fav:'handsome man'};
love.call(xiaoMing); //小明 love handsom man

一句话,call 可以改变this的指向。关于call和apply以及bind,请网上搜索自行学习。
我们先把call关键字替换掉吧。

xiaoMing.love();//xiaoMing的确没有love这个方法,但请不要在意这些细节

或者写出这样,你会开心点?

love();  //this->xiaoMing

再次回到正文,看这段代码,继续代入变量

function s(o, u) {
    var l = n[o] = {exports: {}};
    t[o][0].call(l.exports, function (e) {
        var n = t[o][1][e];
        return s(n ? n : e)
    }, l, l.exports, e, t, n, r)
    return n[o].exports
}
//变成下面这样
var o = 1;
var yourModule = t[o][0] = function (require, module, exports) {
        exports.a = function () {
            return b.b();
        }
    }
    
var r = function (e) {
        var n = t[o][1][e];
        return s(n ? n : e)
    }
    
function s(o, u) {
    var l = n[o] = {exports: {}};
    yourModule.call(l.exports, r, l, l.exports, e, t, n, r)
    return n[o].exports
}

//实际上yourModule只用到了3个形参,我们把传入的其他参数先无视

function s(o, u) {
    var l = n[o] = {exports: {}};
    yourModule.call(l.exports, r, l, l.exports)
    //yourModule(r, l, l.exports); //this->l.exports
    return n[o].exports
}

//替换掉call

function s(o, u) {
	function yourModule(require, module, exports) {
        exports.a = function () {
            return b.b();
        }
    }

    var l = {exports: {}};
    yourModule(r, l, l.exports); //this->l.exports
    return n[o].exports
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值