Convert the argument (a variable) into string a string automatically - javascript

I made a temperature conversion function and I am curious if there is anyway to automatically convert an argument into a string.
For instance, convertTemp(72, F) --> convertTemp(72, 'F') and then start the function.
I know I can just enter the argument in as a string, but It got me wondering if there was a way to turn a (somehow erroneously entered) variable declaration into a string without having to deal with the Reference error saying that the argument is not defined (declared).
I've been looking through the toString() method, String(), etc. but they all convert values not an implicit variable like format would be.
If it's not possible that's fine, just a curiosity.
Thanks!
function convertTemp(temperature, format) {
if (format == 'C') return CtoF();
else if (format == 'F') return FtoC();
else return 'Invalid Metric';
function CtoF() {
let F = Math.floor((1.8) * temperature + 32);
return F;
}
function FtoC() {
let C = Math.floor(((temperature - 32) * 5) / 9);
return C;
}
}
TLDR; function is entered as: convertTemp(72, F) instead of convertTemp(72, 'F'), can this be automatically corrected?

The answer to your question is technically "no".
You'd have to do some pretty hacky stuff to avoid a ReferenceError and none of it would be efficient and would be bound to cause bugs, but just for fun I've come up with just the kind of hack that should make most programmers cringe.
Disclaimer: Under no circumstances would I recommend ever doing this
First let's consider a function that simply outputs its arguments
function doStuff(...args){
console.log("Args:", ...args)
}
If you try and pass this function a variable, that variable has to be defined somewhere. As other users have stated, a global variable would be the only way to ensure the variable is defined in any scope, and we will be using that later.
If you surround a reference error with try/catch, then it's possible to catch the reference error's message. Then using regex you can extract the missing parameter, which luckily will already be a string, add it to the global scope, then simply call the function again.
try {
doStuff(A)
} catch (e) {
const [,arg] = e.message.match(/^(.*?) is not defined$/i)
window[arg] = arg
doStuff(A)
}
But that's redundant and pointless, so now let's take this logic and put it in a function that will automatically define the variable for you in the global scope then call the function again like so:
function wrapError(fn){
try {
fn()
}catch(e){
const [, arg] = e.message.match(/^(.*?) is not defined$/i)
window[arg] = arg
wrapError(fn)
}
}
The unfortunate caveat here is that you have to pass a function to wrapError, or else doStuff will evaluate inline and will throw its error outside the try/catch block.
wrapError(()=>doStuff(A, B, C))
Finally you end up with the following, which was tested on Chrome on Mac. It's possible that the error message thrown will have a different format or structure and this regex isn't that robust, so keep that in mind.
function doStuff(...args){
console.log("Args:", ...args)
}
function wrapError(fn){
try {
fn()
}catch(e){
const [,arg] = e.message.match(/^(.*?) is not defined$/i)
window[arg] = arg
wrapError(fn)
}
}
// With wrapper
wrapError(()=>doStuff(PLZ, DONT, DO, THIS))
// Without wrapper
doStuff(Hello, Error) // ReferenceError
Conclusion: Never do this and I hope nobody ever takes this seriously.

It is not possible without a preprocessor, which would clean up the code in advance.
You could take a const for 'F'. But I would not recommend it.
const F = 'F';

Related

SyntaxError when extending Number object

I am trying to extend the Number object with this code:
Number.prototype.isNumber = function(i){
if(arguments.length === 1){
return !isNaN(parseFloat(i)) && isFinite(i);
} else {
return !isNaN(parseFloat(this)) && isFinite(this);
}
}
try {
var x = 8.isNumber();
} catch(err) {
console.log(err);
}
I get SyntaxError: identifier starts immediately after numeric literal
also when I try the following:
Number.isNumber(8)
I get Number.isNumber is not a function!!
The JavaScript parser reads 8.isNumber as a number literal.
To access a Number method on a numeric literal you'll have to surround the number with parenthesis so the JavaScript interpreter knows you're trying to use the number properties.
Number.prototype.isNumber = function(i) {
if (arguments.length === 1) {
return !isNaN(parseFloat(i)) && isFinite(i);
}
return !isNaN(parseFloat(this)) && isFinite(this);
}
try {
var x = (8).isNumber();
console.log(x);
} catch(err) {
console.log(err);
}
I couldn't help it but provide an additional answer although you already accepted one.
The first thing you need to know, is that there is a fundamental difference between the Number object, and the Number prototype (see here).
As it stands, you are extending the Number prototype, not the object itself! Your isNumber implementation actually has the same effect like the following:
Number.prototype.isNumber = function(){return isFinite(this)}
Why? Because in order to execute this prototype method, the parser first needs to know the type of the literal you are invoking the function on. That's why you either need to turn your number literal into an expression by wrapping it in parentheses: (8).isNumber() or by using an even weirder notation 8..isNumber() (the first . is the decimal point, the second the property accessor). At this point, the javascript engine already evaluated it as a Number and thus can execute the isNumber() method.
On the other hand, although at first glimpse your code looks like it could handle the following case correctly (since you are doing a parseFloat): "8".isNumber() will always throw an exception, because here we have a string literal, and the String prototype does not have the according method. This means, you will never be able to detect numbers that are actually string literals in the first place.
What you instead should do, is directly extend the Number object so you can actually do a proper check without having to deal with errors:
Number.isFiniteNumber = function(i){
return !Number.isNaN(i) && Number.isFinite(i);
}
Number.isFiniteNumber(8); // returns true
Number.isFiniteNumber("3.141"); // returns true
Number.isFiniteNumber(".2e-34"); // returns true
Number.isFiniteNumber(Infinity); // returns false
// just for informational purposes
typeof Infinity === "number" // is true
Bonus material:
Extending native objects is potentially dangerous.
Number.isNaN() probably does not what you think it does.

Calling a function bypassing eval()

I am working with a Javascript code that uses eval function.
eval(myString)
The value of myString = myFunc(arg), I want to call myFunc directly without using eval.
I dont have any control over the function to call as I am getting that function as a String (here myString).
The arguments to that function is also part of the same string.
So, is there any way through which I can call the intended function without using eval?
I'm a bit skeptical of allowing users to provide function names at all, but... Assume you have the function name in a variable and the value of arg in a variable. Boom:
var myString = window[fn](arg);
arg is already presumably in an argument, so that's simple enough. The next part is exatracting the function name. Just a bit of regex:
var fn = /^([a-z0-9_]+)\(arg\)$/i.exec(str)[1];
if (fn && typeof window[fn] === 'function') {
window[fn](arg);
}
This does of course assume that the function is always in the global scope, but if it's not, you should be able to adjust accordingly for that. Also, my regex is just the first thing I came up with. It probably doesn't cover all possible function names.
If you wanted to limit the string to just a certain set of functions (and you almost certainly should), that becomes quite easy as well once you have the function name:
var allowedFunctions = {fn1: fn1, fn2: fn2, someOtherFunction: function() {} },
fn = /^([a-z0-9_]+)\(arg\)$/i.exec(str)[1];
if (fn && allowedFunctions[fn]) {
allowedFunctions[fn](arg);
} else {
// Hah, nice try.
}
(If arg isn't actually a variable name but is some kind of literal or perhaps an arbitrary expression, this gets a little more complicated and a lot less safe.)
JavaScript does not provide any way of calling a function represented as a string, other than using eval. There's nothing wrong about using it, though. Given that you have no other option.
Possibly you may try using Function:
var sure = function(s) {
return confirm(s);
};
var str = 'sure("Are you sure?")';
var rtn = new Function('return ' + str)();
alert(rtn);

NewBee on NodeJs or PhantomJS: Function names on Javascript

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.

JavaScript: alert object name as a string

I'm trying to alert any JavaScript object as a string, in a function. This means if the parameter given to the function is window.document, the actual object, it should alert "window.document" (without quotes) as a literal string.
The following calls...
example(window);
example(window.document);
example(document.getElementById('something'));
...calling this function...
function example(o) {/* A little help here please? */}
...should output the following strings...
window
window.document
document.getElementById('something')
I've attempted to do this with combinations of toString() and eval() among some more miscellaneous shots in the dark without success.
No need insane backwards compatibility, newer ECMAScript / JavaScript features/functions are fine. Feel free to inquire for clarifications though the goal should be pretty straight forward.
This is not possible to do in a self contained script.
If using a preprocessor would be an option, then you could write one which converts example(whatever) into example('whatever'). Other than that I'm afraid you're out of luck.
The first problem is that objects don't have names.
The second problem is that from your examples, you're not really wanting to print the (nonexistent) name of an object, you want to print the expression that evaluated into a reference to an object. That's what you're trying to do in this example:
example(document.getElementById('something'));
For that to print document.getElementById('something'), JavaScript would have had to keep the actual text of that expression somewhere that it would make available to you. But it doesn't do that. It merely evaluates the parsed and compiled expression without reference to the original text of the expression.
If you were willing to quote the argument to example(), then of course it would be trivial:
example( "document.getElementById('something')" );
Obviously in this case you could either print the string directly, or eval() it to get the result of the expression.
OTOH, if you want to try a real hack, here's a trick you could use in some very limited circumstances:
function example( value ) {
var code = arguments.callee.caller.toString();
var match = code.match( /example\s*\(\s*(.*)\s*\)/ );
console.log( match && match[1] );
}
function test() {
var a = (1);
example( document.getElementById('body') );
var b = (2);
}
test();
This will print what you wanted:
document.getElementById('body')
(The assignments to a and b in the test() function are just there to verify that the regular expression isn't picking up too much code.)
But this will fail if there's more than one call to example() in the calling function, or if that call is split across more than one line. Also, arguments.callee.caller has been deprecated for some time but is still supported by most browsers as long as you're not in strict mode. I suppose this hack could be useful for some kind of debugging purposes though.
Don't know why you need this, but you can try walking the object tree recursively and compare its nodes with your argument:
function objectName(x) {
function search(x, context, path) {
if(x === context)
return path;
if(typeof context != "object" || seen.indexOf(context) >= 0)
return;
seen.push(context);
for(var p in context) {
var q = search(x, context[p], path + "." + p);
if(q)
return q;
}
}
var seen = [];
return search(x, window, "window");
}
Example:
console.log(objectName(document.body))
prints for me
window.document.activeElement

Can I detect unused extra parameters passed to javascript methods?

In Javascript I can call any method with more than the necessary amount of parameters and the extra parameters are silently ignored.
e.g.
letters = ['a','b','c']
//correct
letters.indexOf('a')
//This also works without error or warning
letters.indexOf('a', "blah", "ignore me", 38)
Are there ways to detect cases where this occurs?
My motivation is that in my experience cases where this occurs are usually bugs. Identification of these by code analysis or at runtime would help track these errors down.
These cases are especially prevalent where people are expecting alterations to base types which may not have occurred. Logging a warning where this happens
e.g.
Date.parse('02--12--2012', 'dd--MM--YYYY')
Notes:
To be clear I would like a solution that doesn't involve me sprinkling checks all over my code and other peoples' code.
You can use the arguments object.
function myFunction(param1,param2)
{
if (arguments.length!=2)
{
// wrong param number!
}
...
}
As per your edit: If you want to implement an automated form of check, without ever touching the original functions:
You still have to process each function with:
functionName = debug(functionName, numberOfExpectedArgs);
This operation wraps the function with a check of the number of arguments.
So we leave a sample function untouched:
// this is the original function... we want to implement argument number
// checking without insertint ANY debug code and ANY modification
function myFunction(a,b,c)
{
return a + " " + b + " " + c;
}
// the only addition is to do this...
myFunction = debug(myFunction,3); // <- implement arg number check on myFunction for 3 args
// let's test it...
console.log(myFunction(1,2,3));
console.log(myFunction(1,2));
You need to implement this debug() function:
function debug(f, n)
{
var f2 = f;
var fn = function()
{
if (arguments.length!=n) console.log("WARNING, wrong argument number");
return f2.apply(f2, arguments);
};
return fn;
}
​
This solution is TOTALLY transparent as per already defined functions, so it may be what you seek for.
I strongly suggest to check against deprecations (there are some) and crossbrowser compatibility.
The functions in JavaScript are objects. As such they have properties. What you want can be achieved with length MDN property, which specifies the number of arguments expected by the function.
function say ( hello, world ) {
alert (
"arguments length = " + arguments.length + "\n" +
"defined with = " + say.length
);
}
say ( "this ", "brave ", "new ", "world" );​
This works even on IE8. Demo. In your case you can do something like this.
Javascript is a very dynamic language and many of its useful features also make it impossible to do some checks statically.
The existance of the arguments implicit object means there is no way to automatically determine how many arguments a function is expecting for all functions. Many var-arg functions declare no formal arguments and uses the arguments object exclusively.
All you can reliably do is to check it manually in each function like Cranio suggested.
If you want to have automated checks, e.g. as part of your unit tests, you can make use of the length property of the Function objects, which returns the number of formal arguments. For var-arg functions, just don't include the check. For example:
function checkNumberOfArguments(args) {
if (args.length != args.callee.length) {
throw new Error('Wrong number of arguments');
}
};
// Use it like
function a(b) {
checkNumberOfArguments(arguments);
}
a(1);
a(1,2);
Inside function you can use arguments object, it contains an array of all the arguments that were supplied to the function when it was called.
function x(){
return arguments.length;
}
x()
=> 0
x(1,1,1,1,1,1,1,1,1)
=> 9

Categories