Object equals another object syntax [duplicate] - javascript

This question already has answers here:
Set a default parameter value for a JavaScript function
(29 answers)
Closed 4 months ago.
There is a function in the testing section in the redux docs and I'm trying to figure out what this syntax means.
export function renderWithProviders(
ui,
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState),
...renderOptions
} = {}
) {
function Wrapper({ children }) {
return <Provider store={store}>{children}</Provider>
}
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }
}
It seems like there's an object being passed as an argument and then it's assigned to nothing? Trying to figure out what the {...properties} = {} syntax means in the function declaration.
Thank you!

It seems like there's an object being passed as an argument and then it's assigned to nothing?
I assume you're referring to the = {} at the end of (and at the start of):
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState),
...renderOptions
} = {}
That's default argument value syntax. To show a simpler example, if I had a paintCar function, and I wanted to default my car to an empty object if none is provided, I could do:
function paintCar(paintColor, car = {}) {
car.color = paintColor;
return car;
}
// this works, even though I didn't provide a car:
const redCar = paintCar('red'); // { color: 'red' }
// ... because JS defaults that argument to "{}"
For any argument, to any function, you can add a = something to make it default to that something. The only requirement is that all the defaults have to come last, so you can't do (say):
function fake(foo=1, bar){
(or technically you can, but when you do fake(someBar) it will get counted as the foo argument, not the bar argument)

Related

Store an object inside another object

I need to insert one object inside another, and I'm using this logic:
// Create object store
const store = {}
// Function to create 'Product' Objects
function createProduct (type, name, price) {
return { type, name, price }
}
// Function to add 'Product' Objects inside the 'Store' Object
function addToStore (obj) {
store.obj = obj
return store
}
const strawberry = createProduct ('fruit', 'strawberry', '0.40')
const peach = createProduct ('fruit', 'peach', '0.80')
addToStore(strawberry)
addToStore(peach)
console.log(store) // < { obj: { type: 'fruit', name: 'peach', price: '0.90' } }
How should I write this function so that store.obj be the same obj passed by parameter?
function addToStore (obj) {
store.obj = obj
return store
// What's happening in the run
function addToStore (peach) {
store.obj = peach
return store
// What I need to happen
function addToStore (peach) {
store.peach = peach
return store
If you mean that you want the property name to come from the name of the variable you use when calling addToStore, you can't quite do that, because when addToStore gets called, it just receives the value of that variable (the reference to the object), it doesn't receive any information about the variable itself.
The simple solution is to pass the name as a second argument:
function addToStore(name, obj) {
store[name] = obj;
return store;
}
// ...
addToStore("peach", peach);
Note the use of [] to make the property name come from the name parameter rather than using . with a literal name.
There is a way to make that a bit more automatic, at the (very small) cost of creating a temporary object, by using shorthand property syntax. Pass an object wrapper around the object you want, where the name of the property comes from the variable name, and have addToStore take the object from that wrapper (or perhaps take all of them, if you pass more than one):
function addToStore(objects) {
Object.assign(store, objects); // Will do the loop and assignments for you
return store;
}
// ...
addToStore({peach});
// ^^^^^^^−−−−−−−−−−− creating the object to pass in using shorthand syntax
You probably wouldn't want to do that in code that's going to do it millions of times in an hour because of the overhead, but short of that I wouldn't worry about it until/unless you ran into a performance problem you tracked down to it.

Javascript Set:Get Pointless?

I have been experimenting with getters and setters with the following pattern:
var mytab = {
_tab: undefined,
get: function () {
return this._tab;
},
set: function (tab) {
this._tab = tab;
return tab;
}
}
My question is, given you have to access those methods explicitly, ie:
mytab.get();
mytab.set('thistab');
Why bother having get or set at all? Why not call them whatever you like? ie:
var mytab = {
_tab: undefined,
getthetab: function () {
return this._tab;
},
setthetab: function (tab) {
this._tab = tab;
return tab;
}
}
I may have missed some fundamental principle here, but both these objects behave exactly the same.
I assumed having special 'setters' and 'getters' would allow the object to be modified using it's object name, ie:
var a = mytab;
mytab = 'thistab';
Or even:
var a = mytab();
mytab() = 'thistab';
This is what I expected, and what I wanted, however those instructions give errors, namely that mytab() is not a function.
I would appreciate some clarity on what special significance the set and get object methods actually have.
In your first example, you haven't declared getters/setters. You've created an object with two methods called get and set.
To declare getters/setters, you'll have to choose an arbitrary name, and prefix it with get or set, like:
var mytab = {
_tab: undefined,
get tab() {
return this._tab;
},
set tab(tab) {
this._tab = tab;
return tab;
}
}
In this case, they form a so-called accessor property, that has the chosen name:
console.log(mytab.get) //undefined
console.log(mytab.set) //undefined
mytab.tab = 'foo'
console.log(mytab._tab) //foo
mytab._tab = 'bar'
console.log(mytab.tab) //bar
console.log(Object.getOwnPropertyDescriptor(mytab, 'tab')) /*
{
get: function(){...},
set: function(tab){...},
...
}
*/
However, you cannot overload operators or otherwise define a single getter/setter pair for your objects, that would allow you to assign a value or read a value from the object itself.
You can only define getters/setters for the properties on the object.
So,
var a = mytab
or
mytab = a
cannot be intercepted, and doesn't do what you expect (the first assigns the object itself to another variable (a), while the second reassigns the variable mytab with the value of a without even affecting / interacting with the object).
The following use case can illustrate advantage of using getters and setters
var person = {
firstName: "John",
lastName: "Doe",
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
};
console.log(person.fullName);
Using getter we could use get fullName as if it was a property of person without the need of maintaining separate field.

Passing javascript object as an argument to a function - typescript equivalent

I'm trying to better understand the code in this example:
https://codesandbox.io/s/r5n96yvwnm
So there is this function (lines 9-11):
function MyCell({ value, columnProps: { rest: { someFunc } } }) {
return <a href="#" onClick={someFunc}>{value}</a>
}
What construct is it, and is it possible to translate it easily into Typescript? I mean, I could go ahead and create a typescript interface with all needed props but I was wondering, if there is any shorter way of doing so. I have never seen a construct like this, so any links with more explanation appreciated.
Thanks
function MyCell({ value, columnProps: { rest: { someFunc } } }) {
This part is using destructuring to pick the properties off of an object. It's the same as:
function MyCell(props) {
const value = props.value;
const columnProps = props.columnProps;
const rest = columnProps.rest;
const someFunc = rest.someFunc;
Doing this with typescript would look something like this (i'm guessing at some of the types in the interface):
interface MyCellProps {
value: number;
columnProps: {
rest: {
someFunc: () => void;
}
}
}
function MyCell: React.FC<MyCellProps>({ value, columnProps: { rest: { someFunc } } }) {
return <a href="#" onClick={someFunc}>{value}</a>
}
Sounds like the params are confusing you. MyCell is a function that takes a single parameter. That parameter is expected to be an object with properties value and columnProps. columnProps is also expected to be an object, with the property rest. rest is likewise expected to be an obj with prop someFunc.
This is called object destructuring, and in the specific case of using it in parameters, it's called unpacking (mdn).

creating one var object vs multiple var

For better code structure, I want to use a javascript object holding all properties instead of using multiple vars:
// 1. WAY
// This returns an error, as _inp cannot be accessed by input_value
// Uncaught TypeError: Cannot read property 'value' of undefined
var ref = {
_inp: input.target,
input_value: _inp.value,
....
};
// 2. WAY
// When using this, it works
var ref = {
_inp: input.target,
input_value: input.target.value,
....
};
// 3. WAY
// This obviously works, too.
var
_inp = input.target,
input_value = _inp.value,
My Question is, why does 3. Way works and 1.Way doesnt?
In example 1, _inp will be a property of an object. It isn't a variable. You can only access it from a reference to the object (and it won't be a property of the object until the object exists, which will be after the object literal has been evaluated, see also Self-references in object literal declarations).
Because _inp will only be filled in with the input.target value after passing through the entire var ref = { ... }; statement. This means that when you try to use it, it doesn't exist yet.
The 1st way don't work because you refers to "_inp" which is not an existing var. and the ref object is not fully created (that's why input_value: this._inp.value won't work either)
To create objects and assigning values to its properties, you can use a function (I keep most of your code):
var ref = {
_inp: input.target,
input_value: null,
init: function()
{
this.input_value = this._inp.value;
}
};
ref.init();
console.log(ref.input_value); // will contains the same as input.target.value
but usually, people create objects with all property with default values, and pass an argument to their init function:
var ref = {
_inp: null,
input_value: null,
init: function(input)
{
if (input)
{
this._inp = input.target;
this.input_value = input.target.value;
}
}
};
var input = {target:{value:"foo"}};
ref.init(input);

'this' is undefined in JavaScript class methods

I'm new to JavaScript. New as far as all I've really done with it is tweaked existing code and wrote small bits of jQuery.
Now I'm attempting to write a "class" with attributes and methods, but I'm having trouble with the methods. My code:
function Request(destination, stay_open) {
this.state = "ready";
this.xhr = null;
this.destination = destination;
this.stay_open = stay_open;
this.open = function(data) {
this.xhr = $.ajax({
url: destination,
success: this.handle_response,
error: this.handle_failure,
timeout: 100000000,
data: data,
dataType: 'json',
});
};
/* snip... */
}
Request.prototype.start = function() {
if( this.stay_open == true ) {
this.open({msg: 'listen'});
} else {
}
};
//all console.log's omitted
The problem is, in Request.prototype.start, this is undefined and thus the if statement evaluates to false. What am I doing wrong here?
I just wanted to point out that sometimes this error happens because a function has been used as a high order function (passed as an argument) and then the scope of this got lost. In such cases, I would recommend passing such function bound to this. E.g.
this.myFunction.bind(this);
How are you calling the start function?
This should work (new is the key)
var o = new Request(destination, stay_open);
o.start();
If you directly call it like Request.prototype.start(), this will refer to the global context (window in browsers).
Also, if this is undefined, it results in an error. The if expression does not evaluate to false.
Update: this object is not set based on declaration, but by invocation. What it means is that if you assign the function property to a variable like x = o.start and call x(), this inside start no longer refers to o. This is what happens when you do setTimeout. To make it work, do this instead:
var o = new Request(...);
setTimeout(function() { o.start(); }, 1000);
None of the previous answers had the full solution for me, so posting mine here.
I had a class, which was returning an error when I ran forEach on the method reference.
e.g.
class Foo {
hello (name) {
return `hello ${name}`
}
doGreet (name) {
return console.log(this.hello(name)) // <- 'this' is undefined
}
}
// print some names...
const foo = new Foo();
(['nick', 'john']).forEach(foo.doGreet)
// TypeError: Cannot read property 'hello' of undefined
// at doGreet (/.../test.js:7:17)
The solution was to the bind the context of the method's this within a constructor. i.e.
class Foo {
constructor () {
this.doGreet = this.doGreet.bind(this) // <- Add this
}
hello (name) {
return `hello ${name}`
}
doGreet (name) {
return console.log(this.hello(name))
}
}
JavaScript's OOP is a little funky (or a lot) and it takes some getting used to. This first thing you need to keep in mind is that there are no Classes and thinking in terms of classes can trip you up. And in order to use a method attached to a Constructor (the JavaScript equivalent of a Class definition) you need to instantiate your object. For example:
Ninja = function (name) {
this.name = name;
};
aNinja = new Ninja('foxy');
aNinja.name; //-> 'foxy'
enemyNinja = new Ninja('boggis');
enemyNinja.name; //=> 'boggis'
Note that Ninja instances have the same properties but aNinja cannot access the properties of enemyNinja. (This part should be really easy/straightforward) Things get a bit different when you start adding stuff to the prototype:
Ninja.prototype.jump = function () {
return this.name + ' jumped!';
};
Ninja.prototype.jump(); //-> Error.
aNinja.jump(); //-> 'foxy jumped!'
enemyNinja.jump(); //-> 'boggis jumped!'
Calling this directly will throw an error because this only points to the correct object (your "Class") when the Constructor is instantiated (otherwise it points to the global object, window in a browser)
Use arrow function:
Request.prototype.start = () => {
if( this.stay_open == true ) {
this.open({msg: 'listen'});
} else {
}
};
In ES2015 a.k.a ES6, class is a syntactic sugar for functions.
If you want to force to set a context for this you can use bind() method. As #chetan pointed, on invocation you can set the context as well! Check the example below:
class Form extends React.Component {
constructor() {
super();
}
handleChange(e) {
switch (e.target.id) {
case 'owner':
this.setState({owner: e.target.value});
break;
default:
}
}
render() {
return (
<form onSubmit={this.handleNewCodeBlock}>
<p>Owner:</p> <input onChange={this.handleChange.bind(this)} />
</form>
);
}
}
Here we forced the context inside handleChange() to Form.
This question has been answered, but maybe this might someone else coming here.
I also had an issue where this is undefined, when I was foolishly trying to destructure the methods of a class when initialising it:
import MyClass from "./myClass"
// 'this' is not defined here:
const { aMethod } = new MyClass()
aMethod() // error: 'this' is not defined
// So instead, init as you would normally:
const myClass = new MyClass()
myClass.aMethod() // OK
If a function has been used as a high order function (passed as an argument) the scope of this gets lost.
To fix this problem one can bind this to the function like #Eliux described:
this.myFunction.bind(this);
To automate this process like #DanielTonon wanted you can do this in the constructor:
Object.getOwnPropertyNames(YourClass.prototype).forEach((key) => {
if (key !== 'constructor') {
this[key] = this[key].bind(this);
}
});
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

Categories