有人说js中有三座大三:this、原型链和scope tree,搞懂了他们就算是js成人礼。当然还有其他不同看法的js成人礼,如熟悉js的:OOP、AP、FP、DOP、AOP。当然还听说一种最牛B的js成人礼:熟悉jQuery……=   =!因为$里面可以放下全世界,比如$(“全世界”)…

这篇文章主要讲KMDjs利用Uglify2去分析出一个函数的所有依赖,之后才能正确地加载相关的js文件。该文涉及到js中三座大山中的scope tree….先看下面这段程序:

function test() {
var user = new User();
}

很显然,该函数依赖User。我一定要去加载User.js才能正确执行该函数。那么我是不是可以写一段非常牛B的正则找到new  和()之间的User。当然,这样一定是不对的,因为js里创建对象的实例可以省略括号,比如:

function test() {
var user = new User;
}

那么,是不是可以写一段非常牛B的正则,去查找new与分号之间的东西?相对于这个函数,是可以的!但是如果,这个函数长成这个样子:

function test(User) {
var user = new User;
}

可以看得到,该函数不依赖任何对象,User是test的参数传递进来…,那么我是不是可以写一段非常牛B的正则,先找到test(User)中的User参数,然后再通过正则找到new后面的所有对象,最后把第二次查找到的结果过滤掉第一次查找到的参数。好问题来了,如果程序长这样子:

function test(User) {
var xxx = "(User)";
var user = new User;
}

可能有人会说了,只能说明你的正则不牛B。牛B的正则是可以确认是字符串中的,还是非字符串中的。那么再看下一段程序:

function test() {
var User = function (name) {
this.name = name;
}
var u = new User();
}

可以看得出,User根本不是参数,而是直接在test内部定义!那么这个函数其实是不依赖User。那么,刚刚憋出的两段牛B的正则就彻底废掉了。再比如:

function test() {
var vp = Bom.getViewport();
}

可以看到,直接访问Bom的静态方法,都不需要new,就能访问Bom下的getViewport方法。所以,该函数依赖Bom。那么,刚刚憋出的两段牛B的正则再次彻底废掉了。再比如:

function test() {
var vp = new Array();
var el = document.getElementById("xx");
}

可以发现,window下的Array和document还需要过滤掉…,再比如

function test() {
var h = 1;
//这里 h a 都是可以找到,不能判定为赖
function a(e) {
//这里面h a e i b都是可以找到,不能判定为赖
var i = 2;
function b(f) {
//这里面h a e i b f c都是可以找到,不能判定为赖
function c(g) {
//这里面h a e i b f c g都是可以找到,不能判定为赖
}
}
}
}

如上面注释所描述,会有一串scope tree。那么…怎么办?uglify2有强大无比的ast.walk和UglifyJS.TreeWalker!如:

http://lisperator.net/blog/using-uglifyjs-for-code-refactoring/

这是官方重构代码的简单例子。受此文启发,我便为kmdjs写了个完美的依赖分析:

function getRef(fn) {
var U2 = UglifyJS;
var ast = U2.parse(fn.toString());
ast.figure_out_scope();
var result = [];
ast.walk(new U2.TreeWalker(function (node) {
if (node instanceof U2.AST_New) {
var ex = node.expression;
var name = ex.name;
if (!isInScopeChainVariables(ex.scope, name)) {
result.push(name);
}
}
if (node instanceof U2.AST_Dot) {
var ex = node.expression;
var name = ex.name;
if (!isInScopeChainVariables(ex.scope, name)) {
result.push(name);
}
}
}));
return result;
} function isInScopeChainVariables(scope, name) {
var vars = scope.variables._values;
if (Object.prototype.hasOwnProperty.call(vars, "$" + name)) {
return true;
}
if (scope.parent_scope) {
return isInScopeChainVariables(scope.parent_scope, name);
}
return false;
}

意外惊喜,在kmdjs加入lazy(kmdjs.get)之后,lazy内部的依赖不会加载!且看下面这段代码

function test(DDDDD) {
kmdjs.get("HelloKMD.Ball", function (Ball) {
//因为Ball是参数,属于该scope tree中的对象,所以不依赖
var ball = new Ball(100, 100, 28, 1, 2, "KMD.js"); });
}

完!

github:https://github.com/kmdjs/kmdjs

AMD and CMD are dead之KMDjs内核之依赖分析的更多相关文章

  1. AMD and CMD are dead之KMDjs内核之分号

    在老版本的kmdjs中,强制了分号的要求.但是总感觉不爽,因为在开发Ket - Kmdjs Extension Tools的时候,总需要导入一些开源的库,然后痛苦就来了,总是报错,一查,就是缺少分号! ...

  2. AMD and CMD are dead之KMDjs集成Blob一键下载全部build包

    更新 不zuo,[A/C]MD就不会死,所以kmdjs赢来来其伟大的版本0.0.6,该版本主要的更新有: 移除去了kmdjs.get(..).then的支持,只支持kmdjs.get(-,functi ...

  3. AMD and CMD are dead之KMDjs在JS工程化的努力

    总览 kmdjs发布了最接近最终版本的0.0.4版本https://github.com/kmdjs/kmdjs,你已经完全可以在项目中使用.我已经无法用语言形容其完美程度.借用我发的微博:   模块 ...

  4. AMD and CMD are dead之KMD规范

    What's KMD? 乱世出英雄,KMD名字的由来充满了杀气. Kill AMD and CMD KMD为替代混乱的AMD和CMD世界而生,一统天下.或者让这个混乱的世界更加混乱,导致: KMD A ...

  5. AMD and CMD are dead之KMD.js之懒

    缘由 "懒"在软件设计中,有着重大的意义.最常见的两种"懒",便是: 懒得计算 懒得加载 "懒得计算"常见于服务器端: 比如Multipla ...

  6. AMD and CMD are dead之KMD.js版本0.0.2发布

    更新 正式从UglifyJS切换至UglifyJS2 增加依赖可视化功能 压缩代码更加方便 统一风格:如main的class名也不能省略 优化了kmdjs管道 修复了无数bug 通过src开启debu ...

  7. AMD and CMD are dead之js模块化黑魔法

    var define, require, define2, require2; typeof JSON != "object" && (JSON = {}), fu ...

  8. AMD and CMD are dead之Why Namespace?

    缘由 当我看到_Franky兄的微博的时候: 我觉得我有必要出来详细说说KMDjs到底有什么本质上的优势了,连教主_Franky.貘吃馍香都不能理解他的好处,那么可想而知,在前端圈.或是全端圈.或是I ...

  9. AMD and CMD are dead之JS工程化终极解决方案KMD.js版本0.0.1发布

    回顾 经过两天晚上疯狂的开发调试,伴随着大量掉落的头发和酸痛的颈椎,KMD.js赢来了第一个稳定版本.在此期间KMD规范也有所修改和完善. 这两天主要完成的功能有: 按需加载 版本控制 模块管理 便捷 ...

随机推荐

  1. WCF学习之旅—WCF概述(四)

    一.WCF概述 1) 什么是WCF? Windows Communication Foundation (WCF) 是用于构建面向服务的应用程序的框架.借助 WCF,可以将数据作为异步消息从一个服务终 ...

  2. Xdebug+ZendStudio配置

    原文链接:http://www.orlion.ga/689/ 好久之前就知道有这么个东西,但是一直没用,一直用exit().var_dump() debug,效率很低. 首先下载xdebug的dll文 ...

  3. 如何在文章/随笔中添加可运行的js代码

    <script type="text/javascript"> alert("你知道我是怎么弹出的吗?"); </script> 看大神 ...

  4. 2012-09-10 23:30 如何解决HtmlAgilityPack得到的InnerText中有残留的script、样式的问题

    那么如何解决HtmlAgilityPack得到的InnerText中有残留的script.样式的问题呢,在google上搜索“HtmlAgilityPack script innerText”找到了s ...

  5. C#将一个excel工作表根据指定范围拆分为多个excel文件

    C#将一个excel工作表根据指定范围拆分为多个excel文件 微软Excel没有提供直接的方法来拆分excel文件,因此要拆分一个excel文件最简单的方法可能就是手动剪切和粘贴了,除此之外,还有其 ...

  6. ProgressBar

    <1>基本信息设置 progressBar1.Maximum = 1000;    //设置ProgressBar的最大值 progressBar1.Value = 0;         ...

  7. Message和handler传递对象

    Bundle可以传递对象,message又可以传递Bundle于是就可以利用buddle作为中间载体传递对象了 Message msg = Message.obtain();  Bundle b =  ...

  8. Linux(Centos)快速搭建SVN

    前言 项目中源码或者文档需要进行管理与版本记录,历数此类工具VSS.CVS.SVN.GIT等等,有非常多的版本控制系统.SVN现在还是很常见,把笔记总结搬上博客,SVN这个再不放以后估计只能写GIT的 ...

  9. 【十大经典数据挖掘算法】Apriori

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 关联分析 关联分析是一类非常有 ...

  10. Struts2 源码分析——Result类实例

    本章简言 上一章笔者讲到关于DefaultActionInvocation类执行action的相关知识.我们清楚的知道在执行action类实例之后会相关处理返回的结果.而这章笔者将对处理结果相关的内容 ...