kmdjs和循环依赖

循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚。所以没解决好循环依赖的模块化库、框架、编译器都不是一个好库、框架、编译器。

kmdjs的本质就是{},从{}扩展出的tree。从很早的版本就开始,是支持循环依赖的。比如下面的代码:

define('namespace1.A',['namespace2'], {
ctor: function () {
this.b = new B();
}
}) define('namespace2.B',['namespace1'] , {
ctor: function () { },
xx: function () {
var a = new A();
}
})

会被kmdjs编译成:

var namespace1 = {};
var namespace2 = {}; namespace1.A = Class.extend({
ctor: function () {
this.b = new namespace2.B();
}
}) namespace2.B = Class.extend({
ctor: function () { },
xx: function () {
var a = new namespace1.A();
}
})

要支持循环依赖其实有个要求,就是lazy using不是lazy using的循环依赖是无解的循环依赖
怎么理解上面这句话呢?看上面的代码,Class.extend执行完之后,各自依赖的东西是不会被调用的。
A代码里的new namespace2.B()要在new namespace1.A的时候才会被调用。
B代码里的new namespace1.A()要var a = new namespace1.A;a.xx()之后被调用后才会被执行。
所以在初始化阶段,这样的循环依赖是被允许的,因为都是lazy using。只要满足lazy using,执行顺序就不重要了,如果不是lazy using(如静态属性方法的设置),执行顺序就必须把依赖的项先执行。
如上面所说,不是所有的循环依赖都能够解决的,比如看C#里面的无解的循环依赖的例子:

namespace Project1
{
public class A
{
public static B b = new B();
}
} namespace Project1
{
public class B
{
public static A a = new A();
}
}

上面的代码编译时候就会报错。怎么改成有解,那么就要lazy using:

namespace Project1
{
public class A
{
public static B b = new B();
}
} namespace Project1
{
public class B
{
public int testMethod()
{
A a = new A();
return 1;
}
}
}

这样的依赖编译器是可以解决的。

kmdjs 0.1.4

kmd的意思是 kernel module definition。该版本和以前的主要变化如下:

  1. kmdjs文件大小从以前的一万多行代码变成了一百多行代码
  2. 从以前的namespace+class组织项目变成namespace+module组织项目

kmdjs API

kmdjs.config
用于配置 namespace + module和文件路径的mapping

kmdjs.config({
'util.bom':'js/util/bom.js',
'app.Ball':'js/ball.js',
'util.dom':'js/util/dom.js',
'util.dom.test':'js/util/test.js',
'main': 'js/main.js'
});

kmdjs.main
程序的入口代码。
kmdjs.define
定义模块

kmdjs.define('main',['util.bom','app.Ball','util.dom.test'], function(bom,Ball,test) {

    var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
alert(test.m(3, 3));
var vp = bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); });

如果只传两个参数,代表不依赖任何模块。这里和AMD一样,在factory的回调里把依赖注入到里面。
但是也直接在代码里把namespace写进去访问,如下所示:

kmdjs.define('main',['util.bom','app.Ball'], function() {

    var ball = new app.Ball(0, 0, 28, 1, -2, 'kmdjs');
var vp = util.bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); });

而有的时候必须使用上面这种方式用来解决循环依赖导致执行顺序问题带来的注入undefined:如:

kmdjs.define("util.dom",['util.bom'] ,function(bom){
var Dom={}; Dom.add = function(a,b){
//循环依赖导致的bom undefined,所以这里写上namespace
return util.bom.sub(a,b);
} return Dom;
});

kmdjs.define("util.bom",["util.dom"], function(dom){
var Bom={}; Bom.getViewport=function() {
alert(dom.add(1,4)); }; Bom.sub = function(a,b){
return a-b;
};
return Bom;
});

bundler

可以通过main传入回调函数,在回调函数中拿到编辑打包好的字符串。

kmdjs.main(function(bundler){
alert(bundler)
});

如上面的例子打包出来的代码:

var util={};
var app={};
util.dom={};
var main={}; util.dom = (function (bom){
var Dom={}; Dom.add = function(a,b){
return util.bom.sub(a,b);
} return Dom;
})(util.bom); app.Ball = (function (){
var Ball = function (x, y, r, vx, vy, text) {
this.x = x;
this.y = y;
this.r = r;
this.d = 2 * r;
this.vx = vx;
this.vy = vy;
this.element = document.createElement("div");
this.element.innerHTML = text; this.element.style.cssText = "text-align:center;position:absolute; -moz-border-radius:" + this.d + "px; border-radius: " + this.d + "px; width: " + this.d + "px; height: " + this.d + "px;line-height:" + this.d + "px;color:white;";
document.body.appendChild(this.element); }; Ball.prototype.tick= function () {
this.x += this.vx;
this.y += this.vy;
this.element.style.left = this.x + "px";
this.element.style.top = this.y + "px";
}; return Ball;
})(); util.dom.test = (function (){
var Element={}; Element.m = function(a,b){
return a*b;
} return Element;
})(); util.bom = (function (dom){
var Bom={}; Bom.getViewport=function() {
alert(dom.add(1,4));
var d = document.documentElement, b = document.body, w = window, div = document.createElement("div");
div.innerHTML = " <div></div>";
var lt = !(div.firstChild.nodeType === 3) ?
{ left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :
{ left: w.pageXOffset, top: w.pageYOffset };
var wh = w.innerWidth ?
{ width: w.innerWidth, height: w.innerHeight } :
(d && d.clientWidth && d.clientWidth != 0 ?
{ width: d.clientWidth, height: d.clientHeight } :
{ width: b.clientWidth, height: b.clientHeight }); return [lt.left, lt.top, wh.width, wh.height]
}; Bom.sub = function(a,b){
return a-b;
};
return Bom;
})(util.dom); main = (function (bom,Ball,test) { var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
alert(test.m(3, 3));
var vp = bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); })(util.bom,app.Ball,util.dom.test);

Github

https://github.com/kmdjs/kmdjs

 
好文要顶 关注我 收藏该文

js和循环依赖的更多相关文章

  1. Node.js的循环依赖

    我们知道在实际编程过程中,要尽可能的减少或者规避循环依赖情况的发生.但在现实环境中,有时却不得不产生循环依赖.Node.js不提倡使用循环依赖,但真有如此情况发生时Node.js也有办法解决.这篇博文 ...

  2. Node.js之循环依赖

    在Node.js中有可能会出现循环依赖的问题,在此做一个简单的记录 假如有一个模块A: exports.loaded = false; const b = require('./b'); module ...

  3. kmdjs和循环依赖

    循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚.所以没解决好循环依赖的模块化库.框架.编译器都不是一个好 ...

  4. seaJS循环依赖的解决原理

    seajs模块的六个状态. var STATUS = {  'FETCHING': 1, // The module file is fetching now. 模块正在下载中  'FETCHED': ...

  5. RequireJS模块化之循环依赖

    如果你定义一个循环依赖关系 (a 依赖b 并且 b 依赖 a),那么当b的模块构造函数被调用的时候,传递给他的a会是undefined. 但是b可以在a模块在被引入之后通过require(‘a’)来获 ...

  6. 3.4 spring5源码系列--循环依赖的设计思想

    前面已经写了关于三篇循环依赖的文章, 这是一个总结篇 第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 第二篇: 3.2spring源码系列----循环依赖源 ...

  7. spring3 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

  8. 在.NET Core中遭遇循环依赖问题"A circular dependency was detected"

    今天在将一个项目迁移至ASP.NET Core的过程中遭遇一个循环依赖问题,错误信息如下: A circular dependency was detected for the service of ...

  9. Atitit js中的依赖注入di ioc的实现

    Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内  builder  即可..2 Service locator method走ok拦2 Jav ...

随机推荐

  1. REF CURSOR和CURSOR

    REF CURSOR DECLARE TYPE TY_EMP_CUR IS REF CURSOR; V_Emp_Cur TY_EMP_CUR; V_Id EMP.ID%TYPE; BEGIN OPEN ...

  2. GSAP学习笔记

    GSAP(Green Sock Animation Platform)是一个十分好用的js动画库,据说是as的精简版 以下是学习GSAP的一些笔记:貌似中文的文档不是很多 GSAP notes: tl ...

  3. PDF417码

    PDF417码是由留美华人王寅敬(音)博士发明的.PDF是取英文Portable Data File三个单词的首字母的缩写,意为“便携数据文件”.因为组成条码的每一符号字符都是由4个条和4个空构成,如 ...

  4. Qt布局与分割器QSplitter

    Qt的布局方式主要有四种:   QGridLayout         栅格布局 QFormLayout       表格布局 QHBoxLayout       水平布局 QVBoxLayout   ...

  5. 用macports装了一份openssl

    我已经用macports装了一份openssl,然后自己又编译了一份openssl....第三方给Mac出的一个类似BSD Ports的一个软件包管理工具装的话只需要sudo port install ...

  6. FLASH ROM与EEPROM的区别

    EEPROM,虽然也叫“非易失性数据存储器”,但它不能直接参与ALU运算,只是用于掉电不丢失的数据存储. EEPROM和片内RAM 类似,也属于数据存储器,它的特点是数据掉电可保持,而程序存储器一般指 ...

  7. SQLite取值时的下标与创建表中字段的关系

  8. HDU 4720 Naive and Silly Muggles (外切圆心)

    Naive and Silly Muggles Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...

  9. 关于PCA算法的一点学习总结

    本文出处:http://blog.csdn.net/xizhibei ============================= PCA,也就是PrincipalComponents Analysis ...

  10. css 基础(一)

    一.css样式表的分类 首先介绍一下css中的样式表  a.外部样式表  将需要的样式放在单独的外部文件中,需要使用是直接调用,通常放在.css文件中.例如:/*以下部分是放在(my.css)自定义名 ...