Only call constructor behaviour if particular function isn't called - javascript

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?

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.

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.

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.

Related

I've been told that functions no need returns can be called without "()" sometimes, Is that right?

some jquery code like:
$("#buy_price").blur(function(){
price_num;
});
$("#buy_num").blur(function(){
price_num;
});
function price_num() {
var price = $("#buy_price").val();
var num = $("#buy_num").val();
$("#buy_result").html(price*num);
};
can anyone tell me if it's right or not for sure?
better to use this way:
$("#buy_price, #buy_num").blur(price_num);
short and simple.
because price_num is a function itself then you can call it in the callback function of the bound event or you have to put () parenthesis there:
$("#buy_price, #buy_num").blur(function(){
price_num();
}); //------^^----if this way then its needed for sure.
No.
If you want to call a function, you can either:
Use ().
Instruct another function to call it.
The return value is irrelevant.
In this example:
$("#buy_price").blur(function(){
price_num;
});
The anonymous function is will be called by another function when the blur event occurs
The price_num function won't be called at all because neither of the two conditions apply
However, if you were to:
$("#buy_price").blur(price_num);
Then price_num would be called by another function when the blur event occurs.
This is not (entirely) true. The person that told you that probably got confused by a particular way of creating objects using the new operator.
This is valid and both statement will create an object as expected:
var a = new SomeFunction();
var b = new SomeFunction;
However, you can't call functions like that, as you are just returning the function to no-where.
myFunction; // Does nothing
Is exactly the same as these
42;
"Jsjsknsdjdj";
4 == 8;
All of these are just ignored because their value is not assigned to anything.
I'd recommend to always use () as it makes it clear when you read the code that a function call is being made, even when creating objects.

Different functions - are they the same?

I'm a JavaScript slightly-more-than-beginner.
While reading the source for EventEmitter, I stumbled upon this interesting and, to me, elegant function:
// alias a method while keeping the correct context
function alias(name) {
return function aliasClosure() {
return this[name].apply(this, arguments);
};
}
I have two main questions:
First: why is the aliasClosure a named function? Is it useful in some way other than clarity? Also, is is really a closure? To me, it looks just like a semi-anonymous function.
Second: I rewrote this function like this:
function alias2(name) {
return this[name].bind(this);
}
Is it equivalent? I think it should, since the this context is the same and it's preserved in both versions.
Is there a reason to prefer one over the other?
No, these are not at all equivalent. From looking at the alias() function I think you would use it something like this:
> Array.prototype.strjoin = alias('join'); // make 'strjoin' an alias of 'join'
> [1, 2, 3].strjoin(" + ");
"1 + 2 + 3"
Using alias2() in the above code will not work.
Providing a name in a function instantiation expression makes a name available for stack traces. (I'm told newer debuggers don't always need it if the function is created in certain contexts, like a var initialization.)
I think the second is equivalent, mostly, though .bind() has some obscure special cases it handles.
edit wait - no, they're not equivalent. The first one involves this explicitly, and performs the lookup on each call. The first function doesn't need this to be bound to anything when it's called, while yours will throw an exception in that case.
One change that would make the two functions almost equal is wrapping bind inside a closure, like this:
function alias2(name) {
return function() {
return this[name].bind(this);
}
}
Still, bind behaves obscurely in rare cases.

Edit Javascript function

Is it possible to edit a JavaScript function after the page has loaded?
I want to edit a function dynamically after Loading.
You can't edit a function, but you can replace it, e.g.:
var myFunc = function() { return "Hello World"; };
myFunc = function() { return "Goodbye"; };
javascript functions are objects, so can be replaced by setting a new value. Is this what you mean?
Unless you are trying to hack some code that doesn't belong to you, the better solution is to write a more flexible initial javascript function who's behavior can be adapted based on conditions (parameters passed, environment, other state, data fetched from other sources, etc...). Then, the one function you have can be written once initially to handle all your different circumstances.
You can even use design patterns such as passing in callback functions that can be used to adapt the behavior at runtime. If you desire many callbacks, you can pass in an object that has a number of different optional methods and call those during your function. In this way you can significantly alter the behavior of the main function without ever changing it's code by passing in different callback functions.
For example, let's assume we have a parsing function that takes some tagged data structure as input and returns an array of results. We want to be able to modify the behavior of this parsing function by passing in callbacks. So, we write the parsing function to take a callback object. That callback object contains one or more methods (all of which are optional) and a state variable that is passed to each callback. Anyone who has worked with ajax or any asynchronous networking in Javascript will recognize the callback object concept. Here's some pseudo code for such a process that shows how the callback object can be used. A real function would obviously be a lot more involved than this one, but it hopefully illustrates the concept:
function parseMyData(data, callbacks) {
var output = []; // output we accumulate
var currentTag;
callbacks = callbacks || {}; // make the callbacks object optional
// do any preprocessing that the caller specified
if (callbacks.preProcessData) {
data = callbacks.preProcessData(data, callbacks.state);
}
[[code to parse to the first tag in the data (after doing so currentTag contains the tag we just parsed)]]
// give our callback object the opportunity to do something to this tag or return null to skip it
if (callbacks.preProcessTag {
currentTag = callbacks.preprocessTag(currentTag, callbacks.state);
}
if (currentTag) {
[[code here for the default processing of the tag that will push results into the output array]]
}
return(output);
}
If you want to add an action to the existing function you can "hijack" it by putting it in a temporary variable and calling it within your overwritten function. E.g.
// The original function.
function sayName(name) {
alert(name);
}
// Temporary variable for original function.
var __sayHello = sayName;
// Overwrite the original function, adding extra actions.
sayName = function(name) {
alert('Hello');
// Call the original function using its temporary variable.
__sayHello(name);
}
// Call the overwritten function.
sayName('Bob');
How to edit a function - 101.
If we reconsider that editing a function at runtime is not absolutely changing the guts of the function, but rather changing what the function guts are digesting, then I would say functions are already built to do just that.
example 1 - The guts cannot be changed.
function one(){
return true;
}
// one() => true;
// Note: We could still change the output without changing the guts.
// !one() => false;
example 2 = The guts can be created to digest a dynamic call.
function one(payload){
return payload;
}
// one(true) => true;
// one(false) => false;
// one('whatever I want to feed the guts to digest');
// => 'whatever I want to feed the guts to digest';
These are quite simple examples, but since you did not provide any real examples as to what you are trying to do, we have to assume you are attempting normal patterns of programming.
Considering NORMAL patterns of programming, it wouldn't be the function itself that needs to change, rather how you are calling it.
example 3 - Give the choice of which function to the caller.
function firstChoice(payload){
return http.post(payload);
}
function secondChoice(choice){
return `Do something else with ${choice}`;
}
// And where you make the choice, perhaps after a click event handler...
function onClick(choice, payload){
choice ? firstChoice(payload) : secondChoice(choice);
}
Functions are supposed to be small bricks with which you build logic. Give them something small to do, then select between them based on your logic.
To answer your question, in my opinion, assuming normal programming needs...
"Is it possible to edit a JavaScript function after the page has loaded?" YES.
Use arguments in your function definition to add the dynamic ability to suit your needs.

Anonymous function references in Javascript

I'm currently in the process of building out a VERY simple Observer class for a project I'm working on. I have successfully implemented the subscribe, unsubscribe, and notify methods. Everything works exactly as expected when using "regular" functions (i.e: var f = function()).
However, when I pass an anonymous function to the subscribe method and then try to unsubscribe passing the "same" anonymous function it (as expected) doesn't remove the function from my array (they are different, after all).
Here's my subscribe and unsubscribe methods:
this._subscribers = {};
subscribe: function(type, callback) {
if ( isUndefined(this._subscribers[type]) ) {
this._subscribers[type] = [];
}
this._subscribers[type].push(callback);
},
unsubscribe: function(type, callback) {
if ( this._subscribers[type] instanceof Array ) {
var index = this._subscribers[type].indexOf(callback);
if ( index >= 0 ) {
this._subscribers[type].splice(index, 1);
}
}
},
And here's the code I'm testing with:
var o = new gaf.events.Observable();
o.subscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent');
// Correct alerts 'Got It!'
o.unsubscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent')
// Incorrectly alerts 'Got It!'
I know I could using an object (i.e.: _subscribers[event] = {}) and then when something subscribes I could add a new property equal to the callback and the value equal to the callback. This will cause Javascript to convert the callback to the string. I could then look it up (provided the methods passed in sub/unsub are exactly the same) using that string.
However, this is a mobile project and I'm very leery about storing strings that could be hundreds of characters long as properties as we could end up with a lot of subscribers.
Are there any other ways of doing this? Are there any SMALL (tiny, even) hashing libraries I can use to maybe hash the string value of the function and use that as the property? Would it be better to store the string value of the callback (so I can compare against it) in the array (rather then the actual callback) and use eval() on it?
EDIT
First, thanks all for the replies!
Per all the questions about "Why even pass anonymous" functions -
There really is no reason one COULDN'T use named functions. In fact, I agree with everyone that named functions are going to be the better solution. I'm simply gathering information and looking for a solution so that I can build out an implementation that handles the most scenarios as best as possible.
The other reason for this is what happens if a user (co-worker) of this Observable class passes it an anonymous function and then unsubscribes. That function won't actually be unsubscribed and therefore won't be cleaned up. I have a thing against orphaned data :)
Maybe another question I should as is, is it possible to test if the callback is anonymous or not? I'm going to assume no but doesn't hurt to ask.
There is nothing wrong with storing the entire string; premature optimization is evil.
However, this sounds like an incredibly bad idea.
If someone changes the function, but forgets to change the unsubscribed copy, the code will be subtly broken with no warning whatsoever.
Instead, you can require the user to store the anonymous function in a variable if they want to unsubscribe from it.
Alternatively, you can pass an optional name with each subscriber, then unsubscribe by that name.
the clients that use the Observer should store the reference to the function.
var obsCallback = function() {
}
o.subscribe('test', obsCallback);
....
o.unsubscribe('test', obsCallback);
in other words, keep a reference to the function around...
Perhaps a better solution is to modify the code using your library
var f = function() { alert('Got It!'); };
o.subscribe('testEvent', f);
o.notify('testEvent');
o.unsubscribe('testEvent', f);
o.notify('testEvent');
You could even return the function from the subscribe method
var f = o.subscribe('testEvent', function() { alert('Got It!'); });
// ...
then if you want to store a hash or some other identifier for subscribed functions, it is opaque to the calling code meaning that you just use the returned value to unsubscribe and the library hides the implementation detail.
What is the reason for passing in anonymous functions rather than named ones, or keeping references that you can use for unsubscribing later?
Alternatively you could allow for an optional 'id' argument but this would require unnecessarily complex bookkeeping to avoid duplicates.

Javascript Event Synchronization

I'm building a concert calendar that's very heavy on javascript (using jQuery). I'm having trouble synchronizing various events throughout the app, and I'm looking for suggestions for how to do this.
An example of a simple use case:
User clicks a month
Calendar skips to that month
An example of a more complex use case:
User selects an artist
Calendar determines the date of that artist's first show
Calendar skips to that month
Calendar highlights that artist's show(s)
One occasional problem is that the new month isn't yet rendered by the time I try to highlight the artist's show(s). Thus, the show isn't highlighted even though these functions are called in order. Obviously, using setTimeout() is pretty hacky, and not guaranteed to work.
So first, a simple question -- would it ever be possible (even in Chrome) for the following function to run out of sequence?
function steps(){
stepOne(); //TAKES 30 SECONDS
stepTwo(); //TAKES < 1 SECOND
}
Second, a related simple question:
If placed at the end of a function, will a JS callback ALWAYS run after
everything else in the given function has finished running?
If so, I could nest each function as a callback of its previous function. But that would likely become unwieldy, once you consider all the different use cases.
Here's an approach I'm considering:
1) Allow each function an optional callback parameter. If it's present,
call it at the very end of the function.
2) During a UI refresh, create an array, and stack any functions to be
called within this array.
3) Once this "script" is completed, iterate through the array, calling
each function in the order it was added, using the next function
as the previous function's callback.
I imagine this would ensure that all the functions are called in order.
Another approach is to attach event listeners using
$(document).bind("listener.name", fnCallback);
And then calling
$(document).trigger("listener.name");
Whenever that event occurs.
However, I'm guessing this would be kind of unwieldy as well, considering different events might need to call different sets of functions depending on the use case. I could always call
$(document).unbind("listener.name");
before adding new events to it, but again -- I'm leaning toward creating sort of a master "script" as I suggested in the first approach.
Hopefully this isn't too vague -- any feedback? Any experience with complex UIs that had to synchronize various events?
Thanks very much,
Michael
Your approach #1 is the best way, and the most natural using jQuery. Most functions that act on the user interface and do something accept a callback function parameter, which gets called after the function has executed.
Where you are doing things not implemented in jQuery following the same pattern will make your code more readable. dominic's answer is a good terse example:
function steps(){
stepOne(stepTwo);
}
function stepOne(callback){
var AsyncDone = function() {
//any Synchronus Things here
callback();
}
someAsyncFunction( params, AsyncDone );
}
Try passing in the function to be called back to as an argument
function steps(){
stepOne(stepTwo);
}
function stepOne(callback){
var AsyncDone = function() {
//any Synchronus Things here
callback();
}
someAsyncFunction( params, AsyncDone );
}
The last approach, of using custom events, is the best approach in my humble opinion.
Design various components and events and let them interact with each other.
E.g. Let's say you have a Calendar object.
var calendar = function()
{
var pub = {};
pub.highlightRow = function(row) {};
pub.getRowByContent = function(content) { };
pub.selectMonth = function()
{
//your code to actually select month.
//Once all the necessary DOM work is done, fire the
//monthSelected event (namespacing the event so as to avoid the clash with other events).
$(document).trigger('calendar:monthSelected');
};
return pub;
}();
Now your artist search method may look like,
function searchArtist(artistName)
{
$(document).bind('calendar:monthSelected'), function()
{
calendar.highlightRow(calendar.getRowByContent(artistName));
}
);
calendar.selectMonth(getShowMonthByArtist(artistName));
}
You can use javascript's then() method to synchronize the functions and have them execute in the order that you want, like so:
function steps() {
stepOne().then(function() { stepTwo(); })
}

Categories