ES6 Fat Arrow and Parentheses `(...) => ({...})` [duplicate] - javascript

This question already has answers here:
ECMAScript 6 arrow function that returns an object
(6 answers)
Closed 6 years ago.
I've been working through some Graph QL/React/Relay examples and I ran into some strange syntax.
When defining the fields in Graph QL Objects the following syntax is used:
const xType = new GraphQLObjectType({
name: 'X',
description: 'A made up type for example.',
fields: () => ({
field: {/*etc.*/}
})
});
From what I gather this is just defining an anonymous function and assigning it to xType.fields. That anonymous function returns the object containing the field definitions.
I'm assuming with however the Graph QL schema mechanism works this has to be defined as a function returning an object rather than simply an object. But the part that has me confused is the parenthesis around the curly braces.
Is this to differentiate an object definition from a function definition? Is it for clarity's sake for the reader?
The only similar syntax a google search has found is in the airbnb style guide where it seems to be a readability/clarity thing.
Just looking for confirmation or an explanation beyond my assumptions as I start to play around with Graph QL a little more.

fields: () => ({
field: {/*etc.*/}
})
is a function that implicitly returns an object (literal). Without using () JavaScript interpreter interprets the {} as a wrapper for the function body and not as an object.
Without using parens: (), the field: ... statement is treated as a label statement and the function returns undefined. The equivalent syntax is:
fields: () => { // start of the function body
// now we have to define an object
// and explicitly use the return keyword
return { field: {/*etc.*/} }
}
So parents are not there for clarity. It's there for using implicit-returning feature of arrow functions.

It's for clarity's sake for the compiler as well as for the reader. The field: syntax in your example appears to be an unambiguous giveaway that this is an object literal, but take this code for instance:
let f = () => {
field: 'value'
}
console.log(f()) //=> undefined
You would expect this to log an object with field set to 'value', but it logs undefined. Why?
Essentially, what you see as an object literal with a single property, the compiler sees as a function body (denoted by opening and closing curly braces, like a typical function) and a single label statement, which uses the syntax label:. Since the expression following is it just a literal string, and it is never returned (or even assigned to a variable), the function f() effectively does nothing, and its result is undefined.
However, by placing parentheses around your "object literal," you tell the compiler to treat the same characters as an expression rather than a bunch of statements, and so the object you desire is returned. (See this article on the Mozilla Development Network, from the comments section.)
let g = () => ({
field: 'value'
})
console.log(g()) //=> { field: 'value' }

Related

Template literals in methods on objects Javascript

I am having an issue when trying to console.log a template literal. As you can see below, I have a simple object of samsung, which has a method where it turns on and prints the template literal to the console.
let samsung = {
model: "S21",
camera: "48px",
processor: "Snapdragon888",
turnOn: function(model, camera, processor) {
console.log(
`I have turned on! I am the ${model}, I have a ${camera} camera and a ${processor} processor`
);
},
};
console.log(samsung.turnOn());
I've tried it lots of different ways, using arrow functions, using the "this" operator, adding/removing parameters of the function, putting in "Samsung" instead of "this" etc. But it prints out the following no matter what: I have turned on! I am the ${model}, I have a ${camera} camera and a ${processor} processor
You didn't pass any parameters to the function, so they are by default undefined.
If you want to get the property value of the object, use this to reference the object:
let samsung = {
model: "S21",
camera: "48px",
processor: "Snapdragon888",
turnOn: function() {
console.log(
`I have turned on! I am the ${this.model}, I have a ${this.camera} camera and a ${this.processor} processor`
);
},
};
console.log(samsung.turnOn());
Just for you to understand the situation:
this can be used to reference the current object for an execution scope, in the case of your sample it's the object you defined.
Using that keyword allows you to access to any method (this.turnOn()) or property (this.camera) it has available.
One caution when using arrow-functions is that this will miss its value, so be careful when to use which syntax for defining your methods.
In your case it could've worked if you defined the function outside the object and just passed each parameter separately using the . operator.
const turnOn = (model, camera, processor) => {
console.log(
`I have turned on! I am the ${model}, I have a ${camera} camera and a ${processor} processor`
);
};
turnOn(object.model, object.camera, object.processor);
Or using this with the method defined inside the object to reference each property.

How to change a vue data variable using this and (multiple) dynamic bracket notations

I am trying to achieve the following:
I start of with a p element that contains the data variable "reportText.Scope_1_T_1", this variable contains the string: "Text to change";
On creation of this component, created() gets called and it fires off a call to the method createObject. The method createObject requires multiple arguments, but the only relevant argument is the second one, which includes the location of the data variable I want to change (in this case: "reportText.Scope_1_T_1");
The method createObject splits this argument/location based on the dots and returns an array. So the string "reportText.Scope_1_T_1" returns the array ["reportText", "Scope_1_T_1"];
Following that this array gets looped through and combined with the context (=this). First loop results in context = this["reportText"], second loop returns in context = this["reportText"]["Scope_1_T_1"].
After this I assign a new String to context (context = reply.fields)
My expectation was that this code would result in a change of the data variable this.reportText.Scope_1_T_1, but unfortunately nothing happens to this variable.
I have tried playing around with dot notation and bracket notation, but nothing really worked. For example if I try to change the code in my createObject method to this:
this.reportText.Scope_1_T_1 = "New String"; or
this["reportText"]["Scope_1_T_1"] = "New String";
It suddenly does work? I don't understand why. I even tried to see if I somehow make a copy of 'this' so it doesn't reference the same object, but as far as I see it doesn't make a copy. It does seems to be a reference problem, because it somehow points to a different location when I use my dynamic brackets.
Here is my relevant code(if you need more, please let me know):
<template>
<p>{{ reportText.Scope_1_T_1 }}</p>
</template>
<script>
export default {
data: function() {
return {
reportText: {
Scope_1_T_1: 'Text to change'
}
}
},
created() {
this.$store.getters.getAppPromise.then(app => {
this.createObject(app, 'reportText.Scope_1_T_1', 'String', '=irrelevantExpression');
})
},
methods: {
createObject(app, location, type, expression) {
if (type === 'String') {
app.createGenericOjbect(
{
fields: {
qStringExpression: expression
}
},
reply => {
let context = this;
location = location.split('.');
location.forEach(item => {
context = context[item];
});
context = reply.fields;
}
)
}
}
}
}
</script>
I would greatly appreciate it if anyone could help me figure out what the difference is between using my dynamically created context and a static context (like this: this["reportText"]["Scope_1_T_1"]). I think that's the key in solving this problem.
My code is based on this stackoverflow question:
Javascript Square Bracket Notation Multiple Dynamic Properties
It's just the final step that won't work. Assigning a new value to context at the end will just update that local variable, not the property of the object.
Instead what you need to do is grab a reference to the relevant object and then update the property. To grab the object you need to drop the final section from the location path. That final section is then the property name that needs to be updated:
let context = this;
const path = location.split('.');
const property = path.pop()
path.forEach(item => {
context = context[item];
});
context[property] = reply.fields;
The syntax used for property access hides some asymmetry in how the parts of the path are interpreted.
Consider this example:
const a = b.c.d.e
What happens is:
Start with b.
Grab the value in property c.
Grab the value in property d.
Grab the value in property e.
Assign that value to a.
All nice and symmetric, c, d and e all seems to work the same way.
Now consider flipping that example:
b.c.d.e = a
This is very different.
Start with b.
Grab the value in property c.
Grab the value in property d.
Assign a to the property e.
In this scenario the c and d properties are still just read operations but the e is handled totally differently. That final part is a write operation instead.
The key thing to appreciate here is that the final part of a 'path' like this is special when you want to set the value. Normally this hides behind the syntax but when you want to break it down like in your example you need to be conscious of what is actually going on.
Whether you use . or [] notation makes no difference to this behaviour, though to access properties dynamically you have to use [].

Why can I define an array literal as a parameter and get a Type Error in Javascript?

The internet, including Stackoverflow states that Javascript does not accept type specific parameters (one such article here). However, why does ES6 accept an array literal as the parameter for a function and when I pass a primitive it throws a Type Error?
I am having a hard time wrapping my head around what Javascript is doing in the background. I thought Javascript typically takes a variable name as the parameter in a function declaration and allocates memory for that name and assigns the value of whatever argument I pass to the parameter. I am not sure if this is exclusively in the Arguments Object or elsewhere also. In the example below, however, I do not have a variable name for the array literal. I just don't know how Javascript is interpreting this parameter.
In the code below I define a function using an array literal as the parameter and when I try to pass a primitive as an argument it produces a TypeError.
function box([width,height]) {
return `I have a box that is ${width} x ${height}`;
}
console.log(box([6,6])); //NO error
console.log(box(6)); //produces error, Webstorm says, "TypeError:
undefined is not a function"
This behavior is documented in the ES6 specification Destructuring assignments.
In the Runtime Semantics section, the definition of the array destructuring assignment is
ArrayAssignmentPattern : [ ]
Let iterator be GetIterator(value).
ReturnIfAbrupt(iterator).
Return IteratorClose(iterator, NormalCompletion(empty)).
It's pretty interesting to dig into it. The array destructuring assignment (so it is an assignment) expects an iterable, that is: an object for which obj[Symbol.iterator] is defined as a function returning an iterator. Try testing this in a console of a browser that supports it (tests done on Firefox 57). In fact when you do:
let [a,b] = 5 //smaller reproduction of the error
you will get TypeError: 5 is not iterable. Contrast with below:
let number = new Number(5);
number[Symbol.iterator] = function*() {
yield 5;
}
let [f,g] = number; // works, f === 5, g === undefined
Probably under the hood JS destructuring maps the named array indexes to a slot which represents the next iteration of the iterator. Numbers do not have a built-in [Symbol.iterator] property, hence the error

Why symbol-type key in Object have a bracket around them [duplicate]

This question already has answers here:
What do square brackets around a property name in an object literal mean?
(2 answers)
Closed 5 years ago.
I just started JS, wondering why there are [] around Symbol. For example: in an object.
var bow = {
[Symbol('apple')] : something,
[Symbol('banana')] : something,
....
}
Also, when it comes to iterator:
var iterableObject = {
[Symbol.iterator] : function() {.....}
}
Can anyone explain what is the use of these [] around them? I googled a while but didn't find satisfied answer, thank you in advance.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors
The bracket notation is just another way of accessing a property on an object. In particular, it's used when the property name is not valid for use with the dot notation, such as Symbol.iterator.
You may also want to look at computed property names: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
These are similar but are instead used to set properties when an object is defined rather than get properties from an already defined object.
The square brakets are just part of object literal syntax.
When you make an object using object literal syntax it is now possible to use variables to set the keys inside the object.
const string = 'whatever'
const normalObject = {
[string]: 'something else'
}
This results in normalObject having one property, 'whatever' pointing to 'something else'
// normalObject
{ whatever: 'something else' }
The use of brackets in object literal syntax is just to allow you to use a variable to set the key in an object.
bringing this back to your example this is just allowing you to use Symbols as keys in your object.
You may have noticed that this is a little weird. Up until very recently an object could only have String keys. Symbols are not the other thing you can use as keys in an object.
var bow = {
[Symbol('banana')] : something,
[Symbol('banana')] : something,
....
}
this will result in an object with two different Symbol(banana) pointing to something.

What's the difference when I enclose a method name inside a function in ' '? [duplicate]

This question already has answers here:
What is the difference between object keys with quotes and without quotes?
(5 answers)
Closed 9 years ago.
I have the following code:
var factory = {
query: function (selectedSubject) {
..
}
}
In Javascript is this the same as:
var factory = {
'query': function (selectedSubject) {
..
}
}
I have seen both used and I am not sure if there is any difference.
The standard requires a property name to be one of:
PropertyName :
IdentifierName
StringLiteral
NumericLiteral
that is, all of these are valid:
obj = {
"query": ....
'query': ....
query: ....
12e45: ....
}
Note that, contrary to the popular opinion, the standard does not require a name to be a valid identifier, only an "identifier name". This effectively means that you can use JS reserved words as property names:
x = {
if: 100,
function: 200,
}
console.log(x.if + x.function) // 300
Not that it's terribly useful in everyday programming, just a funny fact worth knowing about.
You can use both, but if there are spaces you can't use the first option. That's why there is a second option.
Valid JSON requires "" to surround property name of an anonymous object, but you can omit them if the property name is not reserved word or does't contain some special chars. Generally it is more safe to use "".

Categories

Resources