1

I would like to do some stuff after before or after new has run.

function F() {

    this.init = function  () { alert(0) }

}

F.prototype.init = function () { alert(1) }

new F().init(); // Will not run mine, because on new F(), init is reassigned within the class.

I understand I can create my own method function Create() { new F().init() }

But I was wondering if there is a way to hook into the new Function call ?

I hope you understand what I mean.

mjs
  • 21,431
  • 31
  • 118
  • 200

3 Answers3

2

new is not a function call, F() is. You could do something like this, replacing F with your own delegate.

function F() {
    this.init = function  () { alert(0) }
}

var oldF = F;
F = function() {
    oldF.apply(this, arguments);
    this.init = function() { alert(1); };
};

new F().init();

If you want a utility function to do this kind of thing:

function wrap(constructor, config) {
    return function() {
        constructor.apply(this, arguments);
        for (var key in config) {
            this[key] = config[key];
        }
    }
}

F = wrap(F, {init: function() { alert(1); }});

or use one of many frameworks/libraries (ExtJS, jQuery, Prototype) that provides this stuff.

Following discussion

This can start you off on what you're trying to do, but I don't guarantee it works in all situations or implementations (only tested on V8). You could pass the context in which F exists as an additional parameter, or make sure you apply/bind/call extend with it.

function extend(constructor, config) {
    this[constructor.name] = function() {
        constructor.apply(this, arguments);
        for (var key in config) {
            this[key] = config[key];
        }
    }
}

extend(F, {init: function() { alert(1); }});
OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • Thanks, exactly my intention! However :( ... Is there a way to do this while not having direct access to the F class, but rather to a parameter ( having it passed ) ... function ( clazz ) { clazz = function () { clazz.apply(this, arguments); this.init(); } ... Is there a way in javascript to set a the reference rathern than the parameter ? :S – mjs Nov 21 '11 at 16:12
  • Not sure what you're asking. How can you not have access to `F` if you're calling `new F()`? – OrangeDog Nov 21 '11 at 19:50
  • What I meant was, I do not have direct access to F. I have a method that takes F, G, H and so on, and I want to do the same for each and one of them. That is why I want to declare a method, that takes a class ( or constructor as you've callin' it ) and rewrites that class. Basically rebind(clazz) { // do the all magic within this method )... So I have access to F through a reference = clazz. I would prefer not to have to return anything, but set the clazz within the method. I understand that this difficult in an OO language. I wish all objects had a method call, obj.replaceMe(...) or something – mjs Nov 22 '11 at 07:18
  • I'm calling it a constructor because that's what it is; there's no such thing as class or method or reference in JavaScript. There's no equivalent in JavaScript to C++ pointers or references, so what you ask is impossible (and also unnecessary). Try reading up on scope and inheritance in JavaScript. – OrangeDog Nov 22 '11 at 09:55
  • Yeah, yeah. Typically for people like yourself to get stuck on semantics which is getting very annoying ( not just from yourself ) . From crockford himself: http://www.crockford.com/javascript/inheritance.html "First, we will make a Parenizor class that will have set and get methods for its value, and a toString method that will wrap the value in parens." I would say that there are mixed usage of words for various things in various languages but you should focus on the intention of my writing and not get hanged up on stuff like that. References doesn't exist in Java either – mjs Nov 22 '11 at 12:47
  • like C POINTERS as you intended to say. You always pass objects by reference in Java. Crockford: http://books.google.com/books?id=PXa2bby0oQ0C&pg=PA22&lpg=PA22&dq=javascript+reference+to+crockford&source=bl&ots=HIniu7u2kI&sig=jRB65MOR_dng7YWnJEBdJE-dk-U&hl=en&ei=jJvLTrWiHY6L4gTr2PxX&sa=X&oi=book_result&ct=result&resnum=10&ved=0CGAQ6AEwCQ#v=onepage&q&f=false "Object are passed around by reference" It is not right to say it is unnecessary as you do not know what I am up to and what I am trying to accomplish. Ok, now I feel a little better but thanks for your initial answer! – mjs Nov 22 '11 at 12:56
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5236/discussion-between-orangedog-and-hamidam) – OrangeDog Nov 22 '11 at 14:07
  • No, that doesnt work in all browsers, constructor.name doesn't exist in IE. But that is not the question I asked an answer for. I've already written the extend part. Now I am just trying to polish the last part. – mjs Nov 23 '11 at 12:07
1

You can use handler.construct() of Proxy to hook the new Operator. Here I alter the arguments passed to the new WebSocket() call:

let WebSocket = require('ws');
// let's hook the new WebSocket(...)
WebSocket = new Proxy(WebSocket, {
  construct: function(target, args, newTarget) {
    // https://github.com/websockets/ws/blob/8.4.0/lib/websocket.js#L51
    let [address, options] = args;  // the original constroctor actually has tree arguments, here we only use 2, to keep it simple

    const extraOptions = createWsOptions(address);

    options = {
      ...options,
      ...extraOptions
    };
    console.log(`options of new Websocket(): ${JSON.stringify(options, null, 2)}`);

    return new target(...[address, options]);
  }
});
ws = new WebSocket(aServer, {
  protocol: 'binary'
});
Iceberg
  • 2,744
  • 19
  • 19
0

Constructors in javascript are just like any other methods, what you're really looking for is AOP in javascript.

See this SO question for some good AOP libraries for javascript.

Community
  • 1
  • 1
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114