Javascript库开发范围和命名空间
Javascript library development scopes and namespaces
我们目前在大学的课程中学习了一些Javascript的东西。为此,我们实现了一个库,用于常见的任务,如show()、hide()、write等。
目前我正在运行这样的实现:
var myLib_maker = function () {
/*
private scope
*/
var debuggingMode=true;
var currentElement=null;
/*
end private scope
*/
return {
getElement: function (id) {
var o;
if (typeof id === 'string') { o = document.getElementById(id); }
if (!!(o && o.nodeType !== 1)) {
throw {
name: 'Type Error',
message: 'Wrong node type at id: '+id
}
}
currentElement=o;
return this;
},
getCurrentElement: function() {
console.log(currentElement)
return currentElement;
},
isVisible: function () {
return this.getCurrentElement().style.display.toLowerCase() === "block";
},
show: function () {
this.debug("show "+this.getCurrentElement())
this.getCurrentElement().style.display = "block";
return this;
},
hide: function () {
this.debug("hide "+this.getCurrentElement())
this.getCurrentElement().style.display = "none";
return this;
},
toggle: function() {
this.debug("toggle "+this.getCurrentElement())
this.isVisible() ? this.hide(): this.show();
return this;
},
write: function (content){
this.debug("write to"+this.getCurrentElement().id);
var tg = this.getCurrentElement().tagName.toLowerCase();
if (tg === 'input' || tg === 'textarea') {
currentElement.value = content;
} else {
currentElement.innerHTML = content;
}
return this
},
debug: function (what) {
if (debuggingMode===true){
console.log("[DEBUG] "+what);
}
return this;
}
};
}
var myLib=myLib_maker();
然后我有一个外部函数(用于测试)来切换两个文本区域的内容。
function switchEditors(id1, id2){
c1=myLib.getElement(id1).getCurrentElement().value;
c2=myLib.getElement(id2).getCurrentElement().value;
myLib.getElement(id1).write(c2)
myLib.getElement(id2).write(c1)
}
我首先尝试了下面的代码,这显然不起作用,因为我覆盖了我的私有currentElement,所以我总是写id2
function switchEditors(id1, id2){
tmp=myLib.getElement(id1).getCurrentElement().value
myLib.getElement(id1).write(myLib.getElement(id2).getCurrentElement().value)
myLib.getElement(id2).write(tmp)
}
但是我最初真正想要的不是使用私有的currentElement变量。写方法的第一个实现扩展了Element Object
Element.prototype.write= function (content){
var tg = this.tagName.toLowerCase();
if (tg === 'input' || tg === 'textarea') {
this.value = content;
} else {
this.innerHTML = content;
}
return this;
}
等getElement函数返回
document.getElementById(id)
我想层叠(我希望这是正确的词->我的意思是myLib.getElement("myid").show().hide()串联的东西),并获得直接访问但是我们不能为我们的库使用全局作用域,所以我必须以任何方式封装我的库。
那么是否有一种优雅的方式来使用级联的东西,并能够直接访问元素对象上的所有属性,而无需在全局元素范围内实现每个方法?
或者我的lib设计完全错误,必须完全不同。如果有,请告诉我,我很感激你的帮助。(我试图弄清楚jQuery实际上是如何实现这些东西的,但没有得到一个真正的线索,它是如何完成的…太多的代码……:))
我希望我描述了我的愿望和要求。
正如您所发现的,currentElement
在呼叫getElement
之间是共享的。相反,您可以使用Object创建myLib-object的新实例。创建并绑定currentElement
。
getElement: function (id) {
var o, self = Object.create(this);
/* ... */
self.currentElement = o;
return self;
}
并始终使用this.currentElement
,以便每个调用使用自己的当前元素。
虽然Magnar的解决方案可以使用这种(单例)模式,但最好避免每次调用getElement
时都创建一个全新的对象。创建"类"而不是单例是有原因的。
你可以这样做:
var MyLib_Maker = (function () { // I capitalized the class as a helpful
// convention recommended by Douglas Crockford
// Private static vars
var debuggingMode = true;
var currentElement = null;
// Private static methods
function _myMethod (x, y) { // call below by _myMethod(3,4);
return x * y;
}
// Private instance methods (but only if called properly:
// invoke below by _instMethod.call(this, 3, 4); )
function _instMethod (x, y) {
return this.anInstanceNumber * x * y;
}
// Private instance properties (quite cumbersome but doable if you
// absolutely must--e.g., for classes whose objects need to be clean when iterated)
// See http://brettz9.blogspot.com/2009/02/true-private-instance-variables-in.html
// and http://brettz9.blogspot.com/2009/02/further-relator-enhancements.html
// (put the Relator inside the closure if you don't want it reusable (and public),
// but then your extending classes must be inside the closure too)
function MyLib_Maker (arg1, arg2) {
// I recommend the following check to allow your class to be
// instantiated without the 'new' keyword (as in jQuery/$):
if (!(this instanceof MyLib_Maker)) {
return new MyLib_Maker(arg1, arg2);
}
// Other constructor code here
// ...
}
// Methods added on the prototype benefit from merely
// providing a low-memory reference across all instances;
// this will avoid adding a whole new object unnecessarily
// into memory
MyLib_Maker.prototype.getElement = function () {
// ....
return this; // Keep the chain going (if not public
// properties, you could add a method which also avoids
// extending the chain, like $(el).get() in jQuery
};
return MyLib_Maker;
}()); // We can invoke immediately to wrap up the closure
// Usage example:
var mlm = MyLib_Maker(2, 3).getElement().doSomething();
顺便说一下,你所描述的被称为连锁;层叠在CSS中被用来表示像瀑布中不同的波浪一样,一个可以写在另一个上面,就像你可以在CSS中写覆盖先前的规则一样。
最好不要覆盖Element对象,因为无论浏览器兼容性如何,这都是最糟糕的全局命名空间污染,因为它会影响所有元素,增加了依赖于该方法的另一个库(或者不小心覆盖内置原型本身)可能会给您带来意想不到的结果的机会。
- 在javascript中使用命名空间
- 为什么不推荐使用“with”?是否有更好或其他方法可以“下降”到对象的命名空间
- javascript中的命名空间,IDE中支持代码完成/内容辅助's
- 如何使用javascript命名空间
- js命名空间和变量范围
- html,js-如何限制元素"范围“-命名空间
- 转换自的JavaScript命名空间
- 命名空间与自调用函数
- 什么's当前命名空间/类中JavaScript子命名空间/类的语法
- 无法加载Ace.js编辑器模式和主题(命名空间项目&AMD require.js&grunt
- jQuery命名空间和使用“;这个“;
- 在Firebug控制台中监视javascript命名空间变量
- jQuery事件命名空间是否可以包含破折号
- 用自定义javascript全局命名空间替换窗口
- 如何在Typescript中导出具有其他名称的命名空间
- 从html文件中的脚本标记调用非全局命名空间函数
- 短范围命名空间数组是什么意思
- 命名空间和词法范围之间的关系是什么
- c++ /CX:在命名空间范围定义公共void
- Javascript库开发范围和命名空间