Associative arrays in javascript

2019-07-16 00:35发布

问题:

I have this object:

function formBuddy()
{
    var fields = new Array();
    var labels = new Array();
    var rules = new Array();
    var count=0;

    this.addField = function(field, label, rule)
    {
        fields[count] = field;
        labels[field] = label;
        rules[field] = rule;
        count = ++count;
    }
}

Its used in this way:

var cForm=new formBuddy();
cForm.addField("c_first_name","First Name","required");
cForm.addField("c_last_name","Last Name","required");

The problem is, in the addField() function the fields array is being set correct (perhaps because a numerical index is being used to refer to it) but the other 2 arrays (labels and rules) aren't being touched at all. Doing a console.log shows them as empty in firebug.

What do I need to change to make them work? I'd still like to refer to the rules and labels by the string index of the field.

回答1:

Use objects instead:

function formBuddy()
{
    var fields = {};
    var labels = {};
    var rules = {};
    var count = 0;

    this.addField = function(field, label, rule)
    {
        fields[count] = field;
        labels[field] = label;
        rules[field] = rule;
        count++;
    }
}

But as Christoph already mentioned, I would store this information in a single data structure too. For example:

function formBuddy() {
    var fields = {};
    this.addField = function(name, label, rule) {
        fields[name] = {
            name: name,
            label: label,
            rule: rule
        };
    };
    this.getField = function(name) {
        return fields[name];
    };
}

var cForm=new formBuddy();
cForm.addField("c_first_name","First Name","required");
cForm.addField("c_last_name","Last Name","required");
alert(cForm.getField("c_last_name").label);


回答2:

fields should be an array, whereas labels and rules should be objects as you want to use strings as keys. Also, addField() is the same for each instance of FormBuddy() (names of constructor functions should be capitalized) and should reside in the prototype, ie

function FormBuddy() {
    this.fields = []; // this is the same as `new Array()`
    this.labels = {}; // this is the same as `new Object()`
    this.rules = {};
}

FormBuddy.prototype.addField = function(field, label, rule) {
    this.fields.push(field);
    this.labels[field] = label;
    this.rules[field] = rule;
};

You can access the labels/rules via

var buddy = new FormBuddy();
buddy.addField('foo', 'bar', 'baz');
alert(buddy.labels['foo']);
alert(buddy.rules.foo);

Just to further enrage Luca ;), here's another version which also dosn't encapsulate anything:

function FormBuddy() {
    this.fields = [];
}

FormBuddy.prototype.addField = function(id, label, rule) {
    var field = {
        id : id,
        label : label,
        rule : rule
    };

    this.fields.push(field);
    this['field ' + id] = field;
};

FormBuddy.prototype.getField = function(id) {
    return this['field ' + id];
};

var buddy = new FormBuddy();
buddy.addField('foo', 'label for foo', 'rule for foo');

It's similar to Gumbo's second version, but his fields object is merged into the FormBuddy instance. An array called fields is added instead to allow for fast iteration.

To access a field's label, rule, or id, use

buddy.getField('foo').label

To iterate over the fields, use

// list rules:
for(var i = 0, len = buddy.fields.length; i < len; ++i)
    document.writeln(buddy.fields[i].rule);


回答3:

Arrays are treated as Objects in Javascript, therefore your piece of code works, it's just that firebug's console.log isn't showing you the "Objects" inside the array, rather just the array values ...

Use the for(var i in obj) to see what objects values the Array contains:

function formBuddy() {
    var fields = new Array();
    var labels = new Array();
    var rules = new Array();
    var count=0;

    this.addField = function(field, label, rule)
    {        
        fields[count] = field;
        labels[field] = label;
        rules[field] = rule;
        count = ++count;

        for(var i in labels) {
            console.log(labels[i]);
        }
        for(var i in rules) {
            console.log(rules[i]);
        }

        console.log(labels.c_last_name);
        // or
        console.log(labels["c_last_name"]);
    }
}

var cForm = new formBuddy();
cForm.addField("c_last_name","Last Name","required");