Javascript function evaluation as variable [duplicate] - javascript

This question already has answers here:
Understanding JavaScript Truthy and Falsy
(9 answers)
Closed 12 months ago.
I wasn't really sure what to name this question, as that is almost the question itself.
Basically I was messing with some code and found something that I can't quite explain. Here's a simplification:
function foo (a, b) {
if (foo) {
console.log("foo is true");
} else if (!foo) {
console.log("foo is false");
}
}
foo();
This outputs "foo is true", but what I don't understand is how is Js evaluating a function without executing it ( lack of (); ) and how can I execute it even without passing parameters defined in the function.
Maybe I should say that the only language I really know is java.

It's simple:
Functions are just objects with an internal [[Call]] method.
All objects produce true when coerced to booleans.

In JavaScript, a function is a value (a somewhat special value, that you can call, using the () operator). In JavaScript, the following values are "false" when evaluated in a boolean context:
false
0
""
undefined
null
NaN
All other values are "true". Therefore, a function is always "true".

It is evaluating the reference to the function that the identifier foo is currently referring to. JavaScript uses object references to point to functions and variables, that you can change quite easily. This allows you to check which function you are currently referencing.

In Java your code would not be legal because the parameter signature has to match the function's parameter signature which includes the name of the function, and its parameter list.
In Javascript the only thing that matters is the name of the function. There is NO overloading in Javascript. This makes sense because Javascript's object model is based off of string -> function/property maps. Java's object model is more complex and nuanced which is why you can do overloading.
So in short. foo() will call your function foo, with a and b being undefined. If you call it with foo(5) a would be 5, and b would be undefined. If you called it with foo(5, 1, 3) a would be 5, b would be 1 and 3 would be ignored. I would guess that you can probably get at 3rd argument using the Javascript arguments variable. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Since a and b are undefined in your example, they evaluate to false. When you evaluate if(foo) you're passing the function object into the if() condition, and defined objects always evaluate to true. null and undefined both evaluate to false.
All falsey values in JavaScript

In javascript you're not required to pass any function arguments. When an argument is not passed the value of that argument is assumed to be undefined. It also prints "foo is true" because foo is defined as the function foo. You can see whats going on by running the following
function foo (a, b) {
console.log(typeof a);
console.log(typeof b);
console.log(typeof foo);
}
foo();
//it prints:
//undefined
//undefined
//function
Basically calling foo(); is like calling foo(undefined,undefined);

Related

Passing `null` as context object vs directly calling the function

From this question, given that I don't want to specify any context, hence, passing null to thisArg in call().
What would be the difference between line 2 and line 3 in the following code? Is there any benefit from doing one over the other?
function sum(a,b) { return a + b; }
var result1 = sum.call(null,3,4); // 7
var result2 = sum(3,4); // 7
Similarly for apply():
var arr = [1,2,4];
var result3 = Math.max.apply(null, arr); // 4
var result4 = Math.max(...arr); // 4
It depends on whether the function you're calling was defined in loose mode or strict mode.
When calling a loose-mode function, the following three things all call the function such that this within the call is the global object for the environment (globalThis, aka window on browsers):
Calling the function without setting this: fn()
Calling the function providing a this value of undefined: fn.call(undefined) and similar
Calling the function providing a this value of null: fn.call(null) and similar
With a strict mode function, the first two both cause this during the call to be undefined, and the third (explicitly setting it to null) sets it to (you guessed it) null.
Examples:
function loose() {
console.log(`loose: ${this === null ? "null" : typeof this}`);
}
loose();
loose.call(undefined);
loose.call(null);
function strict() {
"use strict";
console.log(`strict: ${this === null ? "null" : typeof this}`);
}
strict();
strict.call(undefined);
strict.call(null);
In the normal case, if you don't need to set this to anything in particular, just call the function so the default behavior takes place.
One wrinkle: If you have an array of arguments you need to spread out as discrete arguments to the function, in any even vaguely up-to-date environment, you can use spread notation to do that: fn(...theArray). If you're stuck in an obsolete environment, the rough equivalent is fn.apply(undefined, theArray).
If you have a specific need to set a specific this value, you can do that via call or apply (as you've found), including (for strict mode functions) undefined or null.
TJ Crowder has the detailed response here, but as a general rule:
fn.call(null): In almost all cases, just call the function.
fn.apply(null, args): This is useful in some cases where you have an array of arguments and your environment doesn't support ...args, but otherwise spreading the arguments is probably more conventional: fn(...args)

JavaScript Function Parameters vs Object Methods

Can someone explain to me the difference of when to use a function by feeding your variables into the parenthesis, and when to tack the function on after the variable with a period, like using the toString() function?
example code
function addMe(a){
a = a+1;
return a;
}
var num = 1;
addMe(num);
num.toString();
I'm not actually sure if my syntax is correct, but I want to know when to feed a variable as a parameter, like how I feed the variable num, to the addMe function. And when to use the function .toString() by putting a period after the variable and typing out the function.
could I have done something like this- provided I built my function correctly?
var num = 1;
num.addMe();
Thanks for the help!
The first is used for simple 'stand alone' functions, while the latter is used for object methods. E.g a number object by default has a toString() method. Some object methods may also require parameters to be passed between the parentheses.
Variables (a function declaration is just a function stored in a variable) are looked up in the scope chain (going up to the next outer scope until a variable with the name is found):
let a = 1; // outer scope
{ // inner scope
console.log(a); // looked up in "inner scope", than "outer scope"
}
Properties of an object are looked up in the objects prototype chain, so if you do
a.b
then a gets looked up in the scopes as explained above, then b is accessed on the resulting object (everything is an object in JavaScript, except for "nothing" (undefined, null)) by looking up the prototype chain. For a simple object, the chain is quite short:
const a = { b: 1 }; // object -> Object.prototype
Here b will be found in the object itself. However all objects inherit from the Object.prototype object, so if you add a property to that (please don't):
Object.prototype.test = 1;
you can then look it up on every object, as the lookup traverses up the prototype chain, and reaches Object.prototype:
console.log({}.test); // 1
Now for numbers (like in your case), they inherit the Number.prototype so you could do:
Number.prototype.addMe = function() {
console.log(this);
};
// two dots are needed to distinguish it from numbers with a fraction (e.g. 1.2)
1..addMe();
That said, now addMe can be called on every number, everywhere in your code. While that might seems useful, it is actually a pain as you don't know where a certain method was added
1..whereDoIComeFrom()
that makes code unreadable and unstructured. Instead if you need a certain functionality multiple times, abstract it into a function, don't touch the native prototypes.
I assume that addMe is just a simplified example, if it isn't, read on:
If you pass an argument to a function in JavaScript, the value will be copied (it is a bit more complicated with non primitives (everything except numbers, booleans etc.)) into the parameter variable of the function called so here:
function addMe(a){
a = a+1;
console.log(a); // 2
return a;
}
var num = 1;
addMe(num);
console.log(num); // 1 ... ?
you actually got two variables (a and num), changing a does not change num. But as you return a you can do:
num = addMe(num);
which copies the value of num into a, then increases a by one and then copues the value of a back to num.
When you did var num = 1 you created a JavaScript object. It looks just like a number but you can think of everything in JavaScript as an object (simplification) and all these objects have different features. So a number has some features, a string has some other features, etc.
You mentioned one feature: toString. Another feature would be toLowerCase.
toString and toLowerCase are functions that come with JavaScript. These functions are then "put on" all of these objects for us to use.
I can have a string variable like
var text = 'MY TEXT'
var lowercaseText = text.toLowerCase()
console.log(lowercaseText) // my text
This code will work because it was decided that the toLowerCase function should work on strings
I can also have an array (list of items)
const list = ['A', 'B', 'C']
const answer = list.toLowerCase()
console.log(answer)
But this code won't work because toLowerCase doesn't work on arrays. So you get the following error message: list.toLowerCase is not a function.
Basically its saying: I don't know what toLowerCase means when used on this list variable (array).
In JavaScript this is called prototypes. Prototype is a way for JavaScript to get some feature from another. Basically: I have all kinds of functions, what object can use what functions. This is called the prototype chain.
In both cases you are using a function. addMe is a function you created and toString is a function in JavaScript that has been placed on objects through this prototype-chain.
Im not actually sure if my syntax is correct
Yes your syntax is correct. Your addMe function is the standard way to create a function in JavaScript.
But i want to know when to feed a variable as a parameter, like how i
feed the variable num, to the addMe function.
Just like you did, you define a function and parameters like you did.
..and when to use the function .toString() by putting a period after
the variable and typing out the function.
When you want to place your function on a object so that all instances of that object can you that object.
In most cases, espcially when you are starting out. You don't have to worry about these prototypes. The way you did.
function addMe(number) {
return number+1
}
const answer = addMe(1) //2
Is a standard way of defining a function and calling it.

mocha assert.deepEqual when one of the values is a function?

Since functions are first-class objects, and can be passed inside of another js object, how can I do an assert in my tests to be sure I'm getting back the right function?
I'm using Q for promises, and mocha/chai/chai-as-promised for testing. My method returns different functions based on the if/else (I need to either redirect or use a different route).
I'll return something like:
fulfill({next: function(res) {return res.render('single-pages/site-map');}});
and my test looks like:
return assert.becomes(
page.helpers.checkIfSinglePage('site-map', null),
{next: function(res) {return res.render('single-pages/site-map');}}
);
but it's telling me that the returned values are not the same.
AssertionError: expected { next: [Function] } to deeply equal { next: [Function] }
Functions are compared by reference in JavaScript.
(function(){}) === (function(){}); // false
In fact, this is because functions are objects. At the moment (until ES7) everything in JavaScript except primitive value types (number, string, null, undefined, bool) is a reference and compares with reference equality checks.
You technically can check the two functions as two strings (comparing the code) and (assuming no old versions of firefox) it will compare equal for the same function - but that's a poor indication since two functions can mean opposite things:
var foo = (function(){
x = alert;
return function foo(){ x(); } // first function
})();
var bar = (function(){
x = console.log.bind(console,"BAR");
return function foo(){ x(); } // first function
})();
foo.toString() === bar.toString(); // true, but an incorrect check.
So to conclude, there is no way to know in JavaScript if two do the same without having a reference to them.
Instead, you can call .next and check that the rendered valuer is the same.

Next parameter is 'undefined' in jQuery, why? [duplicate]

This question already has answers here:
How does this JavaScript/jQuery syntax work: (function( window, undefined ) { })(window)?
(5 answers)
Closed 10 years ago.
In following code of jQuery, why next parameter is undefined
JavaScript:
(function(a,b){
....
})(window)
Here a=window but b=undefined, why is so?
That's a common technique to assure you have a true undefined value to check against since the undefined property of the window object used to be writeable and thus could not reliably be used in checks. Since only one parameter is handed over to the function, the second one is assured to be undefined. The name of that variable does not matter, it could be undefined but as well foobar or, as in this case, (because this is the shortest possible way saving valuable bytes) b.
Now you can safely check for undefinedness of variables, because you are sure about the value of b:
// overwriting the global undefined property works in old browsers
undefined = 3;
(function(a,b){
var asd; // not initialised, thus undefined
if (asd === undefined){
// should trigger, but won't because undefined has been overwritten to 3
}
if (asd === b){
// is safe, bcause you know that b is undefined
}
})(window)
New browsers (IE9, FF4+, Chrome) obey the EcmaScript5 specification and undefined is not writable any more.
Because you are not passing anything for the second parameter. You are passing just one, namely window.
Your code
(function(a,b){
....
})(window)
defines a function and calls it immediately. The last line above actually calls the function using the window parameter. If you pass 2 parameters there, b will not be undefined.
This is immediate javascript function syntax you're trying to use:
(/* function body */)(/* params */)
Named function defined like:
function addNumbers(a, b){
alert(a + b);
}
You call it:
addNumbers(1, 2)
Or similar immediate function (defined and executed at the same time):
(function(a, b){
alert(a + b);
})(1, 2)

Why does attempting to assign a value to a simple type's property in Javascript not throw an exception?

Simple types in Javascript are immutable and are not keyed collections like Objects. Why does the following code just return the value of the assignment without complaining?
var foo = 'bar';
foo.newProperty = 'blaha';
The second statement just returns 'blaha'. However if you now call foo.newProperty you naturally get undefined because simple types are not hashes. So the question is shouldn't the attempt at property assignment throw an exception the same way that you get a TypeError when trying to replace a value in a tuple in Python. Or is there some obscure feature of the syntax that makes foo.newProperty evaluate to something unexpected?
There is an obscure feature of the syntax that makes foo.newProperty work. :-) Strings and numbers can be either primitives or objects, and the interpreter will automagically convert from a primitive to an object (and vice-versa) if it sees the need to.
var foo = 'bar'; // `foo` is a primitive
alert(typeof foo); // alerts "string"
var foo2 = new String('bar'); // `foo2` is an object
alert(typeof foo2); // alerts "object"
The reason that adding a property to a primitive works, but then seems later not to have worked, is that the conversion is only for the purposes of the expression. So if I do:
foo.newProperty = 'blaha';
The primitive string value is retrieved from the foo variable and then converted from a primitive to an object for the expression, but only for the expression (we haven't assigned a new value to the variable foo, after all, it's just that the value retrieved from foo for the expression has been changed to make the expression work). If we wanted to ensure that foo referred to a String object, we'd have to do that on purpose:
foo = new String(foo);
foo.newProperty = 'blaha';
This automagic conversion is covered (a bit) in Section 9 ("Type Conversion and Testing") and Section 11.2.1 ("Property Accessors") in the spec, albeit in the usual awkward specification-speak style. :-)
Re your question "...is there a good reason for this automagic wrapping?" below: Oh yes. This automatic promotion from primitive to object is pretty important. For instance:
var foo = "bar";
alert(foo.length);
Primitives don't have properties, so if there weren't any auto-promotion, the second line above would fail. (Naturally, an implementation is free to optimize such that actual object creation isn't required, as long as it behaves as the spec dictates externally.) Similarly:
var foo = "bar";
alert(foo.indexOf('a')); // alerts 1
Primitives aren't objects, and so they don't have a prototype chain, so where does that indexOf property come from? And of course, the answer is that the primitive is promoted to a String instance, and String.prototype has indexOf.
More dramatically:
alert((4).toFixed(2)); // alerts "4.00"
Since numbers are also promoted as needed, it's perfectly acceptable to do that. You have to use the parens — e.g., the (4) rather than just 4 — to satisfy the grammar (since the . in a literal number is a decimal point rather than a property accessor), although if you wanted to be really esoteric you could use 4['toFixed'](2). I wouldn't. :-)

Categories

Resources