c24w
c24w

Reputation: 7876

Only call constructor behaviour if particular function isn't called

Apologies - I have no idea to how to describe this. Example:

function OutputNumber(number) {
    this.outputThisInstead = function (otherNumber) {
        console.log(otherNumber);
    }
    console.log(number);
}

Desired usage:


new OutputNumber(1);

Console output: 1


new OutputNumber(1).outputThisInstead(2);

Console output: 2


Naturally, 1 will always be written to the console, irrespective of what else is called on the object.

I'm after this particular syntax, as well as the behaviour - attaching a function onto the initialisation. It feels impossible since the object must be constructed before any function is called on it, but is this achievable any other way?

Upvotes: 1

Views: 66

Answers (3)

T.J. Crowder
T.J. Crowder

Reputation: 1074595

It would be possible with a time delay (e.g., in a browser environment, setTimeout or similar) and a flag. Not desirable, but possible.

Without that, no, you can't base the action of the constructor on something that hasn't happened yet. You'd have to instead pass something into the constructor to let it know what was going on.

Browser example (again, I don't recommend this):

function OutputNumber(number) {
    var handle = 0;
    this.outputThisInstead = function (otherNumber) {
        if (handle) {
            clearTimeout(handle);
            handle = 0;
        }
        console.log(otherNumber);
    }
    handle = setTimeout(function() {
        console.log(number);
    }, 0);
}

From your comment on the question:

This is the end of a sequence of chaining objects/functions, that I'm experimenting with. For example:

Assert.that(1).is.not(2).because('output this message if fails');

Here not(2) returns an object on which because can optionally be called. The behaviour of the object would depend on because being called.

Rather than have the behavior of an earlier function in the chain depend on a later function in the chain, I'd probably add an .end() at the end of something:

Assert.that(1).is.not(2).because('output this message if fails').end();

end would output whatever message/messages was/were stored by the previous functions. No need for black magic. Obviously this suffers from the fact that people could fail to put the .end() on, but you need some kind of trigger that it's okay to do the output, if you want the output to change based on an optional subsequent function call.

Upvotes: 2

Minko Gechev
Minko Gechev

Reputation: 25672

It's possible to declare outputThisInstead as "static":

function OutputNumber(number) {
    console.log(number);
}

OutputNumber.outputThisInstead = function (otherNumber) {
    console.log(otherNumber);
}

new OutputNumber(1); //1
OutputNumber.outputThisInstead(2); //2

But if you want to create an object with the new operator the function will always log the number parameter.

You can also achieve similar behavior to the one you want with partial apply of the function (here). This is also called Currying or Schönfinkeling. The idea is that you can fill the function's parameters one after another and when the full set of parameters is available the function is being executed. You can see a currying example here.

Upvotes: 1

David G
David G

Reputation: 96810

Not possible. By the time you do new OutputNumber(1) the function has already been called. A chained method will have no access to its preceding call.

Upvotes: 1

Related Questions