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;
};
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;
window
(<script>alert(this.name)</script>
)alert()
), this
points to the window
object(ticket.resolve())
, this
points to the object on the left of the dot (ticket
).new Ticket
), this
is a new empty object that has Ticket.prototype
in its prototype chain.onclick="alert(this.id)"
), this
points to the HTML element where you attached the eventsetTimeout
, setInterval
and AJAX callbacks, this
usually points to window
apply
or call
, you can specify what this
will beFunction.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