I'm reading "Mastering React Test-Driven Development", and one of the refactorings the book recommends is extracting a common test into a helper function, by changing this:
it('saves existing first name when submitted', async () => {
expect.hasAssertions();
render(<CustomerForm {...{firstName: 'Ashley'}} onSubmit={(customer) =>
expect(customer.firstName).toEqual('Ashley')} />);
await ReactTestUtils.Simulate.submit(form('customer'));
});
it('saves existing last name when submitted', async () => {
expect.hasAssertions();
render(<CustomerForm {...{lastName: 'Jones'}} onSubmit={(customer) =>
expect(customer.lastName).toEqual('Jones')} />);
await ReactTestUtils.Simulate.submit(form('customer'));
});
...to this:
const itSavesExistingValueWhenSubmitted = (fieldName, fieldValue) => {
it('saves existing value when submitted', async () => {
expect.hasAssertions();
render(<CustomerForm {...{[fieldName]: fieldValue}} onSubmit={(props) =>
expect(props[fieldName]).toEqual(fieldValue)} />);
await ReactTestUtils.Simulate.submit(form('customer'));
});
}
itSavesExistingValueWhenSubmitted('firstName', 'Ashley');
itSavesExistingValueWhenSubmitted('lastName', 'Jones');
My question is about the code snippet {...{[fieldName]: fieldValue}} in the refactored test. I get that the ... is a spread attribute for the subsequent {} object. But why does fieldName need to be wrapped in square brackets? What is the grammar here?
{...{[fieldName]: fieldValue}}
Here [fieldName] is a computed property name. Computed property name is a feature that allows to use a value of a variable as a property name.
So when you pass fieldName as "firstName", "firstName" will be used as the property name, whereas if you omit [], the property name will literally be "fieldName" not the value of fieldName.
This is a feature of ES6. Refer this for more details
The square brackets is used to evaluate the object key in ES6.
You can do this way, for example:
var person = {};
var key = "name";
person[key] = "John";
console.log(person); // should print Object { name="John"}
But if you are using ES6 you can do the following to set the object:
var key = "name";
var person = {[key]:"John"};
console.log(person); // should print Object { name="John"}
Related
I'm new to JavaScript and I'm having a little trouble with execution context; the value of this.
Consider the following:
const name = "Mary";
const proto = {
hello: () => `Hello, my name is ${ this.name }.`
};
const greeter = name => Object.assign(Object.create(proto), { name });
const joe = greeter("Joe");
console.log(joe.hello());
I expected the log would be: Hello, my name is Joe. But this was instead the global object. It returned Hello, my name is Mary.
On the other hand:
const name = "Mary";
const proto = {
hello() { return `Hello, my name is ${ this.name }.` }
};
const greeter = name => Object.assign(Object.create(proto), { name });
const joe = greeter("Joe");
console.log(joe.hello());
This time the expected string was returned; the only difference is the "method definition" inside the proto object.
So my question is what is the second syntax even called?
It is not a function declaration nor a function expression, so what is it? Either way I expected the property accessor invocation from the 'greeter' object, 'joe' to associate this to the object itself.
And when should I use a function expression and when should I use this alternative form of declaring an object's method?
I hope this makes sense and thank you in advance for you attention.
I'm going through the lessons on freecodecamp for Javascript. In the ES6 tutorials there's: "use destructuring assignment to pass an object as a function's parameter"
While I understand how they converted it to this, I don't understand at all what the purpose is or how to call/use the values/whatever inside this function. I tried searching online, but couldn't find anything related to functions with deconstructed objects as their parameters. Basically I don't understand how I can call or manipulate, or what I'm to do with an object in this form
i.e.
let dog1 = {
name : "whitey",
colour: "white"
}
let dog2 = {
name : "blackey",
colour: "black"
}
//const {name,colour} = dog1
//let's me call each property like: console.log(name)="whitey"
var dogfunc = (dog1) =>{
const {name, colour} = dog1}
//which can be rewritten as:
var dogfunc = ({name, colour}) => {}
//Now I'm stuck, I don't understand how I would call each property of dog1 or dog2
//I thought the point would be to allow me call/edit either dog1 or dog2 properties.
The idea of destructuring assignment is to reduce the extra necessary code as well as to "only get what is needed".
Using your example, consider a function which receives a dog object and print its name:
const dogObject = {
name: "Doge",
breed: "Labrador"
}
function printDogName(dog){
console.log(dog.name);
}
// or using destructuring
function printDogNameWithInternalDestructuring(dog){
const { name } = dog;
console.log(name);
}
printDogName(dogObject); // Doge
printDogNameWithInternalDestructuring(dogObject); // Doge
If you read carefully, you can see that from the whole dog object (it can contain a lot of other properties), we are only interested in the name. So, in the body of our functions we needed to get this property from the received object.
Using destructuring assignment, we can move the destructuring to the function required arguments definition. The function definition specifies which kind of object we expect as argument and from this object which properties are required, in our case, the name.
function printDogNameWithDestructuring({name}){
console.log(name);
};
printDogNameWithDestructuring(dogObject); // Doge
From your example:
let dog1 = {
name : "whitey",
colour: "white"
}
let dog2 = {
name : "blackey",
colour: "black"
}
const {name,colour} = dog1
//let's me call each property like: console.log(name)="whitey"
console.log(name) // prints whitney
var dogfunc = (dog1) => {
const {name, colour} = dog1
console.log(name);
}
dogfunc(dog1); // prints whitney
dogfunc(dog2); // prints blackey
//which can be rewritten as:
var dogfunc = ({name, colour}) => {
console.log(name)
}
// or using a shorter syntax
var dogfunc = ({name, colour}) => console.log(name);
dogfunc(dog1); // prints whitney
dogfunc(dog2); // prints blackey
I was reviewing someones code and he have wrote a syntax which looks like this
export const actions = {
[ACTIONS.SOMEACTION.ATTEMPT.name] ({ commit }, payload) {
return new Promise((resolve, reject) => {
Can someone please explain me what the person is trying to do here? like if someone could explain this syntax?
There are two thing in the code.
Computed Property Names:
[ACTIONS.SOMEACTION.ATTEMPT.name](... this is setting the method for the object whose name will be equal to the value ofACTIONS.SOMEACTION.ATTEMPT.name.
Unpacking fields from objects passed as function parameters
({ commit }, payload)
The line { commit } take out the property commit of the object passed as first parameter to this function.
Eaxample
let str = "func"
let obj = {
[str]({commit},other){
console.log(commit,other);
}
}
obj.func({commit:"the value of commit"},"Other parameter");
This is either inside of an object or a class and declares a method.
[ACTIONS.SOMEACTION.ATTEMPT.name] is a
computed property name, the methods name will be whatever is stored inside ACTIONS.SOMEACTION.ATTEMPT.name.
({ commit }, payload) those are the two parameters the method takes, the first being an object that gets destructured, so the commit property gets taken out of it.
The method then creates and returns a Promise:
return new Promise((resolve, reject) => {
This is using computed property names with destructuring assignment.
Here,
[ACTIONS.SOMEACTION.ATTEMPT.name]
will be converted to the name of the function (due to computer property names). For instance, if ACTIONS.SOMEACTION.ATTEMPT.name was equal to "foo" your result will be somewhat equivlant to:
foo({commit}, payload) {
// ... function body ...
}
which can later be called using .foo(arg1, arg2)
Note: as we are inside an object the function keyword can be omitted.
The {commit} is using destructuring assignment which can be used to "unpack" properties from an object. In this case, commit will be equal to the commit property from arg1. So if you used your function like so:
.foo({commit:10, id:1}, "bar")
Then your function will "unpack" 10 from your first argument object and make that equal to commit.
I am trying to solve.
`let str = "func"
let obj = {
[str]({commit},other){
console.log(commit,other);
}
}
obj.func({commit:"the value of commit"},"Other parameter");`
How would I go about using the map function via ES6?
This is what I have so far.
var names = ["Will", "Rick", "Blake"];
var formalGreeting = (name) => {
names.map("Hello " + name);
}
You are missing a return in formalGreeting(). Can get rid of the {} block in arrow function and anything after => will be returned.
Also missing the function callback for map()
var names = ["Will", "Rick", "Blake"];
var formalGreeting = (arr) => arr.map(name => "Hello " + name);
console.log(formalGreeting(names))
Map takes a function so you just need to add the name => and return the value to push to the new array. This will get you started:
const namesArray = ["Will", "Rick", "Blake"];
const formalGreeting = names => names.map(name => `Hello ${name}`);
console.log(formalGreeting(namesArray));
ES6 considerations:
You don't need to wrap your code with {} for arrow functions that return one line of code
You should be using const and let to declare variables rather than var
String Templates are awesome, check them out!
Is there a way I can get a property`s name inside the property itself?
I mean something like this:
let myObj = {
myProperty: {
name: <propertyName>.toString()
}
};
console.log(myObj.myProperty.name); // Prints `myProperty`
No, there isn't. There's nothing available when the object initializer is evaluated that provides that information.
Presumably if this were a one-off, you'd just repeat the name. If it's not a one-off, you could give yourself a utility function to do it:
// Define it once...
const addProp = (obj, name, value = {}) => {
obj[name] = value;
value.name = name;
return obj;
};
// Then using it...
let myObj = {};
addProp(myObj, "myProperty");
addProp(myObj, "myOtherProperty", {foo: "bar"});
console.log(myObj.myProperty.name);
console.log(myObj.myOtherProperty.name);