当对象从服务器发送到客户端时,JS原型方法消失

时间:2016-04-27 17:49:29

标签: javascript node.js

我使用节点服务器将一些对象发送到我的前端代码。我使用原型为我的对象添加了一些方法,但是当我将它们发送到前端时,原型方法就消失了。对象仍然具有原型方法名称的属性,但该值已设置为undefined。有没有办法可以在客户端恢复原型方法?

我的代码如下所示:

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'
});

2 个答案:

答案 0 :(得分:3)

对象通过jQuery Ajax作为JSON(纯文本格式)发送。 JSON将序列化对象的对象属性,但是当它被转换回另一端的对象时,它将被转换为普通的JS对象,而不是任何特定类型的对象,因此它不会有任何类型的自定义原型在上面。

JSON格式没有用于捕获对象类型的内置机制,因此保留了原型方法。因此,当您将JSON解析回另一端的对象时,您不会获得原型。

此外,JSON不会序列化函数/方法,只能序列化数据。

像你这样的案例通常的解决方法是发送一个普通值数组。接收端知道它将接收一个普通的值数组。如果它想要那个值数组,在Class个对象中,那么它将采用该数组并构造一个用适当数据初始化的Class个对象数组。

$.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());
});

更好的办法是将服务器代码更改为只发送一个简单的数据值数组,而不是一个对象数组,因为它只是不必要的开销。

答案 1 :(得分:1)

这是因为在字符串化类对象时,Javascript不会考虑原型属性。

如果您JSON.stringify(new Class(2)) {"value":2},则会看到toJSON

为此,您应该提供Class.prototype.toJSON = function() { return { value: this.value, isEven: this.isEven } } 方法,该方法在对字符串进行字符串化时调用,如下所示:

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

但是如果你这样做,你会发现该功能还没有显示出来。为什么?这是因为函数不能被字母化为JSON,因为JSON中不存在函数。

您可以在this answer中看到函数远远超过其代码。

要解决这个问题,您只需获取函数的值即可:

public void DrawLetter() {
    new AsyncTask<Void, Void, Bitmap>() {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }
        @Override
        protected Bitmap doInBackground(Void... params) {
            Draw(); 
            Draw2();
            return currentBitmap;
        }
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if(bitmap!=null) {

                loadImageToImageView();
            }
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);


}