简体   繁体   English

jQuery重构-DRY

[英]jQuery Refactoring - DRY

I have these two functions, inside of my main function. 我的主要功能内部有这两个功能。 As you'll see the only difference between the two of them is in the middle with how they append/edit the html. 正如您将看到的,两者之间的唯一区别在于中间如何附加/编辑html。 I am thinking it would be nice to come up with two new functions, one that does the first half and the other that does the second half. 我认为提出两个新功能会很不错,一个功能执行前一半,另一个功能执行后一半。 I'm not sure if this is possible with jQuery, or even with JavaScript for that matter, as I don't know how to call these new functions inside of these functions, if that makes sense. 我不确定这是否可以用jQuery甚至是JavaScript来实现,因为我不知道如何在这些函数中调用这些新函数。 Any help/guidance would be great! 任何帮助/指导都会很棒!

Here is the first one 这是第一个

$('#save').click(function(){
var title = $('#title').val();
var tags = $('#tags').val();
var notes = $('#notes').val();
var myDate = new Date();
if (title.length < 1) {
  $('.title-warn').show();
}
if (tags.length < 1) {
  $('.tags-warn').show();
}
if (notes.length < 1) {
  $('.notes-warn').show();
}
if (title.length >= 1 && tags.length >= 1 && notes.length >= 1) {
  $allNotes.prepend('<li class="note"><div><h1>' + title + '</h1><div class="date">      <h2>'+ myDate.toDateString() +'</h2><span class="btn btn-edit">Edit</span></div><h3>' + tags + '</h3><p>' + notes + '</p></div></li>');
  $allNotes.show();
  $newNote.hide();
  $('.title-warn').hide();
  $('.tags-warn').hide();
  $('.notes-warn').hide();
}
$('#title').val('');
$('#tags').val('');
$('#notes').val('');
$('#search').prop('disabled', false);
$('#search').attr("placeholder", "Search by title, tags, date, or even words/sentences in notes");
$('.btn-search').prop('disabled', false);
});

And now the second one 现在第二个

$('#edit').click(function(){
var title = $('#edit-title').val();
var tags = $('#edit-tags').val();
var notes = $('#edit-notes').val();
var myDate = new Date();
if (title.length < 1) {
  $('.title-warn').show();
}
if (tags.length < 1) {
  $('.tags-warn').show();
}
if (notes.length < 1) {
  $('.notes-warn').show();
}
if (title.length >= 1 && tags.length >= 1 && notes.length >= 1) {
  $('.edited-note').html('<div><h1>' + title + '</h1><div class="date">      <h2>'+ myDate.toDateString() +'</h2><span class="btn btn-edit">Edit</span></div><h3>' + tags + '</h3><p>' + notes + '</p></div>');
  $('.allnotes').show();
  $('.edit-note').hide();
  $('.title-warn').hide();
  $('.tags-warn').hide();
  $('.notes-warn').hide();
}
$('#title').val('');
$('#tags').val('');
$('#notes').val('');
$('#search').prop('disabled', false);
$('#search').attr("placeholder", "Search by title, tags, date, or even words/sentences in notes");
$('.btn-search').prop('disabled', false);
$('.edited-note').removeClass('edited-note');
});

And of course if anyone has any suggestions on any other aspects of my code I am up for criticism! 当然,如果有人对我的代码的其他方面有任何建议,我将受到批评!

You answered your own question! 你是在自问自答! "As you'll see the only difference between the two of them is in the middle with how they append/edit the html." “正如您将看到的,两者之间的唯一区别在于它们附加/编辑html的方式在中间。” An initial pretty naive and mechanical attempt attempt at refactoring might look like something like this, just pulling out all the common code into shared functions: 最初的一次天真的,机械的重构尝试可能看起来像这样,只是将所有通用代码提取到共享函数中:

function preHandler(title, tags, notes) {
    if (title.length < 1) {
        $('.title-warn').show();
    }
    if (tags.length < 1) {
        $('.tags-warn').show();
    }
    if (notes.length < 1) {
        $('.notes-warn').show();
    }

    return title.length >= 1 && tags.length >= 1 && notes.length >= 1;

}


function commonPost () {

    $('#title').val('');
    $('#tags').val('');
    $('#notes').val('');
    $('#search').prop('disabled', false);
    $('#search').attr("placeholder", "Search by title, tags, date, or even words/sentences in notes");
    $('.btn-search').prop('disabled', false);


}



$('#save').click(function(){
    var title = $('#title').val();
    var tags = $('#tags').val();
    var notes = $('#notes').val();
    var myDate = new Date();
    if  (preHandler(title, tags, notes)) {

        $allNotes.prepend('<li class="note"><div><h1>' + title + '</h1><div class="date">      <h2>'+ myDate.toDateString() +'</h2><span class="btn btn-edit">Edit</span></div><h3>' + tags + '</h3><p>' + notes + '</p></div></li>');
        $allNotes.show();
        $newNote.hide();
        $('.title-warn').hide();
        $('.tags-warn').hide();
        $('.notes-warn').hide();

    }
    commonPost();

});


$('#edit').click(function() {
    var title = $('#edit-title').val();
    var tags = $('#edit-tags').val();
    var notes = $('#edit-notes').val();
    var myDate = new Date();

    if  (preHandler(title, tags, notes)) {

        $('.edited-note').html('<div><h1>' + title + '</h1><div class="date">      <h2>'+ myDate.toDateString() +'</h2><span class="btn btn-edit">Edit</span></div><h3>' + tags + '</h3><p>' + notes + '</p></div>');
        $('.allnotes').show();
        $('.edit-note').hide();
        $('.title-warn').hide();
        $('.tags-warn').hide();
        $('.notes-warn').hide();

    }

    commonPost();
    $('.edited-note').removeClass('edited-note');

});

It doesn't really win you that much when there are only two scenarios. 当只有两种情况时,它并不能真正赢得您那么多。 But with more than two doing this sort of refactoring starts to reap rewards. 但是,如果有两个以上的人员进行这种重构,就会开始获得回报。

This first attempt could be refined (a lot). 第一次尝试可以改进(很多)。 Perhaps nice folks will post. 也许好人会发帖。 But this would be a good first attempt. 但这将是一个不错的尝试。

Generally I like creating some sort of a controller class which does all the UI work for each page in my application. 通常,我喜欢创建某种控制器类,该类可以为应用程序中的每个页面执行所有UI。 This makes testing a whole lot easier because you can invoke your target methods in a very easy manner. 这使测试变得非常容易,因为您可以非常轻松地调用目标方法。

I also like prefer hiding my selectors behind easy to read variables, so if I were to read this file in a few weeks/months from now, I can quickly bring myself to speed by reading what the high-level logic is intending to do. 我还喜欢将选择器隐藏在易于读取的变量后面,因此,如果从现在起数周/数月内要读取此文件,则可以通过阅读高级逻辑打算做什么来快速提高自己的速度。 (FYI in my answer below I haven't done this. I actually don't know what editTitle is supposed to represent. But here are few examples of how I would rename it as: TaskTitle, BlogTitle, etc.) (仅供参考,我在下面的答案中还没有做到这一点。实际上我不知道editTitle应该代表什么。但是这里有一些示例将其重命名为:TaskTitle,BlogTitle等。)

These are all guidelines really, but I wished I had always written my code like this. 这些确实是所有准则,但我希望我总是这样编写代码。 I would recommend you to take out some time and just read about javascript design patterns, programming idioms, etc. 我建议您花一些时间,然后阅读有关javascript设计模式,编程习惯用法等的信息。

var myApp = new app();

$(function () {
    myApp.init();
});

var app = function () {
    var editTitle = "#edit-title";
    var editTitleWarning = ".title-warn";

    var editTags = "#edit-tags";
    var editTagsWarning = ".tags-warn";

    var editNotes = "#edit-notes";
    var editNotesWarning = ".notes-warn";

    var saveButton = "#save";
    var editButton = "#edit";

    var updateUI = function (args) {
        var isSave = args.data.isSave;
        var title = $(editTitle).val();
        var tags = $(editTags).val();
        var notes = $(editNotes).val();
        var myDate = new Date();

        // (suggestion) add comment here 
        if (title.length < 1) {
            $(editTitleWarning).show();
        }

        // (suggestion) add comment here 
        if (tags.length < 1) {
            $(editTagsWarning).show();
        }

        // (suggestion) add comment here 
        if (notes.length < 1) {
            $(editNotesWarning).show();
        }

        if (isSave) {
            // add save append code here
        } else {
            // add edit html code here
        }

        // add remaining code here
    };

    this.init = function () {
        $("body")
            .on("click", saveButton, { isSave = true }, updateUI)
            .on("click", editButton, { isSave = false }, updateUI);
    };
}

Talking only about making the code DRY (versus about architecturing it properly in general), I'd probably rewrite the code as: 只谈论使代码DRY(相对于通常对其进行适当的架构设计),我可能会将代码重写为:

 var handler = function(prefix, htmlHandler, removeEditedNoteCls) { prefix = '#' + (prefix === false ? '' : (prefix + '-')); var list = ['title', 'tags', 'notes'], i = 0, h = { date: new Date }, act = true; for (; i < list.length; i++) { h[list[i]] = $(prefix + list[i]).val(); if (h[list[i]].length < 1) { $('.' + list[i] + '-warn').show(); act = false; } } if (act) { htmlHandler.call(this, h); for (i = 0; i < list.length; i++) { $('.' + list[i] + '-warn').hide(); } } for (i = 0; i < list.length; i++) { $('#' + list[i]).val(''); } $('#search').prop('disabled', false); $('#search').attr("placeholder", "Search by title, tags, date, or even words/sentences in notes"); $('.btn-search').prop('disabled', false); if (removeEditedNoteCls) { $('.edited-note').removeClass('edited-note'); } }, prepend = function(h) { $allNotes.prepend('<li class="note"><div><h1>' + h.title + '</h1><div class="date"> <h2>' + h.date.toDateString() + '</h2><span class="btn btn-edit">Edit</span></div><h3>' + h.tags + '</h3><p>' + h.notes + '</p></div></li>'); $allNotes.show(); $newNote.hide(); }, replace = function(h) { $('.edited-note').html('<div><h1>' + h.title + '</h1><div class="date"> <h2>' + h.date.toDateString() + '</h2><span class="btn btn-edit">Edit</span></div><h3>' + h.tags + '</h3><p>' + h.notes + '</p></div>'); $('.allnotes').show(); $('.edit-note').hide(); }; $('#save').click(function() { handler('', prepend); }); $('#edit').click(function() { handler('edit', replace, true); }); 

Basically, you: 基本上,您:

  1. Don't repeat var per earch variable declaration. 不要在每个earch变量声明中重复var Use commas to separate declarations under the same var . 使用逗号分隔同一var下的声明。 Although not a big deal with DRY but it makes code shorter and nicer. 尽管与DRY无关紧要,但是它使代码更短,更好。
  2. Identify repeating/similar stuff and squash it into either: 识别重复/类似的东西并将其压缩为:
    • Loops over arrays which contain the differences only. 循环仅包含差异的数组。 In your case it will be the array of IDs ['title', 'tags', 'notes'] ; 在您的情况下,它将是ID ['title', 'tags', 'notes']的数组; OR 要么
    • Methods accepting the differences as arguments. 接受差异作为参数的方法。 In your case both "edit" and "save" handlers are pretty similar, which should be the first signal to you to wrap them into a named method ( handler in my example). 在您的情况下,“ edit”和“ save”处理程序非常相似,这应该是您第一个将它们包装到命名方法中的信号(在我的示例中为handler )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM