I don't think there's such thing because I guess I would have found it by now but the only way to be certain is to be given a straight answer, therefore I must ask before I give up. I need a method that's going to be called every time I try to access an object's method. Is there such a thing in JavaScript?
Basically I need to run a couple of lines before and after each of my object's methods. Hardcoding them is really not an option. The other thing I thought of was to have a main method like
Mainmethod(ActualMethod, Parameters)
But this really doesn't look good to me, I'd really like not having to do this.
If this is just for a particular object or a particular type of object, you can dynamically replace all the methods with your own stub that does your pre-work, calls the original method and then does your post-work.
Something like this will work:
function overideMethods(obj) {
// can pass either an instantiated object (hooks existing methods on the object)
// or a function constructor (hooks methods in the prototype)
if (typeof obj === "function") {
obj = obj.prototype;
}
for (var prop in obj) {
if (typeof obj[prop] === "function") {
(function(origMethod) {
obj[prop] = function() {
var retVal, args;
// do your pre-work here
// make copy of args passed to this method
args = Array.prototype.slice.call(arguments, 0);
// call original method with proper args
retVal = origMethod.apply(this, args);
// do your post-work here
return retVal;
};
})(obj[prop]);
}
}
}
Working demo: http://jsfiddle.net/jfriend00/7LzQj/
You can now pass this function either an object or a constructor function. If you pass it an object, it will hook the existing enumerable methods on that object. If you pass it a constructor function, it will hook the methods on the constructor's prototype. This allows you to set up the hooks for all objects made from an entire constructor (in advance) or just hook an individual object.
If your object adds methods dynamically, either in the constructor or later in the life of the object and you want those methods hooked, then you will need to call overideMethods() on the object AFTER those methods are added - you will not be able to just call it on the constructor.
Here's a possible solution with function decorators. If you have something like Underscore at hand you can trim the code a bit, but I'm assuming you don't.
A decorator is a higher-order function that returns a modified version of another function. Decorators are a safer approach to monkey patching in some situations but it all depends on your needs.
Here's a demo: http://jsbin.com/ApaLAVab/1/edit
function compose(f, g) {
return function() {
return f(g.apply(this, arguments));
};
}
function before(fn) {
return function() {
console.log('before'); // code before method
fn.apply(this, arguments);
};
}
function after(fn) {
return function() {
fn.apply(this, arguments);
console.log('after'); // code after method
};
}
var run = compose(before, after);
function A() {}
A.prototype = {
say: run(function(name) { // decorate method
console.log('Hello '+ name);
})
};
var a = new A();
a.say('Peter');
//^ before
// Hello Peter
// after
You can also add it to the constructor, so you don't have to run it manually:
function SimpleClass(){
this.overideMethods();
}
SimpleClass.prototype.overideMethods = function() {
var obj = this;
for (var prop in obj) {
if (typeof obj[prop] === "function") {
console.log(prop);
(function(origMethod) {
obj[prop] = function() {
var retVal, args;
// do your pre-work here
alert("before function call");
// make copy of args passed to this method
args = Array.prototype.slice.call(arguments, 0);
// call original method with proper args
retVal = origMethod.apply(this, args);
// do your post-work here
alert("after function call");
return retVal;
};
})(obj[prop]);
}
}
}
SimpleClass.prototype.testFn = function(){
alert("In the function.");
};
var testObj = new SimpleClass();
testObj.testFn();
Working example: http://jsfiddle.net/awesomepeter/wvxAd/1/
Credit to jfriend00 though, i wanted to do the same thing as him just came a little bit too late ;) So i just copypasted his answer and improved.
Related
i have a function. say function createObj() { }
var obj1= new createObj();
var obj2= createObj();
what changes you need to make in the function createObj() to support both above secenario with and without new keyword. Both should work at the same time.
In the function test the type of this and use the new keyword internally, whenever required
function createObj()
{
if ( !(this instanceof createObj) )
return new createObj();
// add existing code of function createObj here ...
}
It's a bit hacky and I don't really recommend doing this but I understand the reasons for why it's sometimes necessary if you need to integrate with some legacy code or transition your API. Here's one way of doing it.
First, we need a way to detect if our function is called with new or not. Now, depending on weather we're in strict mode or not, if it's not called with new then this will either be undefined or the global object. If it's called with new then it will be an instance of the object inherited from the prototype. So here's how we can check:
function createObj () {
if (typeof this == 'undefined' || typeof this.Array == 'function') {
// Not called with `new`
}
else {
// Called with `new`
}
}
Now using this we can properly construct the object:
function createObj () {
var self; // replacement of `this` because what it points to
// depends on the logic below:
if (typeof this == 'undefined' || typeof this.Array == 'function') {
// Not called with `new`
self = Object.create(createObj.prototype); // create object instance
}
else {
// Called with `new`
self = this;
}
// From this point on do things normally except use `self`
// instead of `this`..
// Remember to return `self` at the end for when we are not
// called with `new`:
return self;
}
Now the function can be used as either a constructor or object factory.
Removed the previous answer cause there is a simpler way
Actually there is a simpler way to do that
function o(n, s) {
function inner(n, s){
this.name = n;
this.surname = s;
}
return new inner(n, s);
}
var lee1 = new o('Bruce', 'Lee'),
lee2 = o('Brandon', 'Lee');
console.log(lee1);
console.log(lee2);
I can advice to you to read some books about JavaScript. Object-Oriented JavaScript - Second Edition
And you can use this small example:
function Sample() { // Sample is the constructor function for your objects
return {
prop_1: 'value',
prop_2: 3
}
}
var obj = Sample(); // without new
console.log(obj); // Object { prop_1="value", prop_2=3}
var obj = new Sample(); // with new
console.log(obj); // The same result with new operator: Object { prop_1="value", prop_2=3}
This is possible only if the return value of your constructor is an object
I would like to make a generic function wrapper that (for example) prints the called function and its arguments.
Doing so is easy through the arguments quasi-array and simple calls. For example:
function wrap(target, method) {
return function() {
console.log(Array.prototype.slice.call(arguments).join(', '));
return method.apply(target, arguments);
}
}
However, this way of doing of course completely loses the arity of the called function (if you didn't know, one can obtain the arity (number of arguments) of a JavaScript function through its length property).
Is there any way to dynamically create a wrapper function that would copy the arguments of the wrapped function to itself?
I've thought about creating a new Function object, but I don't see any way to statically extract the arguments list, since the arguments property is deprecated.
Here's a solution using Function:
// could also generate arg0, arg1, arg2, ... or use the same name for each arg
var argNames = 'abcdefghijklmnopqrstuvwxyz';
var makeArgs = function(n) { return [].slice.call(argNames, 0, n).join(','); };
function wrap(target, method) {
// We can't have a closure, so we shove all our data in one object
var data = {
method: method,
target: target
}
// Build our function with the generated arg list, using `this.`
// to access "closures"
f = new Function(makeArgs(method.length),
"console.log(Array.prototype.slice.call(arguments).join(', '));" +
"return this.method.apply(this.target, arguments);"
);
// and bind `this` to refer to `data` within the function
return f.bind(data);
}
EDIT:
Here's a more abstract solution, which fixes the closure problem:
function giveArity(f, n) {
return new Function(makeArgs(n),
"return this.apply(null, arguments);"
).bind(f);
}
And a better one, that preserves context when invoked:
function giveArity(f, n) {
return eval('(function('+makeArgs(n)+') { return f.apply(this, arguments); })')
}
Used as:
function wrap(target, method) {
return giveArity(function() {
console.log(Array.prototype.slice.call(arguments).join(', '));
return method.apply(target, arguments);
}, method.length)
}
Is it possible to get notification from within JavaScript when calling an object's methods?
Example:
o.foo(arg1);
function o_ongenericcall(name, arguements)
{
switch (name)
{
case "foo":
// Do something
break;
}
}
In the above example, o is the object and I would like o_ongenericcall to be raised when any method is trying to be invoked.
You could create a kind of proxy on the object's function calls.
// create a copy of the original function
o.foo_ = o.foo;
// replace the original function with a wrapper that calls the notification
o.foo = function() {
console.log("notify: foo(" + arguments[0] ")");
o_ongenericcall("foo", arguments);
this.foo_.apply(this, arguments);
}
o.foo("testing");
notify: foo(testing)
Note that you could set this up by looping through the object's properties:
for (var member in o) {
if (typeof o[member]=="function") {
console.log(member);
applyNotificationProxy(o, member);
}
}
DEMO
I don't think it can be done natively.
You probably want to implement the Observer Pattern.
This will probably not help you much, but what you need is a Proxy. This is a fairly new and unstable API in Javascript, not yet part of any standard, and is not really supported by any browser. V8 supports proxies, but does not expose that functionality to Chrome; you can however enable them in Node.js by executing it with a --harmony-proxies parameter.
No, this is only possible if you called o_ongenericcall from the foo method.
However, you can easily decorate all methods on an object with that invocation:
function decorated(obj) {
var res = {}; // you might also use obj itself if you don't want to create a new one
for (var p in obj)
if (typeof obj[p] == "function")
(function(orig, p) {
res[p] = function() {
o_ongenericcall(p);
return orig.apply(this, arguments);
};
})(obj[p], p);
else
res[p] = obj[p];
}
obj = decorated({foo:function(){console.log("foo");}});
obj.foo(); // calls o_ongenericcall, then logs "foo"
Check AOP (Aspect Oriented Programming: Wikipedia) then, check this: AOP from Stackoverflow
In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this, args);
}
The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(<otherFn's original context>, args);
}
Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.
class Client
constructor: (socket) ->
#socket = socket
#avatar = socket.handshake.avatar
#listeners = {}
addListener: (name, handler) ->
#listeners[name] ||= {}
#listeners[name][handler.clientListenerId] = wrapper = =>
# append client object as the first argument before passing to handler
args = Array.prototype.slice.call(arguments)
args.unshift(this)
handler.apply(this, args) # <---- HANDLER'S CONTEXT IS CHANGING HERE :(
#socket.addListener(name, wrapper)
removeListener: (name, handler) ->
try
obj = #listeners[name]
#socket.removeListener(obj[handler.clientListenerId])
delete obj[handler.clientListenerId]
Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.
If I understand you correctly:
changes context
| n | y |
accepts array n | func() | func.call() |
of arguments y | ???????? | func.apply() |
PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().
Function.prototype.invoke = function(args) {
var i, code = 'this(';
for (i=0; i<args.length; i++) {
if (i) { code += ',' }
code += 'args[' + i + ']';
}
eval(code + ');');
}
Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.
Proof that it works:
function showArgs() {
for (x in arguments) {console.log(arguments[x]);}
}
showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);
Firefox console output:
--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]
Simply put, just assign the this to what you want it to be, which is otherFn:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(otherFn, args);
}
'this' is a reference to your function's context. That's really the point.
If you mean to call it in the context of a different object like this:
otherObj.otherFn(args)
then simply substitute that object in for the context:
otherObj.otherFn.apply(otherObj, args);
That should be it.
If you bind the function to an object and you use everywhere the bound function, you can call apply with null, but still get the correct context
var Person = function(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log("Name: " + this.name);
}
var bob = new Person("Bob");
bob.printName.apply(null); //window.name
bob.printName.bind(bob).apply(null); //"Bob"
One way that you can work around the change of context that can happen in JavaScript when functions are called, is to use methods that are part of the object's constructor if you need them to be able to operate in a context where this is not going to mean the parent object, by effectively creating a local private variable to store the original this identifier.
I concede that - like most discussions of scope in JavaScript - this is not entirely clear, so here is an example of how I have done this:
function CounterType()
{
var counter=1;
var self=this; // 'self' will now be visible to all
var incrementCount = function()
{
// it doesn't matter that 'this' has changed because 'self' now points to CounterType()
self.counter++;
};
}
function SecondaryType()
{
var myCounter = new CounterType();
console.log("First Counter : "+myCounter.counter); // 0
myCounter.incrementCount.apply(this);
console.log("Second Counter: "+myCounter.counter); // 1
}
These days you can use rest parameters:
function fn(...args) {
otherFn(...args);
}
The only downside is, if you want to use some specific params in fn, you have to extract it from args:
function fn(...args) {
let importantParam = args[2]; //third param
// ...
otherFn(...args);
}
Here's an example to try (ES next version to keep it short):
// a one-line "sum any number of arguments" function
const sum = (...args) => args.reduce((sum, value) => sum + value);
// a "proxy" function to test:
var pass = (...args) => sum(...args);
console.log(pass(1, 2, 15));
I'm not going to accept this as an answer, as I'm still hoping for something more suitable. But here's the approach I'm using right now based upon the feedback on this question so far.
For any class that will be calling Client.prototype.addListener or Client.prototype.removeListener, I did added the following code to their constructor:
class ExampleClass
constructor: ->
# ...
for name, fn of this
this[name] = fn.bind(this) if typeof(fn) == 'function'
message: (recipient, body) ->
# ...
broadcast: (body) ->
# ...
In the above example, message and broadcast will always be bound to the new ExampleClass prototype object when it's instantiated, allowing the addListener code in my original question to work.
I'm sure some of you are wondering why I didn't just do something like the following:
example = new ExampleClass
client.addListener('message', example.bind(example))
# ...
client.removeListener('message', example.bind(example))
The problem is that every time .bind( ) is called, it's a new object. So that means that the following is true:
example.bind(example) != example.bind(example)
As such, the removeListener would never work successfully, thus my binding the method once when the object is instantiated.
Since you seem to want to be using the bind function as it is defined in Javascript 1.8.5, and be able to retrieve the original this object you pass the bind function, I recommend redefining the Function.prototype.bind function:
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
/** here's the additional code **/
fBound.getContext = function() {
return oThis;
};
/**/
return fBound;
};
Now you can retrieve the original context that you called the bind function with:
function A() {
return this.foo+' '+this.bar;
}
var HelloWorld = A.bind({
foo: 'hello',
bar: 'world',
});
HelloWorld(); // returns "hello world";
HelloWorld.getContext(); // returns {foo:"hello", bar:"world"};
I was just reminded of this question after a long time. Looking back now, I think what I was really trying to accomplish here was something similar to how the React library works with its automatic binding.
Essentially, each function is a wrapped bound function being called:
function SomeClass() {
};
SomeClass.prototype.whoami = function () {
return this;
};
SomeClass.createInstance = function () {
var obj = new SomeClass();
for (var fn in obj) {
if (typeof obj[fn] == 'function') {
var original = obj[fn];
obj[fn] = function () {
return original.apply(obj, arguments);
};
}
}
return obj;
};
var instance = SomeClass.createInstance();
instance.whoami() == instance; // true
instance.whoami.apply(null) == instance; // true
Just push properties directly to the function's object and call it with it's own "context".
function otherFn() {
console.log(this.foo+' '+this.bar); // prints: "hello world" when called from rootFn()
}
otherFn.foo = 'hello';
otherFn.bar = 'world';
function rootFn() {
// by the way, unless you are removing or adding elements to 'arguments',
// just pass the arguments object directly instead of casting it to Array
otherFn.apply(otherFn, arguments);
}
I have this class where I have a private property and a public method for access:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) { //Get
return this.Name
} else {
this.Name = value; //Set
}
};
return _public;
};
I want to force the context in _public.Name for access a this.Name.
I know the technique of closure, but I want to see if I can force a context.
I found a technique to do it, extend object Function:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
f().apply(scope);
}
}
And my class becomes:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return this.Name
} else {
this.Name = value;
}
}.setScope(this);
return _public;
};
So I can force correctly the context, but I can not pass value and can not, however, return this.Name.
Not
f().apply(scope);
just
f.apply(scope);
(No () after f.) You want to use the apply function on the function f object, not call the function f and access apply on its return value.
To also pass on the arguments that your function in setScope receives, add this:
f.apply(scope, arguments);
arguments is an implicit argument to all functions, which is a pseudo-array of the actual arguments passed to the function at runtime. apply accepts any array-like thing as its second parameter to specify the arguments to use when calling the underlying function.
I'd also have it return the return value:
return f.apply(scope, arguments);
So setScope becomes:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
return f.apply(scope, arguments);
}
}
Live example
Note that the usual name for this function, and the name it has in the new ECMAScript5 standard, is bind (Section 15.3.4.5; ECMAScript5's bind also lets you curry arguments, which isn't done by this implementation). setScope is a particularly unfortunate name, because it doesn't set the scope, it sets the context.
Having said all that, there's no reason you need setScope in your Person constructor. You can just do this:
Person = function () {
var self = this;
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return self.Name;
} else {
self.Name = value;
}
};
return _public;
};
Live example
But using bind (aka setScope) can be useful in places where you don't want a new closure over the context in which you're doing it.
Off-topic: The way you're specifying Person will break certain things people might expect to work, such as:
var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
...because you're replacing the object new created for you, but returning a different object out of your constructor (which overrides the default).
Rather than creating a new object and returning that in your constructor, allow the object constructed for you by new to be the object (and thus the Person relationship is maintained), but you can still get truly private variables and use accessors:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = function(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
};
}
Live example
As you can see, this is dramatically simpler, and it preserves the instanceof relationship. Note that we're not qualifying our references to name within Name at all, and so we're using the local variable in the constructor call in which our Name function, which closes over it, was created.
I've also taken the liberty there of giving the constructor function a name, because I'm not a fan of anonymous functions. I should have given the accessor a name as well:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = Person_Name;
function Person_Name(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
}
}
Off-topic 2: The overwhelming convention in JavaScript code is to use initial caps on function names only for constructor functions (like Person), and not on other kinds of functions (like Name). You're free to do whatever you like, of course, but I thought I'd mention the convention, as it makes it easier for other people to read your code.
Worth noting: All of these techniques result in every single Person object having its own copy of the accessor function. If there are going to be a lot of these objects, that could be a memory issue. If there are only going to be a few, that's fine.
First thing, I think the correct way to go about this is the "closure" method, as the syntax is easier and simpler to understand and makes more sense and most object oriented code written in Javascript is written that way. Another thing to note is that in your method, the "private" member can be accessed from outside by accessing Person.Name (instead of (new Person()).Name).
That being said, it seems that you want something like Prototype.JS's bind method, which allows you to bind a function reference as a method call to a specific object, and also passes all the arguments correctly (including allowing preloaded arguments).
Look at Prototype.JS source for the complete implementation, but a simple implementation of this semantic might look like this:
Function.prototype.bind = function(context) {
var callee = this;
var args = Array.prototype.slice.call(arguments,1);
return function() {
var newargs = args.concat(Array.prototype.slice.call(arguments,0));
return callee.apply(context, newargs);
};
};
It is difficult to understand what you are trying to achieve. But if I guess that you are trying to create a Person class with a name method to get/set the person's name, here is my suggestion:
function Person() {
this._name = undefined; // not required but is better than assigning a fake name
return this;
}
Person.prototype.name = function( _name ) {
if ( _name === undefined ) return this._name; // get
return this._name = _name; // set
}
Note that I have defined the name function with a lower case first letter. This is standard practice in JavaScript where only constructors are usually capitalized. To use this class you do:
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"
There is no need to bind any context with this method, so you may be looking for something else. If you can clarify your need, I'll be happy to edit my answer.
I hope this helps.