3

I'm using a node server to send some objects to my front end code. I've added some methods to my objects using a prototype, but when I send them to the front end the prototype method disappears. The objects still have a property with the prototype method name, but the value has been set to undefined. Is there a way that I can recover the prototype method on the client side?

My code looks like the following:

server.js

function Class (data) {
  this.value = data;
}

Class.prototype.isEven = function() {
  return this.value % 2 === 0;
};

app.get('/data', function(req, res) {
  db.query('select * from table', function(err, rows, fields) {
    var items = [];
    for (var i = 0; i < rows.length; i++) {
      items.push(
        new Class(rows[i]['value'])
      );
    }
    res.send(items);
  });
});

client.js

$.ajax({url: "/data", type: "GET", success: function(data) {
  var item = data[0];
  console.log(item.isEven); // displays 'undefined'
});
Derek Pollard
  • 6,953
  • 6
  • 39
  • 59
Copernicus
  • 291
  • 1
  • 2
  • 13

2 Answers2

4

Objects are sent via jQuery Ajax as JSON (a plain-text format). JSON will serialize the object properties on your objects, but when it is converted back into an object on the other end, it will be converted into plain JS objects, not into any particular type of object so it will not have any sort of custom prototype on it.

The JSON format does not have a built-in mechanism for capturing the type of an object and thus preserving prototyped methods. Thus, you don't get the prototype when you parse the JSON back into an object on the other end.

In addition, JSON does not ever serialize functions/methods, only data.

The usual work-around for a case like yours is to just send an array of plain values. The receiving end knows it will be receiving a plain array of values. If it wants that array of values, to be in Class objects, then it will take that array and construct an array of Class objects that are initialized with the appropriate data.

$.ajax({url: "/data", type: "GET", success: function(data) {
  // convert array of plain objects into array of Class objects
  var items = data.map(function(item) {
      return new Class(item.value);
  });
  console.log(items[0].isEven());
});

Even better would be to change the server code to just send a plain array of data values, not an array of objects since that it just unnecessary overhead.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

It's because prototyped properties aren't considered by Javascript when stringify an class object.

If you did JSON.stringify(new Class(2)) you'll see {"value":2}.

For that, you should provide the toJSON method, which is called when you stringify an object, like this:

Class.prototype.toJSON = function() {
    return {
        value: this.value,
        isEven: this.isEven
    }
}

But if you do this, you'll see that the function isn't showing up yet. Why? It's because functions cannot be stringified as JSON, because doesn't exists functions in JSON.

Functions are much more than their code, as you can see in this answer.

To fix that, you can simply get the value of the functions, doing this:

Class.prototype.toJSON = function() {
    return {
        value: this.value,
        isEven: this.isEven.toString()
    }
}
Community
  • 1
  • 1
daymannovaes
  • 1,416
  • 12
  • 23