js和循环依赖
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。该版本和以前的主要变化如下:
- kmdjs文件大小从以前的一万多行代码变成了一百多行代码
- 从以前的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
js和循环依赖的更多相关文章
- Node.js的循环依赖
我们知道在实际编程过程中,要尽可能的减少或者规避循环依赖情况的发生.但在现实环境中,有时却不得不产生循环依赖.Node.js不提倡使用循环依赖,但真有如此情况发生时Node.js也有办法解决.这篇博文 ...
- Node.js之循环依赖
在Node.js中有可能会出现循环依赖的问题,在此做一个简单的记录 假如有一个模块A: exports.loaded = false; const b = require('./b'); module ...
- kmdjs和循环依赖
循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚.所以没解决好循环依赖的模块化库.框架.编译器都不是一个好 ...
- seaJS循环依赖的解决原理
seajs模块的六个状态. var STATUS = { 'FETCHING': 1, // The module file is fetching now. 模块正在下载中 'FETCHED': ...
- RequireJS模块化之循环依赖
如果你定义一个循环依赖关系 (a 依赖b 并且 b 依赖 a),那么当b的模块构造函数被调用的时候,传递给他的a会是undefined. 但是b可以在a模块在被引入之后通过require(‘a’)来获 ...
- 3.4 spring5源码系列--循环依赖的设计思想
前面已经写了关于三篇循环依赖的文章, 这是一个总结篇 第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 第二篇: 3.2spring源码系列----循环依赖源 ...
- spring3 循环依赖
循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...
- 在.NET Core中遭遇循环依赖问题"A circular dependency was detected"
今天在将一个项目迁移至ASP.NET Core的过程中遭遇一个循环依赖问题,错误信息如下: A circular dependency was detected for the service of ...
- Atitit js中的依赖注入di ioc的实现
Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内 builder 即可..2 Service locator method走ok拦2 Jav ...
随机推荐
- QT 遍历目录查找指定文件(比较简单)
QString FindFile(const QString &strFilePath, const QString &strNameFilters){ if (strFilePath ...
- VS QT 配置OpenGL
在visual studio 下编译OpenGL代码出现以下错误,原因是vs没有自带opengl库,需要自己引入 无法解析的外部符号 __imp__glClear@4 无法解析的外部符号 __imp_ ...
- WPF:使用Json.NET在TreeView中树形显示JSON数据
原文 WPF:使用Json.NET在TreeView中树形显示JSON数据 据 读者可以参考这个开源的可以树形显示XML和JSON的工具: Mgen Object 603:XML/JSON树形显示小工 ...
- [WPF疑难]Hide me! not close
原文 [WPF疑难]Hide me! not close [WPF疑难]Hide me! not close 周银辉 有朋友遇到这样的一个问 ...
- Niagara技术文档汇总
Niagara技术文档汇总http://wenku.baidu.com/view/ccdd4e2c3169a4517723a38f.html Niagara讲解要点http://wenku.baidu ...
- [对话CTO]当当网熊长青:兴趣是成为优秀工程师的第一因素-CSDN.NET
Women Techmaker 北京站 [对话CTO]当当网熊长青:兴趣是成为优秀工程师的第一因素-CSDN.NET [对话CTO]当当网熊长青:兴趣是成为优秀工程师的第一因素 发表于2 ...
- Loadrunner 运行场景时:missing newline in XXX.dat 错误解决
脚本参数化类型为file,在controller里运行场景的时候,报了个missing newline的错误,查了一下,将参数化的dat文件中的最后一行补上一个空行就解决啦!! 如果遇到此错误,需检查 ...
- UItexfile实时验证输入字符
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementS ...
- 从零开始学C++之IO流类库(四):输出流格式化(以操纵子方式格式化 以ios类成员函数方式格式化)
一.以操纵子方式格式化 数据输入输出的格式控制使用系统头文件<iomanip>中提供的操纵符.把它们作为插入操作符<<的输出对象即可.如setiosflags.setw.set ...
- 查看一个int数组里边的每个数字出现过几次
public void aa() { int[] a = { 1, 2, 3, 4, 5, 4, 3, 2, 1 }; Hashtable ht = new Hashtable(); for (int ...