Javascript 库开发范围和命名空间
我们目前在大学的课程中学习了一些 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();
比我有一个外部函数(用于测试)来切换2个文本区域内容。
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 变量。 write 方法的第一个实现扩展了 Element 对象
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()连接事物)并直接访问 所有元素属性,但我们不能对我们的库使用全局范围,所以我必须以任何方式封装我的库。
那么是否有一种优雅的方法来使用级联,并且能够直接访问元素对象上的所有属性,而无需在全局元素范围内实现每个方法?
或者我的库设计完全错误并且必须完全不同。 如果是这样,请告诉我,我感谢任何帮助。 (我试图弄清楚 jQuery 是如何实际实现这些东西的,但没有得到真正的线索是如何完成的......太多的代码......:))
我希望我描述了我的愿望和要求。如果没有,请询问更具体的细节。
we currently learn some Javascript stuff in a course at the university.
For that we implement a library for common tasks like show(), hide(), write and such things.
Currently im running with an implementation like:
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();
Than I have an external function (for testing) to switch 2 textareas contents.
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)
}
I first tried with the following code, which obviously does not work, cause I overwrite my private currentElement and so I write always to 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)
}
But what I really wanted initially was not using a private currentElement variable.
The first implementation of the write method extended the 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;
}
and such the getElement function returned
document.getElementById(id)
I want cascading (I hope this is the right word -> I mean the myLib.getElement("myid").show().hide() concatenation thing) and getting direct access to
all Element attributes but we must not use global scope for our library, so I have to encapsulate my library in any way.
So is there an elegant way to use the cascading thing and be able to get a direct access to all attributes on an element object without implementing each method within the global element scope?
Or is my lib desing completely wrong and has to be done totally different.
If so, just tell me, I appreciate any help.
(I tried to figure out how jQuery actually implement these things, but didn't get a real clue how it is done ... too much code ... :) )
I hope I described my wishes and requirements. If not please ask for more specific details.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如您所了解的,
currentElement
在对getElement
的调用之间共享。相反,您可以使用 Object.create 创建 myLib-object 的新实例并绑定currentElement
对此。并始终使用
this.currentElement
,以便每次调用都使用自己的当前元素。As you've figured out, the
currentElement
is shared between calls togetElement
. Instead you could create a new instance of myLib-object with Object.create and bindcurrentElement
to that.And use
this.currentElement
throughout so that each call uses its own current element.虽然 Magnar 的解决方案适用于这种(单例)模式,但最好避免每次调用
getElement
时都创建一个全新的对象。创建“类”而不是单例是有原因的。你可以这样做:
顺便说一句,你所描述的称为链接;级联用于 CSS 之类的应用中,表示就像瀑布中的不同波浪一样,一个波浪可以覆盖另一个波浪,就像您可以通过编写覆盖 CSS 中先前规则的规则来做到这一点。
最好不要重写 Element 对象,因为无论浏览器不兼容,这都是最糟糕的全局命名空间污染,因为它会影响所有元素,增加另一个依赖该方法(或粗心的库)的机会覆盖内置原型本身)可能会给您带来意想不到的结果。
While Magnar's solution will work with this (singleton) pattern, it is a better idea to avoid creating a whole new object each time you call
getElement
. There is a reason for creating "classes" instead of singletons.You can do it like this:
By the way, what you describe is called chaining; cascading is used in the likes of CSS to indicate that like different waves out of a waterfall, one may write over the other, as you can do by writing rules which override prior ones in CSS.
And it is good you moved away from overriding the Element object because, whatever the browser incompatibilities, this is the worst kind of global namespace pollution because it affects all elements, increasing the chance that another library which depends on that method (or which is careless in overriding the built-in prototypes itself) may get you unexpected results.