1

I found a strange behavior when I cloned simple JSON objects with property that's name is "must" when the unit.js library is used. See the example:

var test = require("unit.js"); // delete this line and the result will be good

var input = {
    "parameter": "value",
    "must": {
        "parameter_in": "value_in"
    }
};

console.log("Input: " + JSON.stringify(input, undefined, 2));
var result = clone(input);
console.log("Result: " + JSON.stringify(result, undefined, 2)); // no "must" element
console.log("Result (must): " + JSON.stringify(result.must, undefined, 2));

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Result:

Input: {
  "parameter": "value",
  "must": {
    "parameter_in": "value_in"
  }
}
Result: {
  "parameter": "value"
}
Result (must): {
  "parameter_in": "value_in"
}

The JSON.stringify doesn't print the must property of result, but it is in the cloned object because JSON.stringify is working for result.must. If I delete the unit.js line, everything is ok. (I use unit.js@0.1.8)

What is the reason of this, does unit.js add something to Object.prototype? Whatever it is, is it a way to protect our application against this kind of errors? It's very strange that a 3rd party library can cause such an error.

Any help would be appreciated!

Ps.: I used the clone function suggested in How do I correctly clone a JavaScript object? but it's also the same with lodash's cloneDeep method.

Update:

I've tried some more queries: use for in, in, hasOwnProperty on the result:

console.log("\"must\" is in: " + ('must' in result));
console.log("\"must\" is with hasOwnProperty: " + result.hasOwnProperty("must"));
console.log("In properties:");
for (var property in result){
    console.log("\tproperty: " + property);
}

The result with unit.js:

"must" is in: true
"must" is with hasOwnProperty: true
In properties:
        property: parameter

So the must attribute doesn't appear only in the for in loop.

Community
  • 1
  • 1
Zoltan Balogh
  • 258
  • 3
  • 8

1 Answers1

1

I've asked it on unit.js's github page and thanks to Nicolas Talle I've got the proper answer.

As a summary it happens because must is added as non enumerable property by MustJS (the same is with should by ShouldJS). We can get rid of this by adding:

delete Object.prototype.must;
delete Object.prototype.should;

For detailed answer see the issue: https://github.com/unitjs/unit.js/issues/6

The documentation of Unit.js is also extended according to this: http://unitjs.com/guide/must-js.html

Zoltan Balogh
  • 258
  • 3
  • 8