javascript:如何使模块同时表现得像对象和函数?
我正在尝试为自己建立一个小助手库。首先,出于学习目的,然后我可以扩展它,以便它在项目中派上用场。
我对原型引用、闭包和范围界定有所了解。我还特意使用模块化模式来制作它,这样我的工具箱就不会污染全局命名空间。 我还知道我们可以将原型分配给构造函数,因此构造的对象将保存这些方法。
这是 toolbox.js
的内容
(function (window) {
var toolbox = (function () {
var toolbox = function(it){
return new pick(it);
}
var pick = function (it){
var craft = document.getElementsByTagName(it);
craft = Array.prototype.slice.call(craft, 0);
return Array.prototype.push.apply(this, craft);
}
pick.prototype = toolbox.prototype = {
raw: function(){
return Array.prototype.slice.call(this, 0);
},
tell: function(secret){
return secret;
}
}
return toolbox;
}());
window.toolbox = toolbox;
})(window);
并调用 toolbox
:
toolbox("div"); //returns the desired object with the div collection
toolbox("div").raw(); //returns a raw array with the divs
toolbox().tell("A secret"); //returns "A secret"
toolbox.tell("It's a secret"); //type error: the function has no method like tell (like hell it does...should)
但像这样修改上面的代码:
var toolbox = (function () {
var toolbox = function(it){
return new pick(it);
}
...
toolbox.tell(secret){ return secret }
return toolbox;
}());
将起作用。
所以我的问题是为什么 toolbox.prototype = {}
不起作用,而 pick.prototype = {}
将使 pick
继承定义的方法?
我希望实现 toolbox.tell("something");
和 toolbox("div").raw();
无需直接解析即可实现将方法原型化到模块中。
请帮忙!我已经用谷歌搜索了好几天来学习这些,但现在我陷入了困境。非常感谢您的帮助!
更新
简而言之,jQuery 是如何做到这一点的:
(function( window, undefined ) {
var jQuery = (function() {
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
//init stuff
}
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
//extend stuff
};
jQuery.extend({
//extend stuff
});
// Expose jQuery to the global object
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
I'm trying to build myself a little helper library. first, for learning purposes, then that later I can extend it so it may come in handy in projects.
I understand somewhat the prototype referencing, closures, and scoping. I also intentionally made it using modular pattern so my toolbox
is not polluting the global namespace.
I also know we may assign prototypes to constructor functions, so the constructed Objects will hold those methods.
Here's the content of toolbox.js
(function (window) {
var toolbox = (function () {
var toolbox = function(it){
return new pick(it);
}
var pick = function (it){
var craft = document.getElementsByTagName(it);
craft = Array.prototype.slice.call(craft, 0);
return Array.prototype.push.apply(this, craft);
}
pick.prototype = toolbox.prototype = {
raw: function(){
return Array.prototype.slice.call(this, 0);
},
tell: function(secret){
return secret;
}
}
return toolbox;
}());
window.toolbox = toolbox;
})(window);
and calling the toolbox
:
toolbox("div"); //returns the desired object with the div collection
toolbox("div").raw(); //returns a raw array with the divs
toolbox().tell("A secret"); //returns "A secret"
toolbox.tell("It's a secret"); //type error: the function has no method like tell (like hell it does...should)
but modifying the above code like this:
var toolbox = (function () {
var toolbox = function(it){
return new pick(it);
}
...
toolbox.tell(secret){ return secret }
return toolbox;
}());
will work.
So my question is why toolbox.prototype = {}
doesn't do the trick, while pick.prototype = {}
will make pick
inherit the defined methods?
I'd like to achieve both toolbox.tell("something");
and toolbox("div").raw();
to be possible without having to resolve directly prototyping the method into the modul.
Please help! I've been googling for days to learn these, and I'm stuck now. Your help is much appreciated!
UPDATE
Here's how jQuery does this in a nutshell:
(function( window, undefined ) {
var jQuery = (function() {
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
//init stuff
}
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
//extend stuff
};
jQuery.extend({
//extend stuff
});
// Expose jQuery to the global object
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当某物在原型中和在对象本身上时是有区别的。
考虑以下示例:
原型基本上是父级和子级之间的中间方式。原型拥有父级拥有的所有内容,加上您附加到它的内容 - 但是,父级没有自己的原型。而且,更令人困惑的是,如果您将内容分配给父对象而不是其原型,则额外的内容不会被复制到子对象。很奇怪,对吧?
解释最后一个语句(使用前面的示例):
这正是为什么您没有
String.split
的原因,但是'abcd'.split
- 这些方法存在在原型中。如果您想让某些东西在对象和原型中都有效,请将其分配给两者!
所以现在,您可以选择继承哪些内容以及保留父代中的内容。如果您希望它仅对父级可用,则仅将其附加到父级。但是,如果您希望它仅在子级上可用(例如,您没有 jQuery.andSelf,但有 jQuery().andSelf),请将其附加到原型中。如果您想要两者,请将其附加到两者。
There's a difference when something is in a prototype and when it's on the object itself.
Consider the following example:
prototype
is basically the mid-way between the parent and the child. The prototype has all what the parent has, plus what you appended to it - however, the parent does not have its own prototype. And, to be more confusing, if you assign stuff to the parent object and not to its prototype, the extra stuff won't get copied to the children. Weird, right?To explain the last statement (using the previous example):
It's exactly why you don't have
String.split
for example, but'abcd'.split
- these methods exist in the prototype.If you want to make something works in both the object and the prototype, assign it to both!
So now, you can choose what gets inherited and what stays in the parent. If you want it only available to the parent, only append it to the parent. However, if you want it to only be available on the child (e.g. you don't have
jQuery.andSelf
, but you do have jQuery().andSelf) append it to the prototype. If you want both, append it to both.你可以定义一个强大的构造函数(我不确定它真的是这样调用的=)),比如:
you can define a power constructor (I'm not sure it's really called that way =)), something like:
原因是 toolbox 从未像 pick 那样实例化为构造函数。简单的解决方案。
而不是仅
使用
这会将方法直接添加到工具箱
The reason for this is that toolbox was never instantiated as a constructor like pick was. Simple solution.
Instead of
use just
This will add the methods directly to toolbox