2

Cannot reproduce MDN's example («Using an object in an array-like fashion»).

  let obj = {
    length: 0,
    addEl: function (element) {
       [].push.call(this, element);
    };
  };
  // Node REPL still expect me to do something, so there's an error. Why?

Could you, guys, explain what's wrong here? Also it seems that I don't get the point with the mechanics here:

// from the example:
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2

What if we call the function with some different agrument, not {}, will it work? And if it won't, then why we should use {} exactly? What is the this context here: addEl method or the object itself? If the second, why not addEl function: it's not an array function, so it should have its own this (and, I guess, I'd use something like objThis = this; property).

One more related question is here.

JulyMorning
  • 531
  • 1
  • 4
  • 8

3 Answers3

3

The code in your post has some typos:

  let obj = {
    length: 0,
    addEl: function (element) {
       [].push.call(this, element);
    };
     ^ syntax error
  };
  // Node REPL still expect me to do something, so there's an error. Why?

As you suspected in your comment in the code, there is a syntax error, which I marked for you. Remove that semicolon.

And then, when trying the example you wrote obj.addElem, but in the above object literal you have addEl.

The example should work just fine, if you simply copy-paste it.

var obj = {
    length: 0,

    addElem: function addElem(elem) {
        // obj.length is automatically incremented 
        // every time an element is added.
        [].push.call(this, elem);
    }
};

// Let's add some empty objects just to illustrate.
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2

What if we call the function with some different argument, not {}, will it work?

Sure it will. Why wouldn't it? An array in JavaScript can contain values of different types. It doesn't need to be homogeneous, so yes, you can insert other things than {}.

What is the this context here: addEl method or the object itself?

It's the object on which the method is called. So it's obj. This is how method invocation works. When you call obj.something(), the this inside something will be the obj.


If you still have some doubts about this example, feel free to drop a comment.

janos
  • 120,954
  • 29
  • 226
  • 236
  • Maybe it's silly, but why there's no need in semicolons here? I thought, it's needed in every statement (putting aside the fact, that JS-engines can predict their positions by themselves). – JulyMorning Oct 08 '17 at 14:07
  • 1
    @JulyMorning that's not a statement, but an object literal. An analogous example where you might see better is `{ a: 1, b: 2;}`, which is incorrect, the `;` should not be there. After the object literal, to terminate a statement, you should of course put a semicolon, for example `var obj = { a: 1, b: 2 };` – janos Oct 08 '17 at 14:59
  • could you, please, take a look @ my edits in the question? – JulyMorning Oct 08 '17 at 18:52
  • @JulyMorning Please, don't ask a new question in this question. Your original question was answered. If you have a new question, post a new question, do not change this question anymore. – janos Oct 08 '17 at 19:05
  • alright, I won't, but they relate so close between each other… sorry. Just wanna know how does this patter work. – JulyMorning Oct 08 '17 at 19:31
  • @JulyMorning It's not so close. It will be better to post a new question, where you paste the example verbatim from MDN, and then ask your new questions about why and how the example works. – janos Oct 08 '17 at 19:36
2

Since an object is not an array, but can behave like an array you need to borrow push from the Array object.

But in this case this refers to the array object created with the shorthand []. So we need to change this into the scope for obj using call.

Because there is a length property defined, push will update this value.

An empty object is passed as an element {}, but any other will do:

let obj = {
  length: 0,
  addEl: function(element) {
    Array.prototype.push.call(this, element); //also borrowing push from the array.prototype prevents an extra array to be made in memory every time we call upon this function.
  } //« fixed the typo here
};

obj.addEl({});
obj.addEl(1);
obj.addEl('a');
obj.addEl(true);
console.log(obj);
Mouser
  • 13,132
  • 3
  • 28
  • 54
  • Is `[]` a proper way to shorten «Arryay.prototype» for every case? Or, may be, for every calling/binding function? – JulyMorning Oct 08 '17 at 18:29
  • 1
    `[]` is a shorthand for `new Array()`. When you use an array like object such as a nodelist or an object with properties you sometimes want to use array functions on them. However Object does not have functions like forEach and push. So we turn to the master object `Array` and use it's prototype to borrow its functionality. However if we simply did `Array.prototype.push(element)` it would try to add element to the Array master object and fail. So we must link our object to push passing its reference using call or bind. – Mouser Oct 08 '17 at 19:02
1
var array = {
    length: 0,
    push: function(obj){
        this[this.length] = obj;
        this.length++;
    }
}

array.push(23);

You can try this, this solves your problrm i guess.

Gautam
  • 815
  • 6
  • 15