19

When I add items to the beats array and then console.log the User, I'm getting the correct number of items in the array. But when I check .length, I always get 1. Trying to call the index will always give me 'undefined' like so: Tom.beats[1] I think I'm missing something obvious, but this is beating me. I suspect that I'm misusing the .push method but I'm unsure. Any help is greatly appreciated! (using Chrome dev tools)

//The USER

function User(name, role){
    this.beats = [ ]; 

    this.name = name;
    this.role = role;

    // add beats to beats array

    this.addBeats = function(beats){ 
        return this.beats.push(beats);
   };

}

// Three New Instances. Three New Users.

var Mal = new User("Mal", "Rapper");
Mal.addBeats(["love", "cash"]);

var Dan = new User("Dan", "Producer");
Dan.addBeats(["cake", "dirt", "sally-mae"]);

var Tom = new User("Tom", "Producer");
Tom.addBeats(["Fun", "Little", "Samsung", "Turtle", "PC"]);

// Check for position in beats array

console.log(Tom.beats); 
console.log(Mal.beats); 
console.log(Dan.beats); 

console.log(Mal.beats[1]);
console.log(Dan.beats[1]);
console.log(Tom.beats[1]);
Kijewski
  • 25,517
  • 12
  • 101
  • 143
MFrazier
  • 400
  • 1
  • 5
  • 10
  • I wonder if the `this` pointer is getting confused in the addBeats function. Can you step-through it in a JS debugger? (IE9 has one). – Dai Jun 17 '12 at 23:43

3 Answers3

52

Array.push(...) takes multiple arguments to append to the list. If you put them in an array itself, this very array of "beats" will be appended.

Array.concat(...) is most likely not what you are looking for, because it generates a new array instead of appending to the existing one.

You can use [].push.apply(Array, arg_list) to append the items of the argument list:

this.addBeats = function(beats) { 
    return [].push.apply(this.beats, beats);
};
Kijewski
  • 25,517
  • 12
  • 101
  • 143
  • Using your, method, it works how I intended now. Thanks! So, my return line was totally incorrect... – MFrazier Jun 18 '12 at 01:13
  • 4
    `[].push` will create a new array each time a function is called. I guess it’s cheaper to use `return this.beats.push.apply(this.beats, beats)` instead. – Alexander Kachkaev Aug 07 '14 at 23:25
  • 2
    @AlexanderKachkaev, actually, no: http://jsperf.com/nil-push/2. Using `[].someFunction.call`, `{}.someFunction.apply`, etc. is a pattern that at least Firefox and Chrome understand and optimize. Using `[].push`, instead of `variable.push` or `Array.prototype.push` is a little faster, since it won't involve a lookup for the variable name. – Kijewski Aug 08 '14 at 00:10
  • 1
    @Kay it'd be nice of jsperf gave a profile of the memory consumption as well. The additional fraction of a percentage performance benefit might be offset by garbage collection deferred to a later time? (This kind of optimization might explain why Gmail takes up more RAM than my Java IDE if I leave its tab open for a few days?!) – David Bullock Nov 11 '14 at 02:56
  • 2
    Note: one year later my statement is not true anymore. `Array.prototype.push.apply` is by 10% or so faster in Firefox v44 and Chrome v46. – Kijewski Nov 13 '15 at 15:59
11

Spread operator

In environments that support the spread operator you may now do the following:

this.addBeats = function (beats) {
    return this.beats.push(...beats);
};

Or if you need more control for overwriting etc

this.addBeats = function(beats) { 
    return this.beats.splice(this.beats.length, null, ...beats);
};
Ashley Coolman
  • 11,095
  • 5
  • 59
  • 81
1

addBeats() should concat this.beats with the beats parameter.

jmulligan
  • 104
  • 1