Reputation: 1201
I'd like to augment all Objects in my Node.js application with a logging function, such that each object can call this.log
or have its log
function referenced by thatObject.log
. I see a number of advantages in doing this:
log
function so it produces special output, andlog
function is provided, it can find a log
function up its prototype chain, andthis.log
refers to Object.prototype.log
, and in any other context, this.log
refers to that object's log
.For example:
Object.prototype.log = function(message) {
console.log(message);
};
function Person(name) {
this.name = name;
};
Person.prototype.log = function(message) {
console.log(this.name + " says " + message);
};
function Ghost() {
};
var joe = new Person("joe");
joe.log("Hi!"); //"Joe says Hi!"
var boo = new Ghost();
boo.log("Boo!"); //"Boo!"
//I can call this in any object context, and get a context-specific message
//This includes the global context, like so
this.log("Log!"); //"Log!"
Unfortunately, due to limitations in external dependencies, I can't modify Object.prototype (not simply a namespacing issue). Is there a way of doing this without modifying Object.prototype?
Most importantly, I would like to preserve the behaviour of calling this.log
from anywhere.
UPDATE: I've found a workaround for this specific problem. See my answer below.
Upvotes: 2
Views: 104
Reputation: 1201
While I've accepted Oriol's answer as the best answer for the original question, I have found a usable workaround for my specific problem, enabling log
from any context:
log
function in the global scope, enabling this.log
for when this
refers to the global object, andLogger
class with a log
function defined on its prototype.log
functionality have Logger
in the prototype chain somewhere.This isn't ideal, because now classes have to have Logger
in their prototype chain somewhere, either added manually or inherited, but it does ensure the log
function will exist for that class. Implemented in the original example,
function log(message) {
console.log(message);
}
function Logger() {};
Logger.prototype.log = function(message) {
console.log(message);
};
function Person(name) {
this.name = name;
};
Person.prototype = Object.create(Logger.prototype);
Person.prototype.log = function(message) {
console.log(this.name + " says " + message);
};
function Ghost() {
};
Ghost.prototype = Object.create(Logger.prototype);
var joe = new Person("joe");
joe.log("Hi!"); //"Joe says Hi!"
var boo = new Ghost();
boo.log("Boo!"); //"Boo!"
this.log("Log!"); //"Log!"
Upvotes: 0
Reputation: 21965
As Oriol already pointed out, no its not possible. Here are a couple of alternatives:
var log = function(message) {
var msg = message || '';
console.log(JSON.stringify(this) + msg);
}
//later in the code
log.call(this, 'Log!'); //prints the stringified Object plus 'Log!'
another alternative if you use constructor functions would be to have all of them inherit from a constructor function with the desired method (although admittedly that doesn't satisfy your 'even global context' requirement).
Upvotes: 1
Reputation: 288470
If you want to add some property to an object, you can add it as an own property (if you have a reference to the object), or somewhere in its prototypical chain.
In this case, you want to add it to all objects. I think it's reasonable to assume that you don't have references to all of them. So the only way is adding the property in the prototypical chain.
For example, you could add the property to Array.prototype
, Function.prototype
, ...
However, that won't affect objects that don't inherit from those. Specially, an usual way to create objects is using object initializers: {}
. Those objects only inherit from Object.prototype
.
Therefore, for those, Object.prototype
is your only option.
However, that isn't enough. It's possible to create objects that don't inherit from Object.prototype
. For example Object.create(null)
.
So no, it's not possible. And IMO that's a good thing, because you shouldn't pollute objects you don't own.
Upvotes: 4