I've been using and loving babel (6.5.2) for a while now and find the new destructuring syntax great for writing clearer JavaScript.
Why doesn't the rest destructuring work (it generates a token error) anywhere in the array?
For example:
const [column, ...restOfColumns] = columns;
const objProps = column.valueChain.slice(0, -1);
const prop = column.valueChain[column.valueChain.length - 1];
//const [...objProps, prop] = column.valueChain
The commented out line would replace the preceding two lines with something much easier to read and understand.
The simple answer is that when you use the destructing syntax ..., it means everything else. Therefore when you try [...objProps, prop], it doesn't know what to assign to prop as you have assigned all values already to objProps
Related
I keep seeing functions that look like this in a codebase I'm working on:
const func = ({ param1, param2 }) => {
//do stuff
}
What exactly is this doing? I'm having a hard time finding it on google, because I'm not even sure what this is called, or how to describe it in a google search.
It is destructuring, but contained within the parameters. The equivalent without the destructuring would be:
const func = o => {
var param1 = o.param1;
var param2 = o.param2;
//do stuff
}
This is passing an object as a property.
It is basically shorthand for
let param1 = someObject.param1
let param2 = someObject.param2
Another way of using this technique without parameters is the following, let's consider then for a second that someObject does contain those properties.
let {param1, param2} = someObject;
It is an object destructuring assignment. Like me, you may have found it surprising because ES6 object destructuring syntax looks like, but does NOT behave like object literal construction.
It supports the very terse form you ran into, as well as renaming the fields and default arguments:
Essentially, it's {oldkeyname:newkeyname=defaultvalue,...}. ':' is NOT the key/value separator; '=' is.
Some fallout of this language design decision is that you might have to do things like
;({a,b}=some_object);
The extra parens prevent the left curly braces parsing as a block, and the leading semicolon prevents the parens from getting parsed as a function call to a function on the previous line.
For more info see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Beware, key errors during object destructuring assignment do NOT throw; you just end up with "undefined" values, whether it's a key error or some other error that got silently propagated as 'undefined'.
> var {rsienstr: foo, q: bar} = {p:1, q:undefined};
undefined
> foo
undefined
> bar
undefined
>
I'm learning functional programming and I'm trying to refactor a piece of old code using lodash FP.
Here's the code I have:
_.filter(x => isIdInArray(x)(xs))(otherXs)
It's too complicated to read and makes me feel a bit weird (smell ?)
My problem is that x value, that is the first argument of isIdInArray is declared this way:
const getId = _.get('id');
const isIdInArray = _.compose(_.includes, getId);
I can't use my lodash filter function this way:
_.filter(isIdInArray(xs))(otherXs)
I don't even know if it's feasible, but I'm pretty sure I can do something clearer or more readable.
Do you have some ideas ?
Try not to stuff all the fancy features that lodash gives you into a single line there.
Having a complex mechanism in one line may seem nice, but if you can't read it anymore its not very helpful at all.
For managing collections i usually use approaches like this:
var collection = [{id: 'a', someField: 1}, {id:'b', someField: 2}];
var theIdsYoureLookingFor = ['a'];
var filtered = collection
.filter(anyObject => _.includes(theIdsYoureLookingFor, anyObject.id))
.map(anyObject => anyObject.someField);
alert(filtered); // alerts 1
Which parses a collection of objects, filters for those who have an id that you consider valid and then maps those objects to a certain field.
Also don't ever use variable names like: x, xs
If you're writing production code, I recommend using a higher-level function. In your particular case I'd say you need _.intersectionBy:
const keepIfIdInArray = _.intersectionBy('id'); // 'id' can be replaced by your getId
const keepIfIdInOtherXs = keepIfIdInArray(otherXs);
keepIfIdInOtherXs(xs);
If you're doing this as an exercice, then I'd say you may need to decompose a little more. Notice that in lodash/fp, _.includes is curried so you should be able to write the following:
const getId = _.get('id');
const isIdInArray = arr => _.compose(_.includes(arr), getId);
const isIdInOtherXs = isIdInArray(otherXs);
_.filter(isIdInOtherXs)(xs);
This question already has answers here:
What does the construct x = x || y mean?
(12 answers)
Closed 6 years ago.
In JavaScript I recently realized you could use the OR || logical operator for assignment, and I want to know if it's considered bad practice.
In particular I have some functions that have optional array input, if the input is null or undefined I should just set it to an empty array [], if it has content it should take the content.
I found that using the assignment using the OR operator handles that perfectly in a single line, it's clean. However, it feels like the kind of thing that might be considered bad practice, or may have some horrible pitfalls I'm not considering.
Another approach is a simple if check, which is fairly safe in general.
I want to know if using the || approach seen below has any pitfalls I'm not considering, although it works in this scenario I would appreciate knowing if it works well to keep using this in the future, or to stop using it altogether.
https://jsbin.com/nozuxiwawa/1/edit?js,console
var myArray = ['Some', 'Strings', 'Whatever'];
// Just assign using OR
var pathOne = function(maybeAnArray) {
var array = maybeAnArray || [];
console.log(array);
}
// Assign using IF
var pathTwo = function(maybeAnArray) {
var array = [];
// Covers null and undefined
if (maybeAnArray != null) {
array = maybeAnArray;
}
console.log(array);
}
console.log('Path one:');
pathOne(myArray); // ['Some', 'Strings', 'Whatever']
pathOne(null); // []
console.log('\nPath two:');
pathTwo(myArray); // ['Some', 'Strings', 'Whatever']
pathTwo(null); // []
IMHO the use of the OR || for the purposes of assignment is perfectly valid and is good practice. We certainly use it in our projects and I've seen it used in lots of 3rd party projects that we use.
The thing you need to be aware of is how certain JavaScript objects can be coerced to be other values. So for example, if you're ORing values such as "", false or 0 then they are treated as false... this means that when you have the following:
function f(o) {
var x = o || -1;
return x;
}
Calling:
f(0)
...will return -1... but calling
f(1)
Will return 1 ... even though in both cases you passed a number - because 0 is treated as false -1 is assigned to x.
...that said, as long as you're aware of how the OR operator will treat the operands that you use with it - then it is good JavaScript practice to use it.
i prefer the first option, it's clear for my eyes, but when i need to share my code with others will think about to use second, will be more clear for any.
Now i'm using sonar, and prefer the second option too, will more easy to comprend for machine in inegration works.
Last idea is to use
if(maybeAnArray !== void(0))
Two reasons:
use cast and type conditionals
void(0) will works same for all browsers
Expect it helps yopu
When given the option, I prefer concise code (which must still be readable).
I would say || is common enough that it is considered good practice. Once one has seen it a few times it reads just fine.
In my opinion there are few reasons why you should rather use the second option:
First of all it's much more readable - new developers that are still learning can have problems with understanding notation like var myArray = someArrayArg || [];
If you are using some kind of code checkers like JSLint, they will return warnings and/or errors like Expected a conditional expression and instead saw an assignment. for the statement with var myArray = someArrayArg || [];
We already have something like var myArray = someArrayArg ? someArrayArg : []; that works pretty well
I'm a bit of a newbie in Javascript. I was looking through a bit of Coffeescript code for an Atom package, and I stumbled upon this piece of code:
loadProperties: ->
#properties = {}
fs.readFile path.resolve(__dirname, '..', 'completions.json'), (error, content) =>
{#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error?
return
I was a bit confused by the last line {#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error? because it seems like it assigns multiple values from the parsed JSON content. In my confusion, I decided to convert this back to Javascript using js2Coffee, and I ended up with the following:
function() {
this.properties = {}; // make list of properties (global to provider)
return fs.readFile(path.resolve(__dirname, '..', 'completions.json'), (function(_this) { //load completions.json (using path module)
return function(error, content) { // edit: nvm, js2coffee's fault. not sure why they wrapped the call back in another anonymous function, but this is a node stream callback
var ref;
if (error == null) { // if there are no errors
ref = JSON.parse(content), _this.pseudoSelectors = ref.pseudoSelectors, _this.properties = ref.properties, _this.tags = ref.tags;
}
};
})(this));
This code is a bit more understandable than the above. I can see that ref is assigned the object parsed from the content stream, and is then used to assign the other variables with their designated data. My question is, how does this type of assignment work? In Coffeescript, how does the preprocessor know where to assign the values, and in what order to assign them in?
By inspecting completions.json, the data is not in the order in which the assignments occur.
This is known as Destructuring Assignment.
To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left.
CoffeeScript interprets an object or array on the left side of an = as a pattern, matching the names used...
#pseudoSelectors
#properties
#tags
...to properties or indices within the value being assigned:
JSON.parse(content).pseudoSelectors
JSON.parse(content).properties
JSON.parse(content).tags
(Defining the additional ref to avoid reevaluating JSON.parse(content) for each.)
As for order, CoffeeScript will generally use the order they're mentioned within the assignment. Moving #pseudoSelectors to the 3rd property in the pattern will be echoed in the generated JavaScript.
{#properties, #tags, #pseudoSelectors} = JSON.parse(content) unless error?
var ref;
if (typeof error === "undefined" || error === null) {
ref = JSON.parse(content),
this.properties = ref.properties,
this.tags = ref.tags,
this.pseudoSelectors = ref.pseudoSelectors; // now last
}
Though, JavaScript Objects, like the result of JSON.parse(content), aren't enforced as sorted data structures. If you need to ensure the order of the values, you'll have to instead use an Array.
I got an 2x10 array and I need set a variable to any member of that array. Make it by hands its not cool, so Im trying to declarate by for operator:
allImages=[
[
'img1-1','img1-2', 'img1-3', 'img1-4', 'img1-5'
],[
'img2-1','img2-2', 'img2-3', 'img2-4', 'img2-5'
]
];
for(i=0;i<1;i++){
console.log(i + ' part ------------------------');
for(j=0;j<5;j++){
x+(i+'-'+j) = allImages[i][j];
console.log((x+(i+'-'+j)) + '-> item');
}
}
But looks like I make a primitive error:
Invalid left-hand side in assignment
Anyway, I cant figure out how to solve this. Can anyone say how to declarate a lot of variables with custom keys throw for operator or with another method?
----- My solution by(https://stackoverflow.com/users/1230836/elias-van-ootegem):
var statImg = {};
var blurImg ={};
for (var i = 0; i < 13; i++) {
var keyName = 'img'+i;
var valOfKey = 'img/'+i+'.png'
statImg[keyName] = valOfKey;
blurImg[keyName] = valOfKey;
};
You'll have to either create an object, and use the left-hand trickery you're trying to generate property names, or you'll have to fall back to the global object (which I hope you don't):
var names = {};//create object
//-> in loop:
names[ x+(i+'-'+j)] = allImages[i][j];
To be complete, but again: don't actually go and do this, you could replace names with window. In which case, you'll be polluting the global scope.
Perhaps you might want to check the values (like x, i and j) for values that make it "difficult" to access the properties, like %, or indeed the dash you're concatenating in your example:
var anObj = {};
anObj['my-property'] = 'this is valid';
console.log(anObj.my-property);//ReferenceError: property is not defined
That is because the dash, or decrement operator isn't seen as part of the property. Eitherway, using separate variables is, in your case, not the best way to go. Programming languages support arrays and objects because of this very reason: grouping related data, making them easy to access through a single variable.
If needs must, just use an object, if not, construct an array you sort using array.sort(function(){});
check MDN on how to acchieve this, if you're stuck down the way, let us know....