I am trying to figure out what is the difference between;
let foo = ({ bar() {} });
and
let foo = { bar() {} };
I am not clear why code uses surrounding parentheses
const actions = ({
setCounter ({ commit }, obj) {
commit(MAIN_SET_COUNTER, obj)
}
})
What I tried;
I assumed as IFEE but I could not understand how does it work
I assumed as a shorthand of function declaration
The two first examples you show are semantically identical. In both cases, foo is assigned an object literal with a Method definition. The braces don't make a difference. As comments suggest, var foo = 1; is identical to var foo = (1);. In the third example, they are also not necessary. Note, that they also are not a mistake.
There are examples, where such braces make a difference, but they are not the ones you show. Some that come to mind:
Returning an object from an arrow function, shorthand version: let foo = () => ({});, differentiates from an empty code block.
Differentiating a code block from a stand-alone object, e.g. in the console: {} + []; vs ({}) + [];
IIFE, turning a function declaration statement into an expression: (function f(){})();, whereas function f(){}(); would result in an error.
Related
I'm new to both ES6 and React and I keep seeing arrow functions. Why is it that some arrow functions use curly braces after the fat arrow and some use parentheses?
For example:
const foo = (params) => (
<span>
<p>Content</p>
</span>
);
vs.
const handleBar = (e) => {
e.preventDefault();
dispatch('logout');
};
The parenthesis are returning a single value, the curly braces are executing multiple lines of code.
Your example looks confusing because it's using JSX which looks like multiple "lines" but really just gets compiled to a single "element."
Here are some more examples that all do the same thing:
const a = (who) => "hello " + who + "!";
const b = (who) => ("hello " + who + "!");
const c = (who) => (
"hello " + who + "!"
);
const d = (who) => (
"hello "
+ who
+ "!"
);
const e = (who) => {
return "hello " + who + "!";
};
You will also often see parenthesis around object literals because that's a way to avoid the parser treating it as a code block:
const x = () => {} // Does nothing
const y = () => ({}) // returns an object
One can also use curly braces to prevent a single line arrow function from returning a value -- or to make it obvious to the next developer that a single line arrow function shouldn't, in this case, be returning anything.
For example:
const myFunc = (stuff) => { someArray.push(stuff) }
const otherFunc = (stuff) => someArray.push(stuff)
console.log(myFunc()) // --> logs undefined
console.log(otherFunc()) // --> logs result of push which is new array length
Parenthesis are used in an arrow function to return an object.
() => ({ name: 'YourName' }) // This will return an object
That is equivalent to
() => {
return { name : 'YourName' }
}
Actually in a briefcase when somebody uses braces in an arrow function declaration, it is equal to below:
const arrow = number => number + 1;
|||
const arrow = (number) => number + 1;
|||
const arrow = (number) => ( number + 1 );
|||
const arrow = (number) => { return number + 1 };
Parenthesis has an implicit return statement while curly braces you need an explicit return statement
If you use curly braces after the arrow to define the function body, you have to use the 'return' keyword to return something.
For example:
const myFun1 = (x) => {
return x;
}; // It will return x
const myFun2 = (x) => {
x;
}; // It will return nothing
If you use the parenthesis, you don't need to mention the 'return' keyword.
For example:
const myFunc1 = (x) => x; // It will return x
const myFunc2 = (x) => (x); // It will also return x
In your first example, the right-hand side of the arrow function shows a single expression that is enclosed by a grouping operator:
const foo = (params) => (
<span>
<p>Content</p>
</span>
);
A similar comparable case would be the following:
const foo = (params) => (<span><p>Content</p></span>);
A distinction, in the above cases using single expressions, is that the right-hand side is the returned value of the function.
On the other hand, if you use curly braces, JavaScript will understand that as a statement:
const foo = (params) => {} // this is not an object being returned, it's just an empty statement
Therefore, using statement is a good start for you to have code in it, multiple lines, and it will require the use of "return" if the function is intended to return value:
const foo = (params) => {
let value = 1;
return value;
}
In case you wanted to return an empty object in the shortest form:
const foo = (params) => ({})
See tests
To answer a duplicate post(question posted here), just for reference for others:
var func = x => x * x;
// concise body syntax, implied "return"
var func = (x, y) => { return x + y; };
// with block body, explicit "return" needed
For reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Function_body
Also note:
If you are returning an object literal as the result from a fat arrow function, then you must enclose the object in parentheses, e.g., myFunc = () => ({ data: "hello"}). You will receive an error if you omit the parentheses because the build tools will assume that the curly braces of the object literal are the start and end of a function body.
Every function has 2 aspects.
First of them is that each one, not just the arrow functions, has an execution context (a block scope) in which the variables are created and used.
In other words, inside the curly braces { ... } of the function, what is declared and assigned there, stays there and is not visible to the outside functions / or variables.
For example, when writing something as
let x = 100;
function doSomething() {
let x = 50;
console.log(x);
}
doSomething(); // 50
console.log(x); // 100
both values are displayed in console (instead of 'x from outside just being replaced by x from inside the function').
You see that despite of let not usually allowing other variable x to be declared again (with the same name x), in this case, because the second x is declared and initialized inside the { ... }, it does not alter the outside one, which also happens because after the function doSomething is called, the x from inside of it is created, assigned, printed in console and then destroyed (deleted from the memory). So that process happens every time we call that function by running doSomething() .
So this is the first aspect to take into consideration when understanding the functions: they execute then forget the values created by the code inside their curly braces.
Because of it, it's easier to understand their second aspect -- as functions cannot just work isolated from the others, they need to also send data to the others, so they have some 'reporting aspect' used to externalize some part of the results computed inside their curly braces, which is exactly why the return statement exists.
Return exists in each function, even in the console.log or alert(), even in doSomething(), but in these cases where we didn't explicitly set something for it, it is always 'return undefined'.
Therefore it isn't necessary to write it, but instead know that where you don't return something specific, the function itself will do it for you by returning undefined.
When you write (or use) a function meant just to execute something, it will also return undefined. Always.
You can check that thing with every function which (apparently) has no declared return:
let x = alert(100);
console.log(x); // undefined
let y = doSomething(); // console prints 50
console.log(y); // 50, then undefined --- 2 lines
console.log(alert('Hello')); // undefined
console.log(console.log('Okay')); // Okay , then undefined
Why is that?
Because alert() which is a method of global object window (in browser) (so it is actually window.alert() ) and also console.log() (which is the same with window.console.log() , too), execute something (printing in an alert box or in the console whatever is in between the () AND THEN return undefined).
Now, coming back to the arrow functions, they are not just some new way of notation for writing the functions but they also have some specific features.
First, if you only have a parameter between the () in an arrow function, you can write it without the parentheses.
Second, if inside the curly braces there's a single statement, you can omit as well the curly braces.
Third one, if the single statement is a return statement, you can omit the word return.
Somehow, using these we could transform many usual functions into arrow functions if needed:
function doSomething() {let x = 50; console.log(x);} // as function declaration
let doSomething = function() {let x = 50; console.log(x);}; // as function expression, which is an anonymous function assigned to the variable 'doSomething'
let doSomething = () => {let x = 50; console.log(x);}; // as arrow function
// let's transform it further
let doSomething = () => {console.log(50)}; //
// that is equivalent to ---- let doSomething = () => {console.log(50); return undefined};
// or even to ---- let doSomething = () => {return ( console.log(50) ) };
// because anyways, *console.log* has *return undefined* in it, as explained above
//which is the same as ---- let doSomething = () => {return console.log(50) };
// let's now apply the rules 2 and 3 from above, one by one:
let doSomething = () => return console.log(50);
let doSomething = () => console.log(50);
// Obviously, this just shows how we could rewrite many usual functions (functions declarations) into arrow functions
// we can do that safely if we don't have any **this** involved in the functions, of course
// also, from all lines of code above only one must remain, for example the last one.
// the last one, despite only having ---- console.log(50) --- as the execution aspect, it also ---- returns undefined ---- as well
// obviously ---- console.log( typeof doSomething ); // function
// while ---- console.log( typeof doSomething() ); // undefined
If an arrow function has 2 or more parameters, we cannot omit the parentheses around them:
function sum(a, b) {let total = a + b; return total}
let sum = function(a, b) {let total = a + b; return total};
// or
let sum = (a, b) => {let total = a + b; return total};
// or
let sum = (a, b) => {return a + b};
// or
let sum = (a, b) => a + b;
For simple operations as above, the fat arrow sign '=>' can be "read" as is transformed into, in other words, a and b is (are) transformed into a + b.
Opposite to that, there are also functions that validate some data (for example checking the data type, etc), like this one
let isNumber = x => typeof x === "number";
// or
let isNumber = (x) => {return (typeof x === "number")};
// obviously,
isNumber("Hello, John!"); // false
Those DON'T transform the data, and thus the arrow sign can be read something more as with the condition that, or similar.
In other words, a function like
let double = x => x * 2 // 'double' is a function that transforms x into x*2
is not the same as a checking one (mostly used in filters, sort, and other kind of validating functions, usually as callback function, etc)
let isArray = arr => Array.isArray(arr) // that last one already returns boolean by itself, no need to write return (Array.isArray() etc)
Last thing to know about return is that when you write code in multiple lines, the ASI (Automatic Semicolon Insertion) will insert a ';' after return if you mistakenly press enter after writing the return word, which will break the code, therefore instead of
return
a+b;
your code will behave as
return;
a+b;
so you better write the code with parentheses as here:
return (
a + b
);
as explained in MDN website here, too.
I'm desperate for someone to give me just some concise information about when I should use which brackets where and why in JS ES6. I know the basics but when we start talking about arrow syntax I just lose it and then can't see why we're wrapping braces in brackets etc... I feel like in order to truly understand why we lay things out the way we do I need to first understand what all of the use cases are for both {} and ().
For example. I'm really struggling to work out syntax like this:
const func = (obj) => {
console.log(obj.a)
}
func({a: "blue"})
It's the func({a: "blue"}) part I'm struggling with here.
Here's another example:
makeSound({
a: "bark",
b: 2,
c: "hiss"
})
function makeSound(options)
console.log("the" + options.a + "was a " + options.c)
I don't know what to make of this. What are we doing at the top with makeSound? I can see we're making an object but then why aren't we just declaring it as a variable with standard let makeSound = {}. What are we actually doing here? Is makeSound nothing untill we make it into a function further down the code?
It's the func({a: "blue"}) part I'm struggling with here.
{a: "blue"} is an object literal. The resulting object is passed as an argument to func(...).
I can see we're making an object but then why aren't we just declaring it as a variable with standard let makeSound = {}.
Because it is only needed once.
let details = {
a: "bark",
b: 2,
c: "hiss"
};
makeSound(details);
… would give the same result, but now you've got a details variable you don't need any more.
Is makeSound nothing untill we make it into a function further down the code?
function declarations are hoisted so it is a function even though the declaration appears later on.
I understand your confusion as there are quite a lot of curly braces indeed!
First, objects.
You define an object using brackets like this.
const obj = { a: 1 };
But you can also define an object inline, directly in a function argument list, using an object literal like this:
myFunc({ a: 1 }); // same as myFunc(obj);
Then you have arrow functions.
Their bodies is defined using curly braces too, just as regular functions, in which case you have to use the return keyword if you want to return a value from your function:
const myFunc = (arg) => { return 'hello ' + arg; }
However, arrow function also support implicit return, if you omit the curly braces, the return value will be implicit:
const myFunc = (arg) => 'hello ' + arg;
Now, you can also use the curly braces for desctructuring assignment.
For example:
const { a } = { a: 1 };
Here the desctructuring happens to the left of = and it allows you to extract properties from objects and assign them to variables.
You can also use object destructuring in function arguments, to access specific properties, like so:
const myFunc = ({ name }) => 'Hello ' + name;
This is equivalent to:
const myFunc = (person) => 'Hello ' + person.name;
And you could call this function with an object literal like this:
myFunc({ name: 'Jo' });
const func = (obj) => {
console.log(obj.a)
}
(obj) is basically saying func function takes obj as an argument.
You can also write it as such if you are passing only one argument;
const func = obj => {
console.log(obj.a)
}
What the parenthesis does basically giving you the ability to add multiple arguments. So like below;
const func = (obj1, obj2) => {
console.log(obj1.a, obj2.a)
}
func({a: "blue"})
Next func({a: "blue"})
Basically here you are calling func function with an object as an argument as a short hand.
So you can call it also like this
const argument = {a: "blue"}
func(argument)
Also you might see a lot of this kind of code
const func = (obj1, obj2) => console.log(obj1.a, obj2.a)
See there aren't anymore the curly braces around the console.log(). You can omit curly braces when you have only one line in the function. When you have multiple lines you will need to use curly braces to wrap the function body like so
func = (obj) => {
if (obj.a === "blue") {
return true
}
return false
}
This question already has answers here:
Are variables declared with let or const hoisted?
(7 answers)
Closed 5 years ago.
Background
I have a functions that is responsible for generating a random number and making it available.
"use strict";
module.exports = function(args) {
let {
min,
max,
} = args;
let currNumber = genRandom(min, max);
const genRandom = (min, max) => Math.floor(Math.random() * max) + min;
const getNumber = () => currNumber;
return Object.freeze({
getNumber
});
};
Problem
For a reason I don't understand, when I run this code with Node.js 7.8, I get the error that genRandom is not defined.
But if I change the code from:
let currNumber = genRandom(min, max);
const genRandom = (min, max) => Math.floor(Math.random() * max) + min;
to:
const genRandom = (min, max) => Math.floor(Math.random() * max) + min;
let currNumber = genRandom(min, max);
then it works!
I don't understand why this happens. I thought that const and let were hoisted just like var, but this leads me to believe I am wrong.
Question
Can someone explain me this behavior ?
I thought that const and let were hoisted just like var, but this leads me to believe I am wrong.
Not really, let and const are indeed hoisted, or as I like to call it, half-hoisted. There are two big differences between var foo and let foo: Scope and initialization. You already know about the scope difference. The second one is that with var foo, both the declaration and the initialization (with undefined) of foo are hoisted. With let, only the declaration of foo is hoisted, not the initialization. foo is only initialized when the step-by-step execution of the code reaches the let foo statement. You can't use (read from or write to) an un-initialized identifier. This time during which you can't use the identifier is called the Temporal Dead Zone (TDZ).
Even with var, the initialization that's hoisted is the initialization with undefined, not the value on the right-hand side of the =:
console.log(typeof foo); // "undefined"
foo(); // TypeError: foo is not a function
var foo = () => {};
The change you've made, moving the declaration of getRandom up before the first use of it, is the correct thing to do. (Or use a function declaration, since the declaration as a whole [including the creation of the function] is hoisted.)
Let's look at this half-hoisting thing:
let foo = "outer";
function x()
{
console.log("...");
let foo = "inner";
console.log(foo);
}
x();
(let and const have block scope, but I'm using a function because I'll be constrasting with var in a moment.)
Within x, that inner foo can't be used until the let foo line. But, you can't access the outer foo above it; this fails:
let foo = "outer";
function x()
{
console.log(foo); // ReferenceError: `foo` is not defined
let foo = "inner";
console.log(foo);
}
x();
That's the half-hoisting: The declaration of the inner foo is hoisted, but the variable isn't initialized until the let foo statement. That means you can't use foo at all (not even from a containing scope) above the let foo line. The inner foo shadows the outer foo throughout the function, but you can't use it until it's initialized. This is covered in Let and Const Declarations in the spec.
This is in constrast with var:
var foo = "outer";
function x()
{
console.log(foo); // undefined
var foo = "inner";
console.log(foo); // "inner"
}
x();
That runs just fine because both the declaration and the initialization of foo (with undefined) are hoisted to the top of the function. (After hoisting, the var foo = "inner"; line becomes a simple assignment statement.) So the inner foo shadows the outer foo throughout, and is also accessible throughout, initially with its default value (undefined) and the later with "inner" (once that's been assigned to it).
Since the TDZ is temporal (related to time), not spatial (related to space or location within the scope), you can use an identifier created by let or const (or class) above its declaration, just not before its declaration. This fails because getNumber tries to access theNumber before it's initialized, while it's still in the TDZ:
const getNumber = () => theNumber;
console.log(getNumber()); // ReferenceError
let theNumber = 42;
This works because getNumber accesses theNumber after it's initialized:
const getNumber = () => theNumber;
let theNumber = 42;
console.log(getNumber()); // 42
One thing that const or let difference from var is that the variable is not accessible before declaration.
Just checkout the specification: http://www.ecma-international.org/ecma-262/6.0/#sec-let-and-const-declarations
The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.
Syntax
LexicalDeclaration[In, Yield] :
LetOrConst BindingList[?In, ?Yield] ;
LetOrConst :
let
const
BindingList[In, Yield] :
LexicalBinding[?In, ?Yield]
BindingList[?In, ?Yield] , LexicalBinding[?In, ?Yield]
LexicalBinding[In, Yield] :
BindingIdentifier[?Yield] Initializer[?In, ?Yield]opt
BindingPattern[?Yield] Initializer[?In, ?Yield]
I have 2 files:
testrequire.js
let a = {};
function foo() {
a = 'test';
};
module.exports.foo = foo;
module.exports.a = a;
test.js
let a = require('./testrequire');
a.foo();
console.log(a);
When I run test.js, this is the result:
{ foo: [Function: foo], a: {} }
But I expect it to be like this:
{ foo: [Fuction: foo], a: 'test' }
However, when I change testrequire.js like this:
let a = {};
function foo() {
a.b = 'test';
};
module.exports.foo = foo;
module.exports.a = a;
The result is:
{ foo: [Function: foo], a: { b: 'test' } }
And it is perfectly like what I expected.
The question here is: Why function foo() can modify a's properties while it cannot modify a?
P/S: I did try var instead of let and the result is still the same. So it is definitely not ES6 let fault.
It's a pointer thing. It's the same in C/C++, Java etc. We've gotten so used to closures that we've sort of expect regular pointers to work the same. But pointers/references are simple indirections.
Let's walk through your code:
let a = {};
Create an object ({}) and point the variable a to that object.
function foo() {
a = 'test';
};
Declare a function foo() that overwrites the value of a with a string. Now, if you remember your C/assembly then you'd remember that the value of a pointer is the address of the thing it points to. So the original value of a is not {} but the address to that object. When you overwrite a with a string that object still exist and can be garbage collected unless something else points to it.
module.exports.foo = foo;
module.exports.a = a;
Export two properties, 1. foo which points to a function and 2. a which points to the same object that a is pointing to. Remember, just like in C/Java this does not mean that module.exports.a points to a but that it points to {}. Now you have two variables pointing to the same object {}.
Now, when you do:
a.foo();
All you're doing is changing the enclosed variable a to point to a string instead of the original object. You haven't done anything to a.a at all. It's still pointing to {}.
Workarounds
There are two ways to get what you want. First, the OO way. Don't create a closure for a, make it a regular object property:
function foo() {
this.a = 'test';
};
module.exports.foo = foo;
module.exports.a = {};
This will work as expected because modules in node.js are proper singletons so they can be treated as regular objects.
The second way to do this to use a getter to get the enclosed a. Remember that closures only work with functions, not objects. So just assigning the variable to a property like you did results in a regular pointer operation not a closure. The workaround is this:
let a = {};
function foo() {
a = 'test';
};
function getA() {
return a; // this works because we've created a closure
}
module.exports.foo = foo;
module.exports.getA = getA;
Now you can do:
a.foo();
a.getA(); // should return 'test'
foo can modify the variable a to point to something else.
But this has no effect on the object exported. When the require is done, the calling module receives whatever a pointed to at the time. After that, it does not care about what happens to (the variable) a.
In your second example, you are not assigning a to a new object, but you are modifying the existing object (by adding a new field). That will of course be visible to anyone who got hold of that object before.
This is (very roughly) analogous to
function callerDoesNotSeeThis(a){ a = 1 }
function callerSeesThis(a){ a.foo = 1 }
How does JavaScript deal with functions with names ending with ()? Consider for example the following piece of code:
var foo() = function () { }; // The empty function
var bar = function(foo) { var myVariable = foo(); };
It seems like there are two possible interpretations for what foo(); means:
Execute the argument foo. This assigns myVariable the returned value of foo.
Consider foo() as the name of the function defined at first. This assigns myVariable the empty function.
Is this even legal code? If so, what are the rules?
Is this even legal code?
No:
var foo() = function () { };
should be:
var foo = function () { };
If so, what are the rules?
In this case the foo argument will have precedence because it is defined in an inner scope than the foo function. So it's really a matter of scope: where is the variable defined. The interpreter first starts by looking in the innermost scope of the code, then in the outer, ... until it reaches the global scope (the window object).
So for example the result of the following code will be 123 as seen in this live demo:
var foo = function () { alert('we are in the foo function'); };
var bar = function(foo) { var myVariable = foo(); alert(myVariable); };
bar(function() { return 123; });
The () isn't considered part of the name. You'll probably get a syntax error. You can find some naming rules here.
In javascript, brackets mean execute. So your code will fail as it will be looking for a function foo on the first line.
Identifiers may not contain any parentheses, so the first statement is illegal. The second, however, is fine, myVariable = foo() executes the foo parameter and assigns the return value.
Do you really mean "Can I pass functions as references?" If so, then the answer is yes:
var foo = function() { return 2; }
var bar = function(fn){ return fn(); }
var two = bar(foo);