javascript:如何使模块同时表现得像对象和函数?

发布于 2024-11-10 15:34:27 字数 2697 浏览 0 评论 0原文

我正在尝试为自己建立一个小助手库。首先,出于学习目的,然后我可以扩展它,以便它在项目中派上用场。

我对原型引用、闭包和范围界定有所了解。我还特意使用模块化模式来制作它,这样我的工具箱就不会污染全局命名空间。 我还知道我们可以将原型分配给构造函数,因此构造的对象将保存这些方法。

这是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坚持沉默 2024-11-17 15:34:27

当某物在原型中和在对象本身上时是有区别的。

考虑以下示例:

var foo = function() { return 'I am foo'; }

foo.prototype.lie = function() { return 'I am not foo'; }
foo.lie(); //error, lie does not exist in foo

var bar = new foo;
bar.lie(); //it works!

原型基本上是父级和子级之间的中间方式。原型拥有父级拥有的所有内容,加上您附加到它的内容 - 但是,父级没有自己的原型。而且,更令人困惑的是,如果您将内容分配给父对象而不是其原型,则额外的内容不会被复制到子对象。很奇怪,对吧?

解释最后一个语句(使用前面的示例):

foo.makeAPoem = function() { return 'Roses are red, violets are blue, coffe milk eggs'; }
var bar = new foo;
foo.makeAPoem(); //works
bar.makeAPoem(); //nope!

这正是为什么您没有 String.split 的原因,但是 'abcd'.split - 这些方法存在在原型中。

如果您想让某些东西在对象和原型中都有效,请将其分配给两者!

foo.jedi = foo.prototype.jedi = function() { return 'This is not the function you are looking for'; }
foo.jedi(); //works
bar.jedi(); //works!

所以现在,您可以选择继承哪些内容以及保留父代中的内容。如果您希望它仅对父级可用,则仅将其附加到父级。但是,如果您希望它仅在子级上可用(例如,您没有 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:

var foo = function() { return 'I am foo'; }

foo.prototype.lie = function() { return 'I am not foo'; }
foo.lie(); //error, lie does not exist in foo

var bar = new foo;
bar.lie(); //it works!

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):

foo.makeAPoem = function() { return 'Roses are red, violets are blue, coffe milk eggs'; }
var bar = new foo;
foo.makeAPoem(); //works
bar.makeAPoem(); //nope!

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!

foo.jedi = foo.prototype.jedi = function() { return 'This is not the function you are looking for'; }
foo.jedi(); //works
bar.jedi(); //works!

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.

染年凉城似染瑾 2024-11-17 15:34:27

你可以定义一个强大的构造函数(我不确定它真的是这样调用的=)),比如:

var toolbox = (function(){
 // some private methods
   var test_1 = function(){ alert("test_1"); };
   var test_2 = function(){ alert("test_1"); };
 // return needed methods and props into the global namespace: 
   return {
    "test_1" : test_1,
    "test_2" : test_2
   }
})();

toolbox.test_1();

you can define a power constructor (I'm not sure it's really called that way =)), something like:

var toolbox = (function(){
 // some private methods
   var test_1 = function(){ alert("test_1"); };
   var test_2 = function(){ alert("test_1"); };
 // return needed methods and props into the global namespace: 
   return {
    "test_1" : test_1,
    "test_2" : test_2
   }
})();

toolbox.test_1();
甚是思念 2024-11-17 15:34:27

原因是 toolbox 从未像 pick 那样实例化为构造函数。简单的解决方案。

而不是仅

pick.prototype = toolbox.prototype = {
....
...
return toolbox;

使用

pick.prototype = {
....
....
for(var attr in pick.prototype) {
  toolbox[attr] = pick.prototype[i];
}

这会将方法直接添加到工具箱

The reason for this is that toolbox was never instantiated as a constructor like pick was. Simple solution.

Instead of

pick.prototype = toolbox.prototype = {
....
...
return toolbox;

use just

pick.prototype = {
....
....
for(var attr in pick.prototype) {
  toolbox[attr] = pick.prototype[i];
}

This will add the methods directly to toolbox

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文