WHY NOT TO BAN 'VAR'?
My question is not about the difference between 'var' and 'let'. All such answers are advocating the advantages of using 'let'.
My question is: why not to tell frankly "do not use 'var' anymore"?
Is there a reason for not being so direct?
'var' is still in use on many serious tutorial sites: Mozilla MDN, w3schools ...
I am wondering if there is an hidden reason that I am missing.
There is one answer below: legacy (old browsers not supporting ES6)
Is that the only reason?
Any performance reason?
Or some fancy use of hoisting?
[ Here was the rest of my original post...
var arr = []; // -> const arr = [];
var obj = {}; // -> const obj = {};
var temp; // -> let temp;
var f = function(){}; // -> const f = function(){};
Doing so, I think that the only way a variable may behave like a var variable (hoisting etc.), is an -unfortunately- undeclared variable: x = sthg; in some function (becoming: var x = sthg; at global scope).
If I missed something, it would highly help me. ]
The only time I've even considered using var in the last year is to take advantage of it being hoisted outside of a code block, particularly with conditionals. Something like this contrived example:
const oneOrZero = shouldBeOne => {
if (shouldBeOne) {
var test = 1
} else {
var test = 0
}
return test
}
You can replace the var in this case with let, but that always struck me as kind of messy:
const oneOrZero = shouldBeOne => {
let test
if (shouldBeOne) {
test = 1
} else {
test = 0
}
return test
}
In the end, what I've done is take advantage of the ternary operator and const. This has the added advantage of not being reassignable after checking the initial conditional, which is typically my intent:
const oneOrZero = shouldBeOne => {
const test = shouldBeOne
? 1
: 0
return test
}
TL;DR: I haven't used var in over a year. const is much preferable, and typically forces me to write better code. let is occasionally useful.
Related
On a recent interview process, I was asked to write code for an API.
I used NodeJS, v16.14.0.
However, I encountered some very weird behavior:
module.exports = {
findSomething: (data) => {
const keys = Object.keys(data).sort();
let maxObj = null;
let maxKey = null;
for (let i = 0; i < keys.length; ++i) {
let key = keys[i];
const currObj = data[key];
if (maxObj == null || currObj.prop > maxObj.prop) {
maxObj = currObj;
maxKey = key;
}
}
// Attempt to assign a new property to the object:
// Variant 1, causes odd behaviour.
maxObj.maxKey = maxKey;
// Variant 2, object copy - works OK.
let newData = {...maxObj}
newData.maxKey = maxKey;
return newData;
}
}
This very minor change (Variant 1 instead of 2), gave no errors, however led the function behave very oddly. sometimes producing right results and others just nothing.
This led me to lose precious time, and eventually I was stunned to find it out.
I am not aware of cases of such behaviour. As I want to learn from this and get better, are you aware of why this could possibly happen, or if I am missing something obvious here? I know that assigning a new property to an existing object is fine in JavaScript, and my variables were all within scope usage.
I'm new to functional programming and I'm trying to refactor my code to have no side-effect.
let keywords = _.get(content, '[0].keywords', []);
keywords = keywords.slice(0, config.keywordLimit);
I'm using lodash. I believe you can just chain these two methods and be something like this.
const keywords = _.get(content, '[0].keywords', []).slice(0, config.keywordLimit);
But I'm just wondering if there's a more functional way of doing this in JavaScript?
Basically, functional style is all about composition. Here is a sample:
var get = _.curry(_.flip(_.get), 3);
var slice = _.curry(_.flip(_.slice), 3);
var comp = function(f, g) {
return function(x) {
return f(g(x));
}
};
var config = {
keywordLimit: 2
};
var program = comp(
slice(config.keywordLimit, 0),
get([], 'x')
)
var x = program({
x: ['abc', 'qwe', 'sdf']
});
console.log(x);
<script src="https://raw.githubusercontent.com/lodash/lodash/4.17.2/dist/lodash.min.js"></script>
In case, this fiddle doesn't work, here's jsbin: http://jsbin.com/gicocivife/edit?js,console
Pay attention to ugly curry(flip(get)) and curry(flip(slise)). The problem is that functions in lodash has such an order of arguments that prevents you from composition. Your function expects data to work with, right? Thus, the argument for this data must be the last one. Therefore, you can compose functions. I'd recommend to look at Ramda. Not only from my point of view this is a great library for FP. Here's the same example written with it.
var config = { keywordLimit: 2 };
var program = compose(
slice(0, config.keywordLimit),
view(lensProp('x'))
)
program({
x: ['abc', 'qwe', 'sdf']
});
The thing is, functions are curried by default. Thus, the partial application comes naturally. It also features Lenses, which is an awesome thing!
How would I create dynamic variable names in NodeJS? Some examples say to store in the window variable, but I was assuming that is client-side Javascript. Correct me if I'm wrong.
Generally you would do something like:
var myVariables = {};
var variableName = 'foo';
myVariables[variableName] = 42;
myVariables.foo // = 42
In node.js there is the global context, which is the equivalent of the window context in client-side js. Declaring a variable outside of any closure/function/module as you would in plain Javascript will make it reside in the global context, that is, as a property of global.
I understand from your question that you want something akin to the following:
var something = 42;
var varname = "something";
console.log(window[varname]);
This in node.js would become:
var something = 42;
var varname = "something";
console.log(global[varname]);
Just don't know what a bad answer gets so many votes. It's quite easy answer but you make it complex.
var type = 'article';
this[type+'_count'] = 1000; // in a function we use "this";
alert(article_count);
One possible solution may be:
Using REST parameter, one can create an array and add each dynamic variable (REST parameter item) as an object to that array.
// function for handling a dynamic list of variables using REST parameters
const dynamicVars = (...theArgs) => {
let tempDynamicVars = [];
// as long as there are arguments, a new object is added to the array dynamicVars, creating a dynamic object list of variables
for (let args = 0; args < theArgs.length; args++){
const vName = `v${args}`;
tempDynamicVars = [...tempDynamicVars, {[vName]: theArgs[args]}]; //using spread operator
// dynamicVars.push({[vName]: theArgs[args]}); // or using push - same output
}
return tempDynamicVars;
}
// short version from above
// const dynamicVars = (...theArgs) => theArgs.map((e, i) => ({[`v${i}`]: e}));
// checking
const first = dynamicVars("F", 321);
console.log("Dynamic variable array:", first);
console.log(` - ${first.length} dynamic variables`);
console.log(" - second variable in the list is:", first[1], "\n");
console.log(dynamicVars("x, y, z"));
console.log(dynamicVars(1, 2, 3));
console.log(dynamicVars("a", "b", "c", "d"));
I have lots of functions of the following template:
function (field, filter){
var q = {};
q[field] = doSomething(filter);
return q;
}
I am new to Javascript, but already got the idea that it is a very expressive language. So, my question is can the body of such a function be written more concisely?
(I cannot pass q as the parameter and eliminate var q = {}, since the output of these functions should not be merged into a single object hash).
I am perfectly aware that knowing the answer to this question is likely to make my code neither faster nor clearer. I just want to learn, that's all - so no flames, please.
No, you can't simplify it more.
You are trying to do something like this:
({})[field] = value;
but then you want to return the (now modified) {}. In order to do that you have to keep a reference to it. That's what your var q = {} does.
You can always avoid repetition in your code, using something like
function objectWith(field, value) {
var q = {}; q[field] = value; return q;
}
Which would make your original code into
function f(field, filter) {
return objectWith(field, doSomething(filter);
}
Or even better, avoid 'f' altogether and use
var o = objectWith(field, doSomething(filter);
whenever you would originally use it, assuming field is always a variable. Were it a literal, it would be even clearer to write
var o = { fieldLiteral: doSomething(filter) };
Just my devious tidbit, but what you are doing is the equivalent as the following piece of code :
function f(field, filter){
var q = {};
q.__defineGetter__(field, doSomething(filter));
return q;
}
There might be some way to shorten it in that form.
Suppose I have this:
var a = { A : { AA : 1 }, B : 2 };
Is there a way for me to create a variable that could allow me to reference either AA or B? What would the syntax look like?
// I know I can do this:
a['B']; // 2
a['A']['AA']; // 1
// something like this?
var myRef = ???;
a[myRef]; 1 or 2 depending on myRef
If not, what's a better way to get what I'm going for here?
Not directly.
Solution 1 - use object flattening
Flatten object, to have new object var a = { 'A.AA' : 1; B : 2 };.
See compressing object hierarchies in JavaScript
or Flattening a complex json object for mvc binding to get the javascript function for it.
Soution 2 - write key-path accessor
I can see it was already addressed by Eugen.
Reposted code-reviewed version:
function Leaf(obj,path) {
path=path.split('.');
var res=obj;
for (var i=0;i<path.length;i++) res=res[path[i]];
return res;
}
Solution 3 - use eval
var x = eval("a." + myRef); // x will be 1 for myRef == "A.AA", 2 for "B"
Be careful with this solution as you may introduce some security issues. It is more of the curiosity.
Since i also encounter this problem, i wrote also a one line util for this (ES6):
const leaf = (obj, path) => (path.split('.').reduce((value,el) => value[el], obj))
Example:
const objSample = { owner: { name: 'Neo' } };
const pathSample = 'owner.name';
leaf(objSample, pathSample) //'Neo'
function Leaf(obj,path) {
path=path.split('.');
var res=obj;
for (var i=0;i<path.length;i++) obj=obj[path[i]];
return res;
}
Leaf(a,'B')=2
Leaf(a,'A.AA')=1
Decorate with error handling etc. according to your needs.
With lodash _.get function, you can access nested properties with dot syntax.
Node server-side example:
const _ = require('lodash');
let item = { a: {b:'AA'}};
_.get(item, 'a.b');
Actually no, because js object are seen as property bags and doing a[X] is for accessing first level properties only...
But you could wrap the logic a['A']['AA']; // 1 in a function that does the same, like this
//WARN... no undefined check here => todo !
function _(o, path) {
var tmp = o
for (var i=0 ; i < path.length ; i++) {
tmp = tmp[path[i]]
}
return tmp
}
var r = _(a, ['A', 'AA'])
This is pretty much the same as other answers, but the difference is when dummy boy create object property name containing dots... Like var a = {"a.a" : 3 } is valid.
Now, such problem would occurs maybe more often now with the help of IndexedDB to store anything locally...