Please: only pure vanilla JS code. No jQuery or other external things, thank you. :)
How can I create a function that contains sub-functions but also returns a value if no sub-function is called?
For example, let's take a number variable num.
I want to add a round() function to the number variable; if it's called directly, I want it to round up or down depending on the variable's actual value.
var num=4.12;
num.prototype.round=function(){return Math.round(this);}
Now I wand round() to have sub-functions that will round up or down, disregarding the decimal values.
num.prototype.round.up=function(){return Math.ceil(this);}
num.prototype.round.down=function(){return Math.floor(this);}
If I do that and log num.round() to console, it does what it's supposed to. But if I log num.round.up() to console, I get an error telling me that num.round.up() is not a function.
So I try putting the sub-functions into the main function declaration like this:
num.prototype.round=function(){
var n=this;
this.up=function(){return Math.ceil(n);}
this.prototype.round.down=function(){return Math.floor(n);}
return Math.round(n);
}
Then again, num.round() will return the correctly rounded value, but both num.round.up() and num.round.down() will return "not a function" errors.
I'm going nuts trying to figure this out... I didn't only try what I mentioned above, but I also tried doing this with immediately executing functions like this:
num.round=(function(){
return function(){
var that=this;
/* anything in here is already useless because this
is no longer num's value but [Object window]... */
}
})();
I guess part of the trouble is that I'm so weak at OOP that I just have no clue about the correct terminology... naturally, that doesn't help when searching for clues or when it comes to knowing any potential reasons why something like this should not work...
So is there any way at all to do this?
Well you can pass a parameter to the function. Not the exact implementation you want, just an alternative:
var num = function (defaultNumValue) {
var delegation = {
'up': 'ceil',
'down': 'floor'
};
return {
round: function (val) {
return Math[ delegation[val] || 'round' ](defaultNumValue);
}
}
};
var sth = num(1.5);
sth.round(); // 2
sth.round('up'); // 2
sth.round('down'); // 1
May be something like:
function num(n) {
this.num=n;
this.round=Math.round(n);
this.up=Math.ceil(n);
this.down=Math.floor(n);
this.up2=function(){return Math.ceil(n);}
}
var num = new num(4.12);
alert(num.num);
alert(num.round);
alert(num.up);
alert(num.down);
alert(num.up2());
Related
var a = 1;
function myFunction() {
++a;
return true;
}
// Alert pops up.
if (myFunction() && a === 2) {
alert("Hello, world!");
}
// Alert does not pop up.
if (a === 3 && myFunction()) {
alert("Hello, universe!");
}
https://jsfiddle.net/3oda22e4/6/
myFunction increments a variable and returns something. If I use a function like that in an if statement that contains the variable which it increments, the condition would be order-dependent.
Is it good or bad practice to do this, and why?
Conditions are order-dependent whether you change the variables used in the condition or not. The two if statements that you used as an example are different and will be different whether you use myFunction() or not. They are equivalent to:
if (myFunction()) {
if (a === 2) {
alert("Hello, world!")
}
}
// Alert does not pop up.
if (a === 3) {
if (myFunction()) {
alert("Hello, universe!")
}
}
In my opinion, the bad practice in your code is not the fact that you change the condition's operands value inside the condition, but the fact that your application state is exposed and manipulated inside a function that does not even accept this state changing variable as a parameter. We usually try to isolate the functions from the code outside their scope and use their return value to affect the rest of the code. Global variables are 90% of the time a bad idea and as your code base gets larger and larger they tend to create problems that are difficult to trace, debug and solve.
It's bad practice, for the following reasons:
The code is far less readable than well-constructed code. This is very important if the code is later examined by a third party.
If myfunction is changed later, the code flow is completely unpredictable, and might require a major documentation update.
Small and simple changes can have drastic effects on the execution of the code.
It looks amateur.
If you have to ask, it's hardly a good practice. Yes, it's a bad practice for exactly the reason you mentioned: changing the order of operands of a logical operation should not affect the outcome, and therefore side effects in conditions should generally be avoided. Especially when they are hidden in a function.
Whether the function is pure (only reads state and does some logic) or whether it mutates state should be obvious from its name. You have several options to fix this code:
put the function call before the if:
function tryChangeA() {
a++;
return true;
}
var ok = tryChangeA();
if (ok && a == 2) … // alternatively: if (a == 2 && ok)
make the mutation explicit inside the if:
function testSomething(val) {
return true;
}
if (testSomething(++a) && a == 2) …
put the logic inside the called function:
function changeAndTest() {
a++;
return a == 2;
}
if (changeAndTest()) …
MyFunction violates a principle called Tell, Don't Ask.
MyFunction changes the state of something, thus making it a command. If MyFunction succeeds or somehow fails to increment a, it shouldn't return true or false. It was given a job and it must either try to succeed or if it finds that job is impossible at the moment, it should throw an exception.
In the predicate of an if statement, MyFunction is used as a query.
Generally speaking, queries should not exhibit side-effects (i.e. not changing things that can be observed). A good query can be treated like a calculation in that for the same inputs, it should produce the same outputs (sometimes described as being "idempotent").
It's also important to know that these are guidelines to help you and others reason about the code. Code that can cause confusion, will. Confusion about code is a hatchery for bugs.
There are good patterns like the Trier-Doer pattern which can be used like your code example, but everyone reading it must understand what's happening though names and structure.
The code presents more then one bad practice actually:
var a = 1;
function myFunction() {
++a; // 1
return true;
}
if (myFunction() && a === 2) { // 2, 3, 4
alert("Hello, world!")
}
if (a === 3 && myFunction()) { // 2, 3, 4
alert("Hello, universe!")
}
Mutates a variable in a different scope. This may or may not be a problem, but usually it is.
Calls a function inside an if statement condition.
This do not cause problems in itself, but it's not really clean.
It's a better practice to assign the result of that function to a variable, possibly with a descriptive name. This will help whoever reads the code to understand what exactly you want to check inside that if statement. By the way, the function always return true.
Uses some magic numbers.
Imagine someone else reading that code, and it is part of a large codebase. What those numbers mean? A better solution would be to replace them with well named constants.
If you want to support more messages, you need to add more conditions.
A better approach would be to make this configurable.
I would rewrite the code as follows:
const ALERT_CONDITIONS = { // 4
WORLD_MENACE: 2,
UNIVERSE_MENACE: 3,
};
const alertsList = [
{
message: 'Hello world',
condition: ALERT_CONDITIONS.WORLD_MENACE,
},
{
message: 'Hello universe',
condition: ALERT_CONDITIONS.UNIVERSE_MENACE,
},
];
class AlertManager {
constructor(config, defaultMessage) {
this.counter = 0; // 1
this.config = config; // 2
this.defaultMessage = defaultMessage;
}
incrementCounter() {
this.counter++;
}
showAlert() {
this.incrementCounter();
let customMessageBroadcasted = false;
this.config.forEach(entry => { //2
if (entry.condition === this.counter) {
console.log(entry.message);
customMessageBroadcasted = true; // 3
}
});
if (!customMessageBroadcasted) {
console.log(this.defaultMessage)
}
}
}
const alertManager = new AlertManager(alertsList, 'Nothing to alert');
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
A class with a precise function, that use its own internal state, instead of a bunch of functions that rely on some variable that could be located anywhere. Whether to use a class or not, it's a matter of choice. It could be done in a different way.
Uses a configuration. That means that would you want to add more messages, you don't have to touch the code at all. For example, imagine that configuration coming from a database.
As you may notice, this mutates a variable in the outer scope of the function, but in this case it does not cause any issue.
Uses constants with a clear name. (well, it could be better, but bear with me given the example).
A function that changes stuff. What is the world coming too? This function must change stuff and return different values each time its called.
Consider the dealCard function for a deck of playing cards. it deals the cards 1-52. Each time it is called it should return a different value.
function dealCard() {
++a;
return cards(a);
}
/* we'll just assume the array cards is shuffled */
/* for the sake of brevity we'll assume the deck is infinite and doesn't loop at 52*/
I have been dealing with issues in multiple pieces of code but it seems to boil down to what I’m showing in this demo. I think it is related to the ’s dereferencing of a closure:
function get_5(callback) {
var result = 5;
callback(result);
}
function get_self(x) {
return x;
}
get_5(console.log);
// 5
console.log(get_self(5));
// 5
In the first result, the first function ran as expected, sending its hidden variable into the input of the console.log function.
The second result also makes sense, as it really just proves the second function works: it takes what was fed in and returns it.
But things get strange when I try to combine the two functions:
var a = get_5(get_self);
console.log(a);
// Undefined!
This third result is undefined, strangely enough, and I am not sure why. Is the closure being dereferenced, maybe to the “sneakiness” of the get_self function? How can I fix this? As a bonus, is there a way to eliminate the get_self function entirely and be able to directly read the variable result, which isn’t modified, without specifying any particular callback?
get_5 has no return statement. It doesn't matter what you pass to get_5, it will always return undefined.
Perl will return the result of evaluating the last statement in a sub, but JavaScript will not.
If you want get_5 to return the result of calling the callback you pass to it, then you have to say so explicitly:
function get_5(callback) {
var result = 5;
return callback(result);
}
Is there a method or way in JavaScript that I can check if assert if a function returns a value through the use of an if statement?
So this:
function(val) {
if (val) return "it is true";
return "it is false";
}
versus this:
function(val) {
var str = 'it is ';
return str += val;
}
I've been looking around and can only find articles related to Java or other languages. Thanks in advance.
EDIT: I'm writing tests to assert whether or not a function (written by a user) utilizes an if statement. Hope that clarifies that a bit!
First I'd like to mention that such checks shouldn't be used in code, in which I mean that proper code should never check whether an if-statement is used inside a function. Whether a value is returned from it or not, this shouldn't be checked or tested.
But, to get back on topic. I'm not quite sure whether this is possible out of the box. I do however have a solution that you might be able to use to achieve something similar to your goals.
You can convert a given function to it's string representation. Take a look at the following example:
// Define a function
var myFunction = function() {
return 1 + 3;
};
// Print the function, as a string
console.log(myFunction.toString());
This code will print the string representation of the function in the console, so that will be function() { return 1 + 3; }. Some environments, such as the Firefox return a compiled version of the function which would look like function() { return 4; } but that doens't really have any effect on our use.
Using this method you'll be able to check whether the given function contains an if-statement. Such code would look like this:
// Define a function
var myFunction = function() {
return 1 + 3;
};
// Check whether the given function contains an if-statement
if(myFunction.toString().indexOf('if') > -1) {
console.log('This function does contain an if-statement');
} else {
console.log('This function does not contain an if-statement');
}
This method isn't ideal for your situation but it might point you in the right direction. Please note that this method isn't a rock-solid solution, at least not in this state. The usage of 'if' as a string (or something else) in a function would also cause the code above to say that the function contains an if-statement. Also, this doesn't explicitly check whether a value is returned from inside of an if-statement.
If you'd like to ensure the things mentioned above (that a real if-statement is used, in which a value is returned from it) you might have to modify the above code to make it smarter if this string-based method suits your needs. Then, I'd highly recommend to write a fancy wrapper around it to make it easier in use.
I am just learning NodeJS and/or PhantonJS.
As a programmer with a lot of C experience, I do not like the way NodeJs code is written and find it a bit messy/unreadable. (Sorry if I ruffled any feathers)
In spirit of cleaning up the code, I was trying to do this and found a block.
In C or C++, we should be able to pass a function by name but in NodeJS/PhantomJS it does not seem to work.
Am I doing somthing wrong ?
Can someone explain to me how this is looked at by the Javascript interpreter ?
var page = require('webpage').create();
var printS = function (s) {
console.log(s);
phantom.exit();
}
/* This works */
page.open('http://net.tutsplus.com', function (s) {
console.log(s);
phantom.exit();
});
/* This does not work
page.open('http://net.tutsplus.com', printS(status));
*/
/*But this works
page.open('http://net.tutsplus.com', function (s) { printS(s);} );
*/
page.open('http://net.tutsplus.com', printS(status));
fails because you're not passing the function but rather the result of invoking the function on status. If you want to pass the function, you'd do it this way
page.open('http://net.tutsplus.com', printS);
I thought it might be helpful to have a more extensive explanation. Let's start simple:
In JavaScript, we have values and variables. Variables are containers for values. Almost everywhere where we can use values, we can use variables.
In JavaScript source code, we express values through literals, e.g. the number literal 42. We can directly pass that value to a function:
f(42);
Additionally, instead of passing the value directly, we can pass a variable to the function:
var v = 42;
f(v);
That is, we can substitute values with variables.
Lets consider
var printS = function() { ... };
This clearly is a variable whose value is a function. If we'd directly pass that value to a function (i.e. we pass a function to a function), it would look like:
f(function() { ... }); // similar to f(42)
That's exactly what you have in your first case:
page.open('http://net.tutsplus.com', function (s) {
// ...
});
Since we know that we can replace values with variables, we can just substitute function() { ... } with printS:
var printS = function() { ... }; // similar to var v = 42;
f(printS); // similar to f(v)
So your example would become
page.open('http://net.tutsplus.com', printS);
What is wrong with
page.open('http://net.tutsplus.com', printS(status));
then?
Notice that you added additional characters after printS, namely (status). They don't appear in the your first example where you inlined the function:
page.open('http://net.tutsplus.com', function (s) {
// ...
});
There is no (status) here. Hence these two constructs cannot be not equivalent.
page.open accepts a function value as second argument, but printS(status) doesn't evaluate to the function printS, it calls the function printS and passes the return value to page.open.
Why does
page.open('http://net.tutsplus.com', function (s) { printS(s);} );
work?
Lets remove the content and the argument of the function, and it becomes:
page.open('http://net.tutsplus.com', function () { ... } );
That looks exactly like one of the examples above. function () { ... }, is a function literal, so to speak. It creates a function value. There are no (...) after it which would call the function.
This doesn't work as you hope because page.open wants a function as its second argument... this callback pattern is very common in JavaScript. In your doesn't-work example, printS is being called with status as its argument, and it returns undefined. As undefined is not a function, it doesn't behave as you wish.
In your browser console or the node repl:
> printS = function (s) { console.log(s); };
function (s) { console.log(s); }
> typeof printS('hi');
hi
"undefined"
> typeof function (s) { printS(s); };
"function"
Another thing to know about JavaScript is that its dynamic typing and fairly generous type coercion can result in baffling behavior with no helpful errors to point you towards the root cause of your problem. A debugger or copious use of console.log() is frequently helpful in understanding these sort of problems.
Is it possible to find the name of an anonymous function?
e.g. trying to find a way to alert either anonyFu or findMe in this code http://jsfiddle.net/L5F5N/1/
function namedFu(){
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var anonyFu = function() {
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var findMe= function(){
namedFu();
anonyFu();
}
findMe();
This is for some internal testing, so it doesn't need to be cross-browser. In fact, I'd be happy even if I had to install a plugin.
You can identify any property of a function from inside it, programmatically, even an unnamed anonymous function, by using arguments.callee. So you can identify the function with this simple trick:
Whenever you're making a function, assign it some property that you can use to identify it later.
For example, always make a property called id:
var fubar = function() {
this.id = "fubar";
//the stuff the function normally does, here
console.log(arguments.callee.id);
}
arguments.callee is the function, itself, so any property of that function can be accessed like id above, even one you assign yourself.
Callee is officially deprecated, but still works in almost all browsers, and there are certain circumstances in which there is still no substitute. You just can't use it in "strict mode".
You can alternatively, of course, name the anonymous function, like:
var fubar = function foobar() {
//the stuff the function normally does, here
console.log(arguments.callee.name);
}
But that's less elegant, obviously, since you can't (in this case) name it fubar in both spots; I had to make the actual name foobar.
If all of your functions have comments describing them, you can even grab that, like this:
var fubar = function() {
/*
fubar is effed up beyond all recognition
this returns some value or other that is described here
*/
//the stuff the function normally does, here
console.log(arguments.callee.toString().substr(0, 128);
}
Note that you can also use argument.callee.caller to access the function that called the current function. This lets you access the name (or properties, like id or the comment in the text) of the function from outside of it.
The reason you would do this is that you want to find out what called the function in question. This is a likely reason for you to be wanting to find this info programmatically, in the first place.
So if one of the fubar() examples above called this following function:
var kludge = function() {
console.log(arguments.callee.caller.id); // return "fubar" with the first version above
console.log(arguments.callee.caller.name); // return "foobar" in the second version above
console.log(arguments.callee.caller.toString().substr(0, 128);
/* that last one would return the first 128 characters in the third example,
which would happen to include the name in the comment.
Obviously, this is to be used only in a desperate case,
as it doesn't give you a concise value you can count on using)
*/
}
Doubt it's possible the way you've got it. For starters, if you added a line
var referenceFu = anonyFu;
which of those names would you expect to be able to log? They're both just references.
However – assuming you have the ability to change the code – this is valid javascript:
var anonyFu = function notActuallyAnonymous() {
console.log(arguments.callee.name);
}
which would log "notActuallyAnonymous". So you could just add names to all the anonymous functions you're interested in checking, without breaking your code.
Not sure that's helpful, but it's all I got.
I will add that if you know in which object that function is then you can add code - to that object or generally to objects prototype - that will get a key name basing on value.
Object.prototype.getKeyByValue = function( value ) {
for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) {
if( this[ prop ] === value )
return prop;
}
}
}
And then you can use
THAT.getKeyByValue(arguments.callee.caller);
Used this approach once for debugging with performance testing involved in project where most of functions are in one object.
Didn't want to name all functions nor double names in code by any other mean, needed to calculate time of each function running - so did this plus pushing times on stack on function start and popping on end.
Why? To add very little code to each function and same for each of them to make measurements and calls list on console. It's temporary ofc.
THAT._TT = [];
THAT._TS = function () {
THAT._TT.push(performance.now());
}
THAT._TE = function () {
var tt = performance.now() - THAT._TT.pop();
var txt = THAT.getKeyByValue(arguments.callee.caller);
console.log('['+tt+'] -> '+txt);
};
THAT.some_function = function (x,y,z) {
THAT._TS();
// ... normal function job
THAT._TE();
}
THAT.some_other_function = function (a,b,c) {
THAT._TS();
// ... normal function job
THAT._TE();
}
Not very useful but maybe it will help someone with similar problem in similar circumstances.
arguments.callee it's deprecated, as MDN states:
You should avoid using arguments.callee() and just give every function
(expression) a name.
In other words:
[1,2,3].forEach(function foo() {
// you can call `foo` here for recursion
})
If what you want is to have a name for an anonymous function assigned to a variable, let's say you're debugging your code and you want to track the name of this function, then you can just name it twice, this is a common pattern:
var foo = function foo() { ... }
Except the evaling case specified in the MDN docs, I can't think of any other case where you'd want to use arguments.callee.
No. By definition, an anonymous function has no name. Yet, if you wanted to ask for function expressions: Yes, you can name them.
And no, it is not possible to get the name of a variable (which references the function) during runtime.