js named function in parameter, can not access out of function - javascript

js named function in parameter, can not access out of function
Because the 5th edition of ECMAScript forbids use of arguments.callee() in strict mode.
mdn warning
So I decided do not use the callee, instead , I use a named function
The example in mdn
function factorial (n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);
become:
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : /* what goes here? */ factorial(n - 1) * n;
});
This is a good idea, but I want to reuse the function factorial
DEMO
function d(x){return x;}
d(function a(){});
d(a);// this is not work, a is undefined(works in ie, failed in ff and chrome)
This is bother me, as I know, the scope in js is function-level, why the second a is undefined ?
jsfiddle DEMO

You're really asking two questions here. The first is easy:
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : /* what goes here? */ factorial(n - 1) * n;
});
What you've got there works just fine. In other words, since you're naming your function (factorial), that identifier is available inside the function body, enabling recursion.
Your second question is a little trickier:
function d(x){return x;}
d(function a(){});
d(a);// this is not work, a is undefined(works in ie, failed in ff and chrome)
It is correct for a to be undefined. If you read the ECMAScript specification, section 13.2.1 clearly states that new execution context that's created includes the actual parameters (argument list). That is, a is defined within the execution context of d, not the caller. It looks like IE is expressing erroneous behavior.

The name of a function expression does not reference itself in the namespace it's defined in (IE bugs on this) but does reference itself within itself
[1].map(function foo() {return foo;});
// [function foo() {return foo;}]
foo;
// undefined
If you want a reference to the function so it can be re-used, create a reference to it, either go back to writing a function declaration (function as a statement), or set the function expression as a variable, and pass the variable as desired
var bar = function foo() {return foo;};
[1].map(bar);
// [function foo() {return foo;}]
foo;
// undefined
bar;
// function foo() {return foo;}
Note that inside the function named foo in this example, both foo and bar will point to the same function, unless bar is changed again later.
var bar = function foo() {return foo === bar;};
bar(); // true, bar is foo inside the function
// change value of bar, keep a reference to function foo
var temp = bar;
bar = 'something else';
temp(); // false, bar is no longer foo inside the function

You say that your previous example doesn't work, but I have to disagree with you,
[1,2,3,4,5].map(function factorial(n) {
return n == 0 ? 1 : factorial(n - 1) * n;
});
I tried this (yes I modified it a bit) using basic logging and it logged n-1 for every recursion indicating that the recursion works fine. I believe Paul explains just fine why.
I recommend, anyway, to change the way you're thinking here because imagine if you're finding factorial(100). You'd be doing
... * factorial(98 - 1) * 98 * 99 * 100
Imagine the overload. I recommend adding a optional parameter which is the sum of the currently evaluated factorials, your result is the same but the overload is way less.
[1,2,3,4,5].map(function factorial(n, sum) {
var sum = sum || 1;
return n == 0 ? 1 : factorial(n - 1, sum*n);
});

Related

What does (append = false) mean in javascript? [duplicate]

I would like a JavaScript function to have optional arguments which I set a default on, which get used if the value isn't defined (and ignored if the value is passed). In Ruby you can do it like this:
def read_file(file, delete_after = false)
# code
end
Does this work in JavaScript?
function read_file(file, delete_after = false) {
// Code
}
From ES6/ES2015, default parameters are in the language specification.
function read_file(file, delete_after = false) {
// Code
}
just works.
Reference: Default Parameters - MDN
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
In ES6, you can simulate default named parameters via destructuring:
// the `= {}` below lets you call the function without any parameters
function myFor({ start = 5, end = 1, step = -1 } = {}) { // (A)
// Use the variables `start`, `end` and `step` here
···
}
// sample call using an object
myFor({ start: 3, end: 0 });
// also OK
myFor();
myFor({});
Pre ES2015,
There are a lot of ways, but this is my preferred method — it lets you pass in anything you want, including false or null. (typeof null == "object")
function foo(a, b) {
a = typeof a !== 'undefined' ? a : 42;
b = typeof b !== 'undefined' ? b : 'default_b';
...
}
function read_file(file, delete_after) {
delete_after = delete_after || "my default here";
//rest of code
}
This assigns to delete_after the value of delete_after if it is not a falsey value otherwise it assigns the string "my default here". For more detail, check out Doug Crockford's survey of the language and check out the section on Operators.
This approach does not work if you want to pass in a falsey value i.e. false, null, undefined, 0 or "". If you require falsey values to be passed in you would need to use the method in Tom Ritter's answer.
When dealing with a number of parameters to a function, it is often useful to allow the consumer to pass the parameter arguments in an object and then merge these values with an object that contains the default values for the function
function read_file(values) {
values = merge({
delete_after : "my default here"
}, values || {});
// rest of code
}
// simple implementation based on $.extend() from jQuery
function merge() {
var obj, name, copy,
target = arguments[0] || {},
i = 1,
length = arguments.length;
for (; i < length; i++) {
if ((obj = arguments[i]) != null) {
for (name in obj) {
copy = obj[name];
if (target === copy) {
continue;
}
else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
return target;
};
to use
// will use the default delete_after value
read_file({ file: "my file" });
// will override default delete_after value
read_file({ file: "my file", delete_after: "my value" });
I find something simple like this to be much more concise and readable personally.
function pick(arg, def) {
return (typeof arg == 'undefined' ? def : arg);
}
function myFunc(x) {
x = pick(x, 'my default');
}
In ECMAScript 6 you will actually be able to write exactly what you have:
function read_file(file, delete_after = false) {
// Code
}
This will set delete_after to false if it s not present or undefined. You can use ES6 features like this one today with transpilers such as Babel.
See the MDN article for more information.
Default Parameter Values
With ES6, you can do perhaps one of the most common idioms in JavaScript relates to setting a default value for a function parameter. The way we’ve done this for years should look quite familiar:
function foo(x,y) {
x = x || 11;
y = y || 31;
console.log( x + y );
}
foo(); // 42
foo( 5, 6 ); // 11
foo( 5 ); // 36
foo( null, 6 ); // 17
This pattern is most used, but is dangerous when we pass values like
foo(0, 42)
foo( 0, 42 ); // 53 <-- Oops, not 42
Why? Because the 0 is falsy, and so the x || 11 results in 11, not the directly passed in 0. To fix this gotcha, some people will instead write the check more verbosely like this:
function foo(x,y) {
x = (x !== undefined) ? x : 11;
y = (y !== undefined) ? y : 31;
console.log( x + y );
}
foo( 0, 42 ); // 42
foo( undefined, 6 ); // 17
we can now examine a nice helpful syntax added as of ES6 to streamline the assignment of default values to missing arguments:
function foo(x = 11, y = 31) {
console.log( x + y );
}
foo(); // 42
foo( 5, 6 ); // 11
foo( 0, 42 ); // 42
foo( 5 ); // 36
foo( 5, undefined ); // 36 <-- `undefined` is missing
foo( 5, null ); // 5 <-- null coerces to `0`
foo( undefined, 6 ); // 17 <-- `undefined` is missing
foo( null, 6 ); // 6 <-- null coerces to `0`
x = 11 in a function declaration is more like x !== undefined ? x : 11 than the much more common idiom x || 11
Default Value Expressions
Function default values can be more than just simple values like 31; they can be any valid expression, even a function call:
function bar(val) {
console.log( "bar called!" );
return y + val;
}
function foo(x = y + 3, z = bar( x )) {
console.log( x, z );
}
var y = 5;
foo(); // "bar called"
// 8 13
foo( 10 ); // "bar called"
// 10 15
y = 6;
foo( undefined, 10 ); // 9 10
As you can see, the default value expressions are lazily evaluated, meaning they’re only run if and when they’re needed — that is, when a parameter’s argument is omitted or is undefined.
A default value expression can even be an inline function expression call — commonly referred to as an Immediately Invoked Function Expression (IIFE):
function foo( x =
(function(v){ return v + 11; })( 31 )
) {
console.log( x );
}
foo(); // 42
that solution is work for me in js:
function read_file(file, delete_after) {
delete_after = delete_after || false;
// Code
}
I would highly recommend extreme caution when using default parameter values in javascript. It often creates bugs when used in conjunction with higher order functions like forEach, map, and reduce. For example, consider this line of code:
['1', '2', '3'].map(parseInt); // [1, NaN, NaN]
parseInt has an optional second parameter function parseInt(s, [radix=10]) but map calls parseInt with three arguments: (element, index, and array).
I suggest you separate your required parameters form your optional/default valued arguments. If your function takes 1,2, or 3 required parameters for which no default value makes sense, make them positional parameters to the function, any optional parameters should follow as named attributes of a single object. If your function takes 4 or more, perhaps it makes more sense to supply all arguments via attributes of a single object parameter.
In your case I would suggest you write your deleteFile function like this: (edited per instead's comments)...
// unsafe
function read_file(fileName, deleteAfter=false) {
if (deleteAfter) {
console.log(`Reading and then deleting ${fileName}`);
} else {
console.log(`Just reading ${fileName}`);
}
}
// better
function readFile(fileName, options) {
const deleteAfter = !!(options && options.deleteAfter === true);
read_file(fileName, deleteAfter);
}
console.log('unsafe...');
['log1.txt', 'log2.txt', 'log3.txt'].map(read_file);
console.log('better...');
['log1.txt', 'log2.txt', 'log3.txt'].map(readFile);
Running the above snippet illustrates the dangers lurking behind default argument values for unused parameters.
Just use an explicit comparison with undefined.
function read_file(file, delete_after)
{
if(delete_after === undefined) { delete_after = false; }
}
As an update...with ECMAScript 6 you can FINALLY set default values in function parameter declarations like so:
function f (x, y = 7, z = 42) {
return x + y + z
}
f(1) === 50
As referenced by - http://es6-features.org/#DefaultParameterValues
being a long time C++ developer (Rookie to web development :)), when I first came across this situation, I did the parameter assignment in the function definition, like it is mentioned in the question, as follows.
function myfunc(a,b=10)
But beware that it doesn't work consistently across browsers. For me it worked on chrome on my desktop, but did not work on chrome on android.
Safer option, as many have mentioned above is -
function myfunc(a,b)
{
if (typeof(b)==='undefined') b = 10;
......
}
Intention for this answer is not to repeat the same solutions, what others have already mentioned, but to inform that parameter assignment in the function definition may work on some browsers, but don't rely on it.
To anyone interested in having there code work in Microsoft Edge, do not use defaults in function parameters.
function read_file(file, delete_after = false) {
#code
}
In that example Edge will throw an error "Expecting ')'"
To get around this use
function read_file(file, delete_after) {
if(delete_after == undefined)
{
delete_after = false;
}
#code
}
As of Aug 08 2016 this is still an issue
If you are using ES6+ you can set default parameters in the following manner:
function test (foo = 1, bar = 2) {
console.log(foo, bar);
}
test(5); // foo gets overwritten, bar remains default parameter
If you need ES5 syntax you can do it in the following manner:
function test(foo, bar) {
foo = foo || 2;
bar = bar || 0;
console.log(foo, bar);
}
test(5); // foo gets overwritten, bar remains default parameter
In the above syntax the OR operator is used. The OR operator always returns the first value if this can be converted to true if not it returns the righthandside value. When the function is called with no corresponding argument the parameter variable (bar in our example) is set to undefined by the JS engine. undefined Is then converted to false and thus does the OR operator return the value 0.
function helloWorld(name, symbol = '!!!') {
name = name || 'worlds';
console.log('hello ' + name + symbol);
}
helloWorld(); // hello worlds!!!
helloWorld('john'); // hello john!!!
helloWorld('john', '(>.<)'); // hello john(>.<)
helloWorld('john', undefined); // hello john!!!
helloWorld(undefined, undefined); // hello worlds!!!
Use this if you want to use latest ECMA6 syntax:
function myFunction(someValue = "This is DEFAULT!") {
console.log("someValue --> ", someValue);
}
myFunction("Not A default value") // calling the function without default value
myFunction() // calling the function with default value
It is called default function parameters. It allows formal parameters to be initialized with default values if no value or undefined is passed.
NOTE: It wont work with Internet Explorer or older browsers.
For maximum possible compatibility use this:
function myFunction(someValue) {
someValue = (someValue === undefined) ? "This is DEFAULT!" : someValue;
console.log("someValue --> ", someValue);
}
myFunction("Not A default value") // calling the function without default value
myFunction() // calling the function with default value
Both functions have exact same behavior as each of these example rely on the fact that the parameter variable will be undefined if no parameter value was passed when calling that function.
ES6: As already mentioned in most answers, in ES6, you can simply initialise a parameter along with a value.
ES5: Most of the given answers aren't good enough for me because there are occasions where I may have to pass falsey values such as 0, null and undefined to a function. To determine if a parameter is undefined because that's the value I passed instead of undefined due to not have been defined at all I do this:
function foo (param1, param2) {
param1 = arguments.length >= 1 ? param1 : "default1";
param2 = arguments.length >= 2 ? param2 : "default2";
}
As per the syntax
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
statements
}
you can define the default value of formal parameters.
and also check undefined value by using typeof function.
function throwIfNoValue() {
throw new Error('Missing argument');
}
function foo(argValue = throwIfNoValue()) {
return argValue ;
}
Here foo() is a function which has a parameter named argValue. If we don’t pass anything in the function call here, then the function throwIfNoValue() will be called and the returned result will be assigned to the only argument argValue. This is how a function call can be used as a default parameter. Which makes the code more simplified and readable.
This example has been taken from here
If for some reason you are not on ES6 and are using lodash here is a concise way to default function parameters via _.defaultTo method:
var fn = function(a, b) {
a = _.defaultTo(a, 'Hi')
b = _.defaultTo(b, 'Mom!')
console.log(a, b)
}
fn() // Hi Mom!
fn(undefined, null) // Hi Mom!
fn(NaN, NaN) // Hi Mom!
fn(1) // 1 "Mom!"
fn(null, 2) // Hi 2
fn(false, false) // false false
fn(0, 2) // 0 2
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Which will set the default if the current value is NaN, null, or undefined
Yes, using default parameters is fully supported in ES6:
function read_file(file, delete_after = false) {
// Code
}
or
const read_file = (file, delete_after = false) => {
// Code
}
but prior in ES5 you could easily do this:
function read_file(file, delete_after) {
var df = delete_after || false;
// Code
}
Which means if the value is there, use the value, otherwise, use the second value after || operation which does the same thing...
Note: also there is a big difference between those if you pass a value to ES6 one even the value be falsy, that will be replaced with new value, something like null or ""... but ES5 one only will be replaced if only the passed value is truthy, that's because the way || working...
Sounds of Future
In future, you will be able to "spread" one object to another (currently as of 2019 NOT supported by Edge!) - demonstration how to use that for nice default options regardless of order:
function test(options) {
var options = {
// defaults
url: 'defaultURL',
some: 'somethingDefault',
// override with input options
...options
};
var body = document.getElementsByTagName('body')[0];
body.innerHTML += '<br>' + options.url + ' : ' + options.some;
}
test();
test({});
test({url:'myURL'});
test({some:'somethingOfMine'});
test({url:'overrideURL', some:'andSomething'});
test({url:'overrideURL', some:'andSomething', extra:'noProblem'});
MDN reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
...meanwhile what Edge DOES support is Object.assign() (IE does not, but I really hope we can leave IE behind :) )
Similarly you could do
function test(options) {
var options = Object.assign({
// defaults
url: 'defaultURL',
some: 'somethingDefault',
}, options); // override with input options
var body = document.getElementsByTagName('body')[0];
body.innerHTML += '<br>' + options.url + ' : ' + options.some;
}
test();
test({});
test({url:'myURL'});
test({some:'somethingOfMine'});
test({url:'overrideURL', some:'andSomething'});
test({url:'overrideURL', some:'andSomething', extra:'noProblem'});
EDIT: Due to comments regarding const options - the problem with using constant options in the rest of the function is actually not that you can't do that, is just that you can't use the constant variable in its own declaration - you would have to adjust the input naming to something like
function test(input_options){
const options = {
// defaults
someKey: 'someDefaultValue',
anotherKey: 'anotherDefaultValue',
// merge-in input options
...input_options
};
// from now on use options with no problem
}
Just to showcase my skills too (lol), above function can written even without having named arguments as below:
ES5 and above
function foo() {
a = typeof arguments[0] !== 'undefined' ? a : 42;
b = typeof arguments[1] !== 'undefined' ? b : 'default_b';
...
}
ES6 and above
function foo(...rest) {
a = typeof rest[0] !== 'undefined' ? a : 42;
b = typeof rest[1] !== 'undefined' ? b : 'default_b';
...
}
Yes - proof:
function read_file(file, delete_after = false) {
// Code
console.log({file,delete_after});
}
// TEST
read_file("A");
read_file("B",true);
read_file("C",false);
Yeah this is referred to as a default parameter
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
Syntax:
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
statements
}
Description:
Parameters of functions default to undefined However, in situations it might be useful to set a different default value. This is where default parameters can help.
In the past, the general strategy for setting defaults was to test parameter values in the body of the function and assign a value if they are undefined. If no value is provided in the call, its value would be undefined. You would have to set a conditional check to make sure the parameter is not undefined
With default parameters in ES2015, the check in the function body is no longer necessary. Now you can simply put a default value in the function head.
Example of the differences:
// OLD METHOD
function multiply(a, b) {
b = (typeof b !== 'undefined') ? b : 1;
return a * b;
}
multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
// NEW METHOD
function multiply(a, b = 1) {
return a * b;
}
multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
Different Syntax Examples:
Padding undefined vs other falsy values:
Even if the value is set explicitly when calling, the value of the num argument is the default one.
function test(num = 1) {
console.log(typeof num);
}
test(); // 'number' (num is set to 1)
test(undefined); // 'number' (num is set to 1 too)
// test with other falsy values:
test(''); // 'string' (num is set to '')
test(null); // 'object' (num is set to null)
Evaluated at call time:
The default argument gets evaluated at call time, so unlike some other languages, a new object is created each time the function is called.
function append(value, array = []) {
array.push(value);
return array;
}
append(1); //[1]
append(2); //[2], not [1, 2]
// This even applies to functions and variables
function callSomething(thing = something()) {
return thing;
}
function something() {
return 'sth';
}
callSomething(); //sth
Default parameters are available to later default parameters:
Params already encountered are available to later default parameters
function singularAutoPlural(singular, plural = singular + 's',
rallyingCry = plural + ' ATTACK!!!') {
return [singular, plural, rallyingCry];
}
//["Gecko","Geckos", "Geckos ATTACK!!!"]
singularAutoPlural('Gecko');
//["Fox","Foxes", "Foxes ATTACK!!!"]
singularAutoPlural('Fox', 'Foxes');
//["Deer", "Deer", "Deer ... change."]
singularAutoPlural('Deer', 'Deer', 'Deer peaceably and respectfully \ petition the government for positive change.')
Functions defined inside function body:
Introduced in Gecko 33 (Firefox 33 / Thunderbird 33 / SeaMonkey 2.30). Functions declared in the function body cannot be referred inside default parameters and throw a ReferenceError (currently a TypeError in SpiderMonkey, see bug 1022967). Default parameters are always executed first, function declarations inside the function body evaluate afterwards.
// Doesn't work! Throws ReferenceError.
function f(a = go()) {
function go() { return ':P'; }
}
Parameters without defaults after default parameters:
Prior to Gecko 26 (Firefox 26 / Thunderbird 26 / SeaMonkey 2.23 / Firefox OS 1.2), the following code resulted in a SyntaxError. This has been fixed in bug 777060 and works as expected in later versions. Parameters are still set left-to-right, overwriting default parameters even if there are later parameters without defaults.
function f(x = 1, y) {
return [x, y];
}
f(); // [1, undefined]
f(2); // [2, undefined]
Destructured paramet with default value assignment:
You can use default value assignment with the destructuring assignment notation
function f([x, y] = [1, 2], {z: z} = {z: 3}) {
return x + y + z;
}
f(); // 6
I've noticed a few answers mentioning that using default params isn't portable to other browsers, but it's only fair to point out that you can use transpilers like Babel to convert your code into ES5 syntax for browsers that have limited support for modern JS features.
So this:
function read_file(file, delete_after = false) {
// Code
}
would be transpiled as this (try it out in the Babel REPL -> https://babeljs.io/repl/):
"use strict";
function read_file(file) {
var delete_after =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
//Code...
}
Of course, if you have no intention of using transpilation, then setting default params in the body of the function like others have demonstrated is perfectly fine as well.
Just a different approach to set default params is to use object map of arguments, instead of arguments directly.
For example,
const defaultConfig = {
category: 'Animals',
legs: 4
};
function checkOrganism(props) {
const category = props.category || defaultConfig.category;
const legs = props.legs || defaultConfig.legs;
}
This way, it's easy to extend the arguments and not worry about argument length mismatch.
export const getfilesize = (bytes, decimals = 2) => {
if (bytes === 0){
return '0 Bytes';
}else{
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
}
def read_file(file, delete_after = false)
# code
end
Following code may work in this situation including ECMAScript 6 (ES6) as well as earlier versions.
function read_file(file, delete_after) {
if(delete_after == undefined)
delete_after = false;//default value
console.log('delete_after =',delete_after);
}
read_file('text1.txt',true);
read_file('text2.txt');
as default value in languages works when the function's parameter value is skipped when calling, in JavaScript it is assigned to undefined. This approach doesn't look attractive programmatically but have backward compatibility.
The answer is yes. In fact, there are many languages who support default parameters. Python is one of them:
def(a, enter="Hello"):
print(a+enter)
Even though this is Python 3 code due to the parentheses, default parameters in functions also work in JS.
For example, and in your case:
function read_file(file, deleteAfter=false){
console.log(deleteAfter);
}
read_file("test.txt");
But sometimes you don't really need default parameters.
You can just define the variable right after the start of the function, like this:
function read_file(file){
var deleteAfter = false;
console.log(deleteAfter);
}
read_file("test.txt");
In both of my examples, it returns the same thing. But sometimes they actually could be useful, like in very advanced projects.
So, in conclusion, default parameter values can be used in JS. But it is almost the same thing as defining a variable right after the start of the function. However, sometimes they are still very useful. As you have may noticed, default parameter values take 1 less line of code than the standard way which is defining the parameter right after the start of the function.
EDIT: And this is super important! This will not work in IE. See documentation. So with IE you have to use the "define variable at top of function" method. Default parameters won't work in IE.
Yes, This will work in Javascript. You can also do that:
function func(a=10,b=20)
{
alert (a+' and '+b);
}
func(); // Result: 10 and 20
func(12); // Result: 12 and 20
func(22,25); // Result: 22 and 25

Javascript - Issue with Arrow Function

I'm beginner with Javascript and my teacher gave me this code :
var z = (x=>(y=>2*y)(x)+3)(5);
(Sorry for my English, I'm a French guy with a bad level of English ^^)
I have to re-write this code with simple functions but I'm not sure of myself.
For me, I can re-write this code like :
var x = 5;
var y = 2 * x;
var z = y + 3;
But, it's not re-write with simples functions.
My question is : can you help me to understand how arrow function works in this case and give me an idea how to re-write this code with simple functions.
Arrow functions that have a => b form implicitly return b when called. You can imagine them like:
function (a) { return b }
Additionally, your code sample is wrapped in () and immediately invoked, pattern known as the Immediately Invoked Function Expression (IIFE):
(a => b)(3)
which is the same as
(function (a) { return b })(3)
Where both functions get defined and invoked immediately, hence the name.
Now all you have to do is use these two ideas, implicit returns and IIFEs for arrow functions, to re-write your example as plain functions with explicit returns and regular IIFEs.
In other words:
Add return statements where they are assumed to exist (implicit in arrow functions)
Add function() around each arrow function's arguments.
Here's what is happening in your code sample in plain English:
Pass 5 into an IIFE which takes x
Pass that x down to another IIFE which takes y
Return 2 * y from the second IIFE
Add 3 to what was return from second IIFE
Return result from the first IIFE
Or as a math formula:
z = x = (2 * y) + 3
We have:
var z = (x=>(y=>2*y)(x)+3)(5);
The arrow function definition says that x=>(....) means (function(x){ return ...})
So
var z = (function(x) {
return (y=>2*y)(x)+3;
})(5);
We have now another arrow function y=>2*y, that means (function(y) { return 2*y}).
So
var z = (function(x) {
return (function(y) {
return 2*y;
})(x) + 3;
})(5);
And that's all.
Remember that (function(){})() it's an anonymous function declaration executed immediately. So at the end, the var z is a simple number.

javascript: will argument value change lead to parameter value change?

It is said in w3cschool that "If a function changes an argument's value, it does not change the parameter's original value."
However, i don't quite understand that with the following example:
function bar(a){
arguments[0] = 10;
console.log("a",a);//10
return a;
}
function foo(cc){
cc = 10;
return arguments[0];
}
console.log(bar(333));//10
console.log(foo(333));//10
I have tested them in both chrome and firefox.
From my understanding , if argument value changes can not lead to parameter value change, why 'bar' fail to return 333?
Given a function:
function bar(a) {
arguments[0] = 10;
return a;
}
Calling it like bar(50) will return 10, because the value inside bar's scope was replaced by 10.
What "If a function changes an argument's value, it does not change the parameter's original value." means is that doing:
var x = 90;
var y = bar(x);
console.log(y);
console.log(x);
// y is 10
// x is still 90
... won't change the value of x outside of bar.
For more info see:
W3Schools tutorial on function parameters
MDN's guide to functions (in particular the section on function scope)
As Rudolfs stated the rule is related to the variable in the outer scope. But it is not always true. For arrays & objects the rule is not applied
function modify(obj) {
obj.value = 'modified';
}
var objOuter = {value: 'original'};
console.log('The original value is ' + objOuter.value); //original
modify(objOuter);
console.log('The modified value is ' + objOuter.value); //modified

Reasonable uses for closure?

Lately, I have been seeing in my companies production code return with closure functions. Such as return (function() {...}()); And I do not like to see this, but I am not an authoritative source. I thought I would ask StackOverflow why and when this good/bad to use.
* NOTE *
Say your not concerned about namespace pollution because all of these functions are already in their on closure.
Example1a:
function foo(bar) {
return {
x: 1 + bar,
y: 1 - bar,
duration: (function() {
var i = 0,
len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return results;
}())
};
}
Example1b:
function barProcess(bar) {
var i = 0;
var len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return results;
}
function foo(bar) {
return {
x: 1 + bar,
y: 1 - bar,
duration: barProcess(bar)
};
}
Example1c:
function foo(bar) {
var i = 0;
var len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return {
x: 1 + bar,
y: 1 - bar,
duration: results
};
}
Observation:
Example1a:
The inner function takes advantage of closure if there is a need.
Example1b:
In case barProcess could require some closure which could make the argument list long and problematic to maintain.
Example1c:
There is no extra function creation per invocation.
It is easiest to debug (in my opinion).
Please if someone can give me some technical reasons for why Example a, b, or c should be used that would be fantastic.
So, my lame answer did not satisfy me, so I tried this. JS Perf Tests. Which I think to make my observations not too far off.
I don't think its possible to choose a clear winner between examples a,b anc c for every simple case.
In the example you give, version (c) is good enough so I would go with it. That said, version (a) keeps the i, len and results veriables in an even tighter scope so it definitely could be a good way to go if you want to keep "x" and "y" more separate from duration "b".
I'm not a fan of splitting things into separate named functions just for organizational or scoping reasons, like you did on example (b), because it tends to make the code more complicated and harder to follow. However, if the barProccess is an actual reuseable abstraction that you can give a clear name for then keeping it separate might be a good idea.
Say your not concerned about namespace pollution because all of these functions are already in their on closure.
I think you are exagerating a bit here. The inner IFFE is not 100% recommended like the outer IFFE is but restricting scope even more is still perfectly OK and I don't think its worth fighting against your coleagues over it.
1a: No closure is formed as the outer function, foo(), has not returned when the inner function executes. The inner function is an anonymous "self-executing" subroutine. Whereas a self-executing function can form a closure, this one neither does nor needs to. This is a slightly "showy" way to structure the code.
1b: No closure is formed as the outer function, foo(), straightforwardly calls the named function barProcess(), which returns a numeric value, not a function. This approach would be useful if barProcess() is also to be called from elsewhere in the code.
1c: No closure is formed. foo() comprises a straightforward block of code, which is simple to understand and will certaily do the job. As javascript for loops don't have their own scope, foo() will simplify to :
function foo(bar) {
for(var i=0, results=0; i<bar; i++) {
results += 1 + (results * bar);
}
return {
x: 1 + bar,
y: 1 - bar,
duration: results
};
}

handling on no argument in javascript functions

I have little experience in javascript but in other programming languages the following is possible, to set a default value for a missing parameter in a function.
For instance lets say i have a function
function foo(a , b)
return a + b
{
I would like to be able to call the above function with 1 parameter or with 2 parameters
one parameter case:
foo(2) //a =2 and b would be automatically set to a default no argument value,
two parameter case:
foo(1,2) // a = 1 , b = 2 => 3
Is this possible in javascript that is IE 8 compatible or using Jquery 1.7.2?
JavaScript functions allow you to call them with less parameters than specified.
What you're trying to accomplish is possible doing something like the following:
function foo(a , b){
if(typeof b === "undefined"){
b=3;
}
return a + b;
}
foo(5);//return 3;
I strongly suggest that you check for undefined and not rely on the || operator. I've spent hours debugging code that made that assumption and failed when passing 0 or another falsy value. The JavaScript type system can get really tricky, for example "0" is falsy.
ECMAScript Harmony (the next version) allows default parameters like in those other languages using the following syntax
function foo(a , b=3){
return a + b;
}
This does not work in IE8 like the first version though.
No, but you can simulate this effect manually with a tertiary operator or an if statement (just make sure you check for undefined!):
function foo(a, b) {
b = (typeof b === "undefined") ? 2 : b;
return a + b;
}
Yes, it's possible. If a parameter isn't passed, you get a special value "undefined". The following works for me:
function foo(a, b) {
a = a || defaultForA;
b = b || defaultForB;
}
Due to the way Javascript treats conversion to boolean, the following will all be considered undefined in the above code snippet:
undefined
null
0
"" (empty string)
false
So if those values are important to you, you'll need to explicitly test for undefined rather than the blanket "if not false" test being used above.
An undefined parameter evaluates as false, so you can do something like this in the beggining of your function foo:
a = a || 0;
b = b || 0;
That way if a or b exist, they will be evaluated with their own values and with 0 otherwise.
You can just test if you received a parameter:
function foo(a, b) {
if(typeof b === "undefined") {b = 2;}
}
By testing for "undefined" you can also accept parameters that evaluate to false (like null or "" or 0 or false)

Categories