Question

Is it safe, when creating a custom object, to give it methods (in my current case, "read", "write" & "save") that overwrite native js functions?

The object in question will never have to write to the DOM (or otherwise use the function(s) it'd be losing); these method names are just ideal, so I got curious, and then was surprised to have a hard time finding a clear answer to this. Example below. Thanks.

/**
 * Ticket class
 * @param category
 * @param issuedBy
 * @param reissuable If true, lock cannot be overridden by the same method that locked it
 * @returns {Ticket}
 * @constructor
 */
Ticket = function (category, issuedBy, reissuable) {
    //properties
    this.id = Date.now().toString();
    this.category = category;
    this.resolved = false;
    this.issuingMethod = issuedBy;
    this.reissuable = reissuable === true;
    this.data = {};

    //methods
    this.resolve = function () { return this.resolved = true;};
    this.read = function (dataPath) { // find dataPath in this.data }
    this.write = function (dataPath, value) { // add value to dataPath of this.data}

    return this;
};
Was it helpful?

Solution

It's not completely safe. When your constructor is called without new, this points to the global object.

var ticket = Ticket(); //this.document will point to the global document object

They key to understanding your code is that it uses this which is a special keyword that can mean different things;

  • When not within a function, it means window (<script>alert(this.name)</script>)
  • When called as a standalone function without an object attached to it, (alert()), this points to the window object
  • When called with dot syntax (ticket.resolve()), this points to the object on the left of the dot (ticket).
  • When called as a constructor (new Ticket), this is a new empty object that has Ticket.prototype in its prototype chain.
  • When called from inline HTML handlers(onclick="alert(this.id)"), this points to the HTML element where you attached the event
  • When called from functions like setTimeout, setInterval and AJAX callbacks, this usually points to window
  • When a function is called using apply or call, you can specify what this will be
  • You can usually use Function.bind to make sure your function is called with the right

In the case for calling var ticket = Ticket(), all your code like this.name = 'something' would be creating or overwriting existing global variables, in this case, the name of the window.

If you care about this problem you can mitigate this problem by doing the following.

    Ticket = function (category, issuedBy, reissuable) {
    if (!this instanceof Ticket) { // called as a function
         return new Ticket(category, issusedBy, reissuable);
    }
    //properties
    this.id = Date.now().toString();

To do it in a generic way, you can see this link http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

Note that this would be probably unnecessary boiler plate code and can be avoided by following code conventions and enforcing them

OTHER TIPS

In the provided code sample you aren't overriding any native Object.prototype methods. However, you could potentially override native methods inherited from Object.prototype if you aren't careful.

function MyObject() {}

MyObject.prototype.hasOwnProperty = function () { return true; };

new MyObject().hasOwnProperty('test'); //true

Clearly that would be misleading and in this case I would opt for another function name with a similar meaning in your domain rather than overriding the native Object.prototype.hasOwnProperty function.

It has been said in another answer that calling a constructor without the new keyword could also potentially override global native variables. While this is very true, it will have quite more negative repercussions than only potentially overriding a native global variable. Linting your code (like you should) using great tools such as JSHint will avoid these mistakes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top