1

Basically I'm trying to create an object that manages my form. I've done this by creating a js constructor for that object and then creating a few prototypes that execute operations on that object. The issue i'm encountering is that other prototype functions are being executed when I execute the save prototype. Notice that I never actually call validate but none the less it gets called. I've put together this jsFiddle and the issue I'm seeing can be identified by putting a breakpoint in the validate function.

https://jsfiddle.net/w4xhxpo3/15/

<input type="button" id="saveBtn" value="save"/>

var stuff = {}

$(function() {
  stuff = new Test(1, 'testName')
});

function Test(id, name)
{
  this.id = id,
  this.name = name

  this.save();
}

Test.prototype.save = function(){
  var _self = this;

  $('#saveBtn').on('click', function() {
    $.post("/echo/json/", _self)
      .done(function(){
       alert('success');
   });
 })
}  

Test.prototype.validate = function(){
 var _self = this;
}
Nick Kuin
  • 13
  • 3
  • Why do you pass `_self` to `$.post`?! – Bergi Oct 31 '17 at 22:29
  • Basically what I want to do is create an object that has the ability to execute the crud operations on itself but no external object can access. Turns out that passing _self also executes the prototype chain. I fixed this by putting my id and name in a nested object and passed the nested object into the post. – Nick Kuin Nov 01 '17 at 13:21

1 Answers1

1

This behaviour is intended.

The data argument to $.post(), $.get, $.ajax, ... methods is serialized to a single query string with key=value pairs delimited by &. Internally this serialization is performed with $.param() for which the documentation says:

As of jQuery 1.3, the return value of a function is used instead of the function as a String.

In other words, the methods of the data object are executed, and their return values are used as the values for the corresponding keys. This is true for owned methods and for methods in the prototype chain, as long as they are enumerable.

Workaround 1: Object.assign

If you define your methods only on the prototype, then you can use Object.assign to take a shallow copy of the object, which will not include the prototype members:

$.post("/echo/json/", Object.assign({}, _self))

Workaround 2: non-enumerable methods

If it is not important to you that methods are enumerable or not, then make them non-enumerable. They will then be ignored by jQuery:

Object.defineProperty(Test.prototype, 'validate', {
    enumerable: false,
    value: function() {
        var _self = this;
    }
});

You will need to do the same for the save method, which otherwise also gets called (again!).

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Great answer. I ended up fixing this by adding the id and the name to a nested object called form and passing _self.form as the second parameter of the post. – Nick Kuin Nov 01 '17 at 13:22