3

I have an array of objects containing references (bound by the .bind() method) to my class functions. When I access them directly, like array[3].myFunction, everything works fine. But the strange behavior occurs when I try to access these function iterating over the array. I've tried by Array.forEach(), for-in, for-of and Array.map() function, but the result is always the same - I get the first function four times. What am I doing wrong here? Thanks in advance.

var Container = function() {
  this.function1 = function() {
    console.log('function 1 invoked');
  };
  this.function2 = function() {
    console.log('function 2 invoked');
  };
  this.function3 = function() {
    console.log('function 3 invoked');
  };
  this.function4 = function() {
    console.log('function 4 invoked');
  };
  
  this.array = [
    { key: '1', myFunction: this.function1.bind(this) },
    { key: '2', myFunction: this.function2.bind(this) },
    { key: '3', myFunction: this.function3.bind(this) },
    { key: '4', myFunction: this.function4.bind(this) },
  ];
};

var container = new Container();

// Just printing the results below
console.log('direct access:');
console.log(container.array[3].myFunction);

console.log('forEach:');
container.array.forEach(el => {
  console.log(el.myFunction);
});

console.log('for in:');
for (let i in container.array) {
  console.log(container.array[i].myFunction);
}

console.log('map:')
container.array.map(el => {
  console.log(el.myFunction);
});

PLNKR: http://plnkr.co/edit/mn8iGh4F3GcJXTNWXMiJ?p=preview

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Daniel Kucal
  • 8,684
  • 6
  • 39
  • 64
  • 1
    Since you're not actually calling these functions, all I get is `function () { [native code] }` (a bound function object) every time. With no way to distinguish it from the others. – Bergi Nov 22 '16 at 00:42
  • 4
    If you actually call the function in those loops, not just log the function itself, the expected output occurs. My guess is a bug in `toString()`, at least in my Chrome version. You might want to point out that in Chrome, at least, it shows the function body for `function1` every time. – Jacob Nov 22 '16 at 00:42
  • @Bergi see the result i.e. in the Chrome console – Daniel Kucal Nov 22 '16 at 00:43
  • 1
    Chrome has some lazy evaluation stuff going on in its dev tools. Similar bug for arrays mentioned here: http://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays – Jacob Nov 22 '16 at 00:45
  • @Jacob, yes it works when I call them directly. But in my project there are passed further... Edit: Thanks, that's a trail! – Daniel Kucal Nov 22 '16 at 00:45
  • 1
    I really think Chrome is just making you think the functions are the wrong values; it just has a buggy console. Try running in Firefox. – Jacob Nov 22 '16 at 00:46
  • 1
    @DanielKucal This only happens in Chrome, try a different browser. Seems to be a bug with the devtools inspector indeed. You might want to report it to Google. – Bergi Nov 22 '16 at 00:48
  • 1
    @Jacob that question shouldn't be relevant, since it deals with multiple logs of the same (but mutated) object. We do have distinct function instances in this example. – Bergi Nov 22 '16 at 00:49
  • Interestingly, at least in my version of Chrome, it logs the correct function if you log the element first, like `console.log(el,el.myFunction);` or in the `for .. in` case, if you log `i` first. – Paul Nov 22 '16 at 00:53
  • Thank you both @Bergi and Jacob. I reported the bug to Google. – Daniel Kucal Nov 22 '16 at 01:03

1 Answers1

0

Have a look below. All seems to be working.

When you do console.log(el.myFunction), it will actually print the handle and not executing it where all handle looks same as function () { [native code] }

When you invoke the function instead el.myFunction(), you can see all they are calling the right functions and print the results respectively.

You can check the function invocation below.

var Container = function() {
  this.function1 = function() {
    console.log('function 1 invoked');
  };
  this.function2 = function() {
    console.log('function 2 invoked');
  };
  this.function3 = function() {
    console.log('function 3 invoked');
  };
  this.function4 = function() {
    console.log('function 4 invoked');
  };
  
  this.array = [
    { key: '1', myFunction: this.function1.bind(this) },
    { key: '2', myFunction: this.function2.bind(this) },
    { key: '3', myFunction: this.function3.bind(this) },
    { key: '4', myFunction: this.function4.bind(this) },
  ];
};

var container = new Container();

// Just printing the results below
console.log('direct access:');
container.array[3].myFunction();

console.log('forEach:');
container.array.forEach(el => {
  el.myFunction();
});

console.log('for in:');
for (let i in container.array) {
  container.array[i].myFunction();
}

console.log('map:')
container.array.map(el => {
  el.myFunction();
});
Aruna
  • 11,959
  • 3
  • 28
  • 42