我应该如何在交互式 Web 应用程序中实现 OOP 模式(借助 jQuery)?

发布于 2024-11-05 07:09:31 字数 2605 浏览 4 评论 0原文

有时,使用 jQuery 会导致您滥用其功能(至少对我来说是这样,因为它的选择器匹配功能)。到处都有事件处理程序。实用功能无处不在。代码一致性几乎不存在。我想通过实现 OOP 模式来缓解这个问题,但由于我有 C++ 和 python 背景,在 javascript 中实现它让我有点奇怪。

下面的代码使用 OOP 模式,但我不完全确定我的实现是否是好的实践。我怀疑我的实现的原因是因为 我的上一个 stackoverflow 问题。我知道他评论的只是我的代码中的一个特定细节,但这也让我想知道我在代码中实现的其他模式。

如果您能指出我的模式中的缺陷和陷阱和/或有任何建议,我将非常感激。非常感谢。

(此代码是我正在开发的代码的简化,但想法相似)

Live示例

$(function(){
    var stream = new Stream();
});


/*          Stream Class
------------------------------------------*/
function Stream(){

    // Disables multiple Stream objects
    if (this.singleton)
        return
    else
        this.__proto__.singleton = true;


    this.elements = jQueryMapping(this.selectors) // Converts a map of selectors to a map of jQuery objects
    this.initEvents();
}

Stream.prototype.singleton = false;

Stream.prototype.selectors = {
    stream : '#stream',
    post_content : '#post-content',
    add_post: '#add-post',
    // ... more action selectors
}

Stream.prototype.initEvents = function(){
    this.elements.add_post.click(this, this.addPost);
    // ... more action event-listeners
}

Stream.prototype.addPost = function(e){
    var self = e.data;
    var post_content = self.elements.post_content.val();

    if (post_content)
        self.elements.stream.append(new Post(post_content));
}


/*          Post Class
------------------------------------------*/
function Post(post_content){
    this.$element = $('<li>')
                        .text(post_content)
                        .append('<button class="delete-post">Delete</button>');

    this.elements = jQueryMapping(this.selectors, this.$element);
    this.initEvents();

    return this.$element;
}

Post.prototype.selectors = {
    delete_post: 'button.delete-post',
    // ... more action selectors
}

Post.prototype.initEvents = function(){
    this.elements.delete_post.click(this.deletePost);
    // ... more action event-listeners
}

Post.prototype.deletePost = function(){
    $(this).parent().slideUp();
}


/*          Utils
------------------------------------------*/
function jQueryMapping(map, context){
    // Converts a map of selectors to a map of jQuery objects

    var $map = {};
    $.each(map, function(key, value){ 
            $map[key] = (context) ? $(value, context) : $(value);
    });

    return $map;
}

Sometimes, using jQuery induces you to abuse its power (at least for me because of its selector matching capability). Event handlers here and there. Utility functions here and everywhere. Code coherence can almost seem nonexistent. I want to alleviate that problem by implementing OOP patterns, but since I have C++ and python background, implementing it in javascript is weirding me out a little bit.

The code below uses OOP patterns, but I'm not entirely sure if my implementations are good practices. The reason I'm doubting my implementations is because of the 3rd comment in my last stackoverflow question. I know it's only one certain detail in my code he commented on, but it also makes me wonder about the other patterns I'm implementing in my code.

I would really appreciate if you could point out the flaws and pitfalls in my patterns and/or if you have any suggestions. Many thanks in advance.

(this code is an simplification of something I'm developing, but the idea is similar)

Live Example

$(function(){
    var stream = new Stream();
});


/*          Stream Class
------------------------------------------*/
function Stream(){

    // Disables multiple Stream objects
    if (this.singleton)
        return
    else
        this.__proto__.singleton = true;


    this.elements = jQueryMapping(this.selectors) // Converts a map of selectors to a map of jQuery objects
    this.initEvents();
}

Stream.prototype.singleton = false;

Stream.prototype.selectors = {
    stream : '#stream',
    post_content : '#post-content',
    add_post: '#add-post',
    // ... more action selectors
}

Stream.prototype.initEvents = function(){
    this.elements.add_post.click(this, this.addPost);
    // ... more action event-listeners
}

Stream.prototype.addPost = function(e){
    var self = e.data;
    var post_content = self.elements.post_content.val();

    if (post_content)
        self.elements.stream.append(new Post(post_content));
}


/*          Post Class
------------------------------------------*/
function Post(post_content){
    this.$element = $('<li>')
                        .text(post_content)
                        .append('<button class="delete-post">Delete</button>');

    this.elements = jQueryMapping(this.selectors, this.$element);
    this.initEvents();

    return this.$element;
}

Post.prototype.selectors = {
    delete_post: 'button.delete-post',
    // ... more action selectors
}

Post.prototype.initEvents = function(){
    this.elements.delete_post.click(this.deletePost);
    // ... more action event-listeners
}

Post.prototype.deletePost = function(){
    $(this).parent().slideUp();
}


/*          Utils
------------------------------------------*/
function jQueryMapping(map, context){
    // Converts a map of selectors to a map of jQuery objects

    var $map = {};
    $.each(map, function(key, value){ 
            $map[key] = (context) ? $(value, context) : $(value);
    });

    return $map;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

南风起 2024-11-12 07:09:31

我相信你的代码设计过度了。我已经重新考虑并简化了它,如此处所示。如果您确实想要一个繁重的 OOP 设置,我建议您使用客户端 MVC(Backbone、knockout 等)构造来正确完成它或保持轻量级。

我将继续对您的代码提供一般反馈。

/*          Stream Class
------------------------------------------*/
function Stream(){

    // Disables multiple Stream objects
    if (this.singleton)
        return
    else
        this.__proto__.singleton = true;


    this.elements = jQueryMapping(this.selectors) // Converts a map of selectors to a map of jQuery objects
    this.initEvents();
}

没有理由使用这样的单例。使用 .__proto__非常不好,

我会推荐这样的模式。

var Stream = (function() {
    var Stream = function() { ... };

    // prototype stuff

    var stream = new Stream();

    return function() {
         return stream;
    };
})());

没有必要像原型上那样存储数据的哈希值。

Stream.prototype.selectors = {
    stream : '#stream',
    post_content : '#post-content',
    add_post: '#add-post',
    // ... more action selectors
}

您可以将其包含为默认哈希值。

(function() {
    var defaults = {
        stream : '#stream',
        post_content : '#post-content',
        add_post: '#add-post',
        // ... more action selectors
    }

    function Stream() {
         ...

         this.elements = jQueryMapping(defaults);
    }

}());

您的效用函数可以稍微优化。

$map[key] = (context) ? $(value, context) : $(value);

这可以重写为

$map[key] = $(value, context)

因为如果 context 未定义,您只需传递一个未定义的参数,这与不传递参数相同。

I believe your code is over engineered. I've re factored and it simplified it as can be seen here. If you really want a heavy OOP setup I recommend you use a clientside MVC (Backbone, knockout, etc) construct to do it properly or keep it light instead.

I'll proceed with general feedback on your code.

/*          Stream Class
------------------------------------------*/
function Stream(){

    // Disables multiple Stream objects
    if (this.singleton)
        return
    else
        this.__proto__.singleton = true;


    this.elements = jQueryMapping(this.selectors) // Converts a map of selectors to a map of jQuery objects
    this.initEvents();
}

There is no reason to use a singleton like this. It's also very bad to use .__proto__

I would recommend pattern like this instead.

var Stream = (function() {
    var Stream = function() { ... };

    // prototype stuff

    var stream = new Stream();

    return function() {
         return stream;
    };
})());

Storing a hash of data like that on the prototype is unneccesary.

Stream.prototype.selectors = {
    stream : '#stream',
    post_content : '#post-content',
    add_post: '#add-post',
    // ... more action selectors
}

You can include this as a defaults hash instead.

(function() {
    var defaults = {
        stream : '#stream',
        post_content : '#post-content',
        add_post: '#add-post',
        // ... more action selectors
    }

    function Stream() {
         ...

         this.elements = jQueryMapping(defaults);
    }

}());

Your utility function could be optimised slightly.

$map[key] = (context) ? $(value, context) : $(value);

This could be rewritten as

$map[key] = $(value, context)

Since if context is undefined you just pass in an undefined paramater which is the same as passing in no parameter.

请你别敷衍 2024-11-12 07:09:31

该标题为“适合初学者”,但我发现此部分 关于设计模式,以及 本节关于使用 jQuery 的设计模式很有用。

The title of this reads "for beginners", but I've found this section on design patterns, and this section on design patterns using jQuery useful.

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