2

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
  • Javascript don't have native associative arrays, only objects. Objects have properties and the name of the property is always a string. Even the index of arrays is converted to a string before the 'array magic' happens. Commented Feb 22, 2009 at 20:13

4 Answers 4

8

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);
Sign up to request clarification or add additional context in comments.

10 Comments

Indeed, javascript has no associative arrays. An associative array is an object.
If I did rules[field] then (where field is a string containing a field name) would it work?
Why use Objects when you can simply augment Arrays? -1.
Because he probably intended for "labels" and "rules" to be looked-up by field name instead of index?
@Luca: because it's bad practice to mis-use arrays as maps? fields should be an array because the keys are numeric, labels and rules should be objects if you want to use non-numeric keys; for another solution, check my answer below
|
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);

7 Comments

I think he/she wants the properties to be private, I could be wrong though.
@Luca: I never understood why so many people are fond of these so-called 'private' variables: it's inefficient - for each instance, an additional function object holding a reference to the closure over the constructor function's variable object has to be created - and imo not 'in the spirit' of JS
@Christoph: you clearly never developed large enough applications in an object oriented environment to not be able to understand privatization.
@Luca: I'm quite aware of encapsulation and information hiding, but also of the concepts called over-engineering and efficiency; in JavaScript, I'd prefer exposing properties directly over implementing unnecessary getters any day
Private in JS is ridiculous - it's just not required in the way it is in build-compiled languages and wastes another few bytes of download time. Definite over-engineering 99% of the time. FWIW, I think the 'field'+ is kind of pointless, I'd just go with id alone
|
0

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");

3 Comments

What i need to do is to be able to retreive the rule of a field. E.g rule=rules[field], or rule=rules.field. That isn't currently working with the arrays code and gives me an error.
Works for me console.log(labels["c_last_name"]); or console.log(labels.c_last_name);
you should check hasOwnProperty() when looping over the properties - some time ago, it was fashionable to extend Array.prototype
0

Is this an alternative to what you are seeking ? Try it.

<script type="text/javascript">"use strict";
  function formBuddy() {
      this.fields = new Array();
      this.labels = new Array();
      this.rules = new Array();
      this.count=0;

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

  var cForm = new formBuddy();

  // FILLING IN THE DATABASE
  cForm.addField("c_first_name","Diasoluka","duplicated");
  cForm.addField("c_Middle_name","Nz","inspect");
  cForm.addField("c_last_name","Luyalu","mandatory");
  cForm.addField("c_first_name","Diasoluka","duplicated");


  console.log(`ACCESSING EACH PROPERTY INDIVIDUALLY\n,${'.'.repeat(31)}`);

  let el=Object.entries(cForm.fields); // DESTRUCTURING
      console.log(Object.is(el,Object.entries(cForm.fields)));
      // false

  const [f1,f2,f3] = el; // DESTRUCTURING=DÉCOMPOSITION
  console.log("FIELDS:\n",f1," | ",f2," | ",f3,"\n\n");
  // FIELDS:
    // Array [ "0", "c_first_name" ]
    // Array [ "1", "c_Middle_name" ]
    // Array [ "2", "c_last_name" ]

  let labels = Object.entries(cForm.labels); // DESTRUCTURING
  const [l1,l2,l3] = labels; // DESTRUCTURING
  console.log("LABELS:\n",l1," | ",l2," | ",l3,"\n\n");
  // LABELS:
    // Array [ "c_first_name", "Diasoluka" ]
    // Array [ "c_Middle_name", "Nz" ]
    // Array [ "c_last_name", "Luyalu" ]

  let rules = Object.entries(cForm.rules); // DESTRUCTURING
  const [r1,r2,r3] = rules; // DESTRUCTURING
  console.log("RULES:\n",r1," | ",r2," | ",r3,"\n\n");
  // RULES:
    // Array [ "c_first_name", "duplicated" ]
    // Array [ "c_Middle_name", "inspect" ]
    // Array [ "c_last_name", "mandatory" ]


  console.log(`PAESING THE DATABASE =\nACCESSING ALL THE FIELDS AT ONCE\n,${'.'.repeat(31)}`);

  for(let key in cForm.fields){
    let el=cForm.fields[key]; // ASSIGNMENT=AFFECTATION
        console.log(Object.is(el,cForm.fields[key]));
        // true true true true

    console.log(`${el} // ${cForm.labels[el]} // ${cForm.rules[el]}\n`);
  }
  // c_first_name // Diasoluka // duplicated
  // c_Middle_name // Nz // inspect
  // c_last_name // Luyalu // mandatory
  // c_first_name // Diasoluka // duplicated


  console.log("\n");


  console.log(`THE INNER STRUCTURE OF OUR cForm OBJECT\n,${'.'.repeat(31)}`);
  console.log(Object.entries(cForm)); // DESTRUCTURING
  // (5) [Array(2), Array(2), Array(2), Array(2), Array(2)]
    // 0: (2) ['fields', Array(4)]
    // 1: (2) ['labels', Array(0)]
    // 2: (2) ['rules', Array(0)]
    // 3: (2) ['count', 4]
    // 4: (2) ['addField', ƒ]
    // length: 5
    // [[Prototype]]: Array(0)
</script>

1 Comment

Some explanation for your code would be appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.