Method Syntax in Object Literal notation? - javascript

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.

Related

How to call/manipulate a deconstructed object when it's a function's parameters

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

What do the square brackets in the following React test do?

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"}

How can I get a property name inside the property itself in Javascript?

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);

Expose private variables in Revealing Module Pattern

I'm trying to implement the Revealing Module Pattern but I'm unable to expose a modified private property.
var myRevealingModule = (function(){
var name = 'Diogo';
function setName () {
name = name + ' Cardoso';
}
return {
fullName: name,
set: setName
};
}());
// Sample usage:
myRevealingModule.set();
console.log(myRevealingModule.fullName); // "Diogo" instead of the excepted "Diogo Cardoso".
return {
fullName: name,
set: setName
};
That uses the values of name and setName. It does not create a reference to the variable. Effectively, name is copied.
You need to create a corresponding getName method, to take advantage of closures so that you can keep a reference to a variable.
var myRevealingModule = (function(){
var name = 'Diogo';
function setName () {
name = name + ' Cardoso';
};
function getName () {
return name;
};
return {
fullName: name,
set: setName,
get: getName
};
}());
http://jsfiddle.net/yeXMx/
If your value is an attribute in an object or array, you can export the object or array and the export will be by reference so outside users will see updated changes. It's a little risky since the generic pattern of exporting variables has the scalar/object copy/reference dichotomy.

simple "this" issue with JavaScript fundamentals

var name = 'Mike';
var person = {
name: 'John',
welcome: function(){
var name = 'Mary';
return 'Hi ' + this.name;
}
}
//person.welcome();
// output is
// Hi John
// I was expecting output to be
// Hi Mary
person.welcome.call();
// output is
// Hi Mike
// In this case since no argument is passed to call so this is window and
// I get that window.name is Mike
var name = 'Mike';
var person = {
name: 'John',
welcome: function(){
var name = 'Mary';
return 'Hi ' + this.name;
}
}
this.name refers to the object property "name"
name refers to the variable "name"
You would get the expected result with return 'Hi ' + name;
Why were you expecting Hi Mary in the first case?
var name = 'Mary';
Doesn't overwrite this.name, but rather creates a local variable named name in the function.
In the second case, you are using call, which takes a this argument, and:
Determines the value of this inside
fun. If thisArg is null or undefined,
this will be the global object.
From here.
this always refers to the object you are calling the function from. In most simple cases this would be whatever is in front of the .. For example, in the case of person.welcome() this now refers to person. If you call person.welcome.call() this refers to the window, because you did not specify anything as a parameter to call().
If you are waiting the output to be Hi Mary then you do not need to use this in the welcome function. This should do it:
var name = 'Mike';
var person = {
name: 'John',
welcome: function(){
var name = 'Mary';
return 'Hi ' + name;
}
}
When you do person.welcome() the this keyword references person, so on the welcome function this.name would become person.name which is John.

Categories