browserify 的原理是什么?
发布于 9 年前 作者 yakczh 6125 次浏览 最后一次编辑是 8 年前 来自 问答

比如 testmod.js

module.exports = function(){
  return 'test';
}

browserify testmod.js -o build/out.js 后是这样

B(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]);

格式化一下

(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 回复

新手,有错误请指正,勿喷。
其实很多时候,觉得代码很晦涩难懂,个人觉得很大一部分原因是:

  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
}
回到顶部