首页 > 解决方案 > 复杂对象中的javascript自引用

问题描述

我重构了一些多余的旧 javascript 代码。我们的页面使用旧版本的 Select2 并在多个位置填充新的 Select2 下拉/搜索框。

我采用了多余的代码并从代码中构建了一个对象。该对象在某些函数中具有自引用。

当我使用该对象时,我制作了该对象的浅表副本。我担心的是副本中的自引用可能指向原始对象的元素,而不是副本的元素。

有什么更好的方法来构造这个对象,使浅拷贝不指向原始对象?

我做了几个小时的研究。不知道谷歌到底用了什么词使得这很难研究。如果这很容易解决,请原谅。

我确实查看了 MDNgettersthis page on self-referenceing in objects。我理解它,但我不知道如何使用它。

    ajax: {
        main: function () {

            let results = (mainObject.ajax.type.toLowerCase === 'new' ? mainObject.ajax.resultNew : mainObject.ajax.resultPreExisting);

            if (typeof (results) != 'function') {
                mainObject.error;
            }
            ajaxObj = {
                url: someOutSideVariableForURL,
                dataType: "json",
                quietMillis: 100,
                data: function (c, d) {
                    return {
                        searchFor: c,
                        maxPerPage: 30,
                        page: d
                    };
                },
                results: results
            }
            return ajaxObj;
        },
        type: "",
        resultNew: function (e, d) {
            //new result function
            var c = {
                results: e.results,
                more: false
            };
            if (d < e.info.totalPages) {
                c.more = true;
            }
            if (c.results.length) {
                $("#someIDTag input[name=firstStuff_" + mainObject.idCount + "]").data("hasResults", true);
            }
            return c;
        },
        resultPreExisting: function (e, d) {
            // Pre existing result function
            var c = {
                results: e.results,
                more: false
            };
            if (d < e.info.totalPages) {
                c.more = true;
            }
            $("#someIDTag input[name=firstStuff_" + mainObject.idCount + "]").data("hasResults", false);
            if (c.results.length) {
                $("#someIDTag input[name=firstStuff_" + mainObject.idCount + "]").data("hasResults", true);
            }

            return c;
        }
    },
    createSearchChoice: function (d) {

        var c = {
            hasResults: $("#someIDTag input[name=firstStuff_" + mainObject.idCount + "]").data("hasResults"),
            results: null
        };
        if ($.trim(d).length) {
            c.results = {
                id: 0,
                text: d
            };
        }
        return c.results;
    },
    error: function(){
        alert("mainObject improper configuration")
        return null
    },
    formatResult: function (item, container, escapeMarkup) {
        var d = {
            response: item.text,
            markup: []
        };
        window.Select2.util.markMatch(d.response, escapeMarkup.term, d.markup);
        if (item.id == 0) {
            d.response += '<br/><i style="font-size:0.8em;"><i class="icon-plus-sign"></i> Add new stuff</i>';
        } else {
            d.response = d.markup.join("");
        }
        if (item.data && item.data.businessFunctions.length) {
            d.response += '<br /><span style="font-size:0.75em;opacity:0.55;">(' + item.data.businessFunctions + ")</span>";
        }
        return d.response;
    },
    formatSearching: function () {
        return ' <i class="icon-spinner icon-spin"></i> Searching stuff...';
    },
    formatSelection: function (item, container) {

        $("#someOtherIDTag  input[name=stuff_" + mainObject.idCount + "]").val(item.text);
        $("#someOtherIDTag input[name=stuff_other_" + mainObject.idCount + "]").val(item.id);
        if (item.id == 0) {
            $(container).append('<i class="pull-right" style="font-size:0.8em;color:#049cdb;font-weight:bold;"><i class="icon-warning-sign"></i> New</i>');
        }
        return item.text;
    },
    getIdCount: function(){ //tried this but do not know how to use it properly
        return this.idCount
    },
    idCount: 0,
    initSelection: function (c, d) {

        d({
            id: $("input[name=dealCompanyID_" + mainObject.idCount + "]").val(),
            text: c.val()
        });
    },
    S2Base: {
        dropdownCssClass: SELECT2FIXED,
        placeholder: "",
        minimumInputLength: 2
    }

} 


// As you can see mainObject is accessed in a few places. Please remember this is not my code. I am just trying to refactor it into an object as the project expands. 

// This is how I use the object (and this is done a few times each time with a different name for newCopyObject):

$(".someClass").each(function(){
    const newCopyObject = {...mainObject};

    newCopyObject.idCount = fromDataAttrOnHTMLNode;
    newCopyObject.ajax.type = 'new';
    $(this).select2({
        ...newCopyObject.S2Base,
        formatSearching: newCopyObject.formatSearching,
        initSelection: newCopyObject.initSelection,
        ajax: newCopyObject.ajax.main(),
        createSearchChoice: newCopyObject.createSearchChoice,
        formatResult:newCopyObject.formatResult,
        formatSelection: newCopyObject.formatSelection
    });
});


// ...do a bunch of other things

标签: javascriptjavascript-objectsjquery-select2

解决方案


在我看来,您可能想要重构。我不完全明白发生了什么,但如果mainObject有对自身的引用,那么在const newCopyObject = {...mainObject}; newCopyObject这些新副本之后将指向mainObject.

使用 _.cloneDeep 来自 lodash 等将是一种方法。我认为使用 ES6 类语法可能是重构它的最快和最容易理解的(对于下一个编码器)方法。


推荐阅读