These days I am reading some javascript source codes,however I found some syntax that I can not understand.
1)the for-in loop
var c;
var obj={name:'test',age:33};
for(var e in c={},obj){
console.info(e+' = '+obj[e]);
}
2)The Conditional Operator (?:)
Generally,we use this operator this manner:
x > 0 ? x*y : -x*y
But I have seen some codes like this:
x > 0 ? (x*y,z=bar,..other expressoin) : (-x*y)
But it does not work if I change the comma to colon,it will throw a error.
In both cases, the comma operator [MDN] is used:
You can use the comma operator when you want to include multiple expressions in a location that requires a single expression. The most common usage of this operator is to supply multiple parameters in a for loop.
And the specification:
11.14 Comma Operator ( , )
Syntax
Expression :
AssignmentExpression
Expression , AssignmentExpression
(...)
Semantics
The production Expression : Expression , AssignmentExpression is evaluated as follows:
Let lref be the result of evaluating Expression.
Call GetValue(lref).
Let rref be the result of evaluating AssignmentExpression.
Return GetValue(rref).
That just means that the result of the last expression is returned as result of the whole "list" of expressions.
In the examples you gave, it is used for its side effects [Wikipedia], namely evaluating every expression.
In general I'd say that this is not such a good style and, as you noticed, more difficult to understand.
for(var e in c={},obj)
is the same as
c = {};
for(var e in obj)
an does not seem to add any value. Even better would have been to just initialize c in the first line: var c = {};.
In case of the conditional operator: If x > 0 is true, then all the expressions are evaluated and the result of the last expression is returned. In this case, using a normal if statement would be better (easier to understand).
Here again, the comma operator and maybe even the conditional operator seems to be used solely because of their side effects: Normally the conditional operator is supposed to only return a value but not to execute arbitrary expressions (a single function call which returns a value might be an exception).
As the MDN documentation says, it is more commonly used in a for loop to initialize multiple variables:
for(var i = 0, l = array.length; i < l; i++)
In Javascript you can define variables like:
var obj1 = { a: 2, b: 4, c: 6};
var obj2 = { x: 1, y: 3, z: 5};
Or, you can comma-separate the declarations, like this:
var obj1 = { a: 2, b: 4, c: 6}, obj2 = { x: 1, y: 3, z: 5};
Now, a for in loop is normally something like:
for(var key in obj1) { console.log(key); }
But, if you comma-chain the part after 'in' it will allow it (just like when assigning), but will run the loop on the last object in the chain.
var key, obj1 = { a: 2, b: 4, c: 6}, obj2 = { x: 1, y: 3, z: 5};
// will output 'a', 'b' and 'c'
for(key in obj2, obj1) { console.log(key); }
// will output 'x', 'y' and 'z'
for(key in obj1, obj2) { console.log(key); }
This means you can assign values within the for in, and then do looping on another object.
var key, obj3; // obj3 === null
var obj1 = { a: 2, b: 4, c: 6}, obj2 = { x: 1, y: 3, z: 5};
// will output 'a', 'b' and 'c'
for(key in obj3 = { j: 9, k: 8, l: 7 }, obj1) { console.log(key); }
// obj 3 is now { j: 9, k: 8, l: 7 }
Okay, so now for the ternary operators. If the above makes sense, so should this.
Ternary operations are like if statements with a single line. You can't put semicolons in a line because then it becomes two or more lines. But putting () around comma-separated declarations then it is still considered one line.
So this is valid:
x > 0 ? a = 1 : a = 2;
And this is valid:
x > 0 ? (a = 1, b = 2) : (a = 2, b = 1);
But this is not, because the commas throw off the interpretation of the ternary:
x > 0 ? a = 1, b = 2 : a = 2, b = 1;
But I would not recommend setting values in a ternary, unless it looks something like:
a = x > 0 ? 1 : 2;
:)
The first? no idea. The second? It's just like your typical inline if except it executes multiple expressions rather than one
x > 0 ? (doThis(),doThat(),x=2) : (again(),another(),y=5);
Isn't the first one just an initializer?
var c;
var obj={name:'test',age:33};
for(var e in c=[], obj){
console.info(e + ' = ' + obj[e]);
c.push(e);
}
console.info(c);
Now, why you'd do it that way... I'm not sure.
Related
I am new to ES6 destructing. I have an object which contains another object. I want to store certain values from the nested object.
For example -
z = {g: 1, h: 2, i: {d1:5, d2:6, d3:7}}
When I do
let { g, i : {d1, d3}, ...less } = z
the less variable only stores h and not d2.
Is there a way to make it so it is
less = {h, i : {d2}}
No there is not. What you could do is
let { g, i: { d1, d3, ...less2 }, ...less } = z
let less = { ...less, i: less2 };
This extracts the remainder and merges them back together while preserving the shape.
No, unfortunately this is not possible.
You can however extract the missing values from i with a second rest spread:
let z = {g: 1, h: 2, i: {d1:5, d2:6, d3:7}};
let { g, i : {d1, d3, ...i_less}, ...rest_less } = z;
let less = { i: i_less, ...rest_less };
console.log(less)
This is my way, hope it could help.
let z = {
g: 1,
h: 2,
i: {
d1:5,
d2:6,
d3:7
}
}
let {g, i: {d1, d3, ...less1}, ...less2} = z
let less = {
i: less1,
...less2,
}
console.log(less); // output: {h: 2, i:{d2:6}}
I want to create a function with an object as parameter
The object can have for exemple three keys : x, y, z
All this keys must have default value assignment
I tried this :
function f({x:x, y:y, z: z} = {x:1,y:2,z:3}) {
return x + y + z;
}
But I have a problem
f() // return 6 => OK!
f({x: 2, y: 3, z: 4}) // return 9 => OK!
f({x: 2, y:3}) // return NaN (because z === undefined), I expect 8
How can I do this?
You can assign individual defaults when destructuring objects:
function f({ x = 1, y = 2, z = 3 } = {}) {
return x + y + z
}
console.log(f())
console.log(f({ x: 2, y: 3, z: 4 }))
console.log(f({ x: 2, y:3 }))
See the docs here, which describes array destructuring, but the same applies to objects.
What does destructuring mean? It’s a JavaScript expression that allows us to extract data from arrays, objects, maps and sets into their own variable. It allows us to extract properties from an object or items from an array, multiple at a time.
Short form: The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Please have a look at this simple code example:
function yourFunction({
x = 1,
y = 2,
z = 3
} = {}) {
return x + y + z
}
out.innerHTML+="<br>" + yourFunction()
out.innerHTML+="<br>" + yourFunction({ x: 3, y: 3, z: 4 })
out.innerHTML+="<br>" + yourFunction({ x: 7, y: 1})
<p id="out">Results: </p>
Have a look at the docs: click
Say you have an object such as:
let objToCheck = {
a: 2,
b: 5,
c: 9,
d: 33
};
How would you go about returning the keys of the three largest values in ascending order, which in this case would be: [ 'c', 'h', 'd' ], in linear time? Evidently you need to loop through the entire object once to compare all values, but I'm having troubling coming up with a solution that doesn't involve nested loops which I believe is O(n²). Here is what my solution currently looks like so far:
function findBig3 (obj){
const res = [];
const largest = Object.values(obj).sort((a,b) => { return b-a }).slice(0,3);
for (let key in obj){
largest.forEach((val) => {
if (obj[key] === val) res.push(key);
}
});
}
return res;
}
I would imagine you need to declare three variables, such as big1, big2, big3, and as you loop through the object do some type of comparison check and reassign as appropriate, but I'm struggling with the implementation.
you can keep pushing 3 objects in an array and keep sorting the array, assuming number of elements you need k is sufficiently less than n, this can give linear efficiency on average.
let objToCheck = {
a: 2,
b: 5,
c: 9,
d: 33,
e: 4,
f: 8,
g: 3,
h: 10
};
function findBig3(obj){
var res = [-1,-1,-1];
for (let key in obj){
res[3] = obj[key];
res.sort(function(a,b){return b-a});
}
res.pop();
return res;
}
console.log(findBig3(objToCheck));
This algorithm runs in O(n).
function getThreeLargestKeys(obj){
var k1, k2, k3;
var v1, v2, v3;
v1 = v2 = v3 = -Infinity;
// O(1)
var insertKey = function(key){
var value = obj[key]; // note 1
// note 2
if(value >= v1){
v3 = v2; v2 = v1; v1 = value;
k3 = k2; k2 = k1; k1 = key;
}else if(value >= v2){
v3 = v2; v2 = value;
k3 = k2; k2 = key;
}else if(value >= v3){
v3 = value;
k3 = key;
}
};
// O(n)
for(var key in obj){
// note 3
insertKey(key);
}
return [k1, k2, k3];
}
https://jsfiddle.net/DerekL/pzatq729/
Please do not copy-paste the code right into your homework as your solution. Rewrite the code once you fully understand it.
Note:
This assumes that object lookup is O(1). This ultimately depends on how it is implemented in the interpreter, but it is usually lower than O(log n).
These conditionals can certainly be optimized. I will leave that as a practice for the reader.
Normally we should check if the key is owned by the object instance, but here I will assume that the input object is not inherited from Object.prototype.
If you just change Object.values to Object.keys and use the key to select from the original object, you can avoid the last loop.
let objToCheck = {
a: 2,
b: 5,
c: 9,
d: 33,
e: 4,
f: 8,
g: 3,
h: 10
};
function findBig3(obj){
return Object.keys(obj).sort((a,b) => {return obj[b]-obj[a]}).slice(0,3);
}
console.log(findBig3(objToCheck));
I currently have a situation where I have 2 objects that look like this:
object a = {n: 15, b: 12, v: 10, h: 9} and so on.
object b = {1: e, 2: b, 3: z, 4: w} and so on.
I need to take the values from object b and use them to replace the values in object a. the result would look like:
object c = {n: e, b: b, v: z} etc.
One important thing is that if there are more items in object b than in object a, I still need them added on to the end of object c. so if there are 3 more items in object b, perhaps something like this {24: a, 25: y, 26:w} would happen at the end.
My first thought, of course, is a loop where I would iterate over each item in object a and replace the 'value' with that from object b. But I didn't know if there was a better way, especially with my concern about making sure that all of the items from object b are included in the new object.
Because of that concern, an alternative could be to replace the keys in object b with the keys in object a instead. that way if object a runs out, the last items in object b would't be excluded.
I've also tried:
Object.assign(a, b);
but that only works if the keys are the same, so that won't work. I need whatever happens to match index to index for the two objects.
If it matters, I can change object b to be anything I want as it's static. So, I could do:
object b = [e, b, z] etc. or
object b = {e: e, b: b, z: z}
Whatever makes it easiest to do.
I appreciate any thoughts anyone might have or if you can point me in the direction of a good post covering something like this. I'm currently scouring the internet and trying anything that sounds like it might work but so far, nothing has fit.
It's also worth noting that at this point I'm using pure vanilla JS so if there is a library or something that would make this super easy, I'm open to that.
You could do something like the following
var objectA = {
b: "test",
a: "test2",
c: "test3",
d: "test4"
};
var objectB = ["new", "new2", "new3", "new4", "new5", "new6"];
var index = 0;
for (var prop in objectA) {
if (objectA.hasOwnProperty(prop)) {
objectA[prop] = objectB[index];
index++;
}
}
for(index; index < objectB.length; index++) {
objectA[index] = objectB[index];
}
Couple things though:
The for..in loop is based on order of implementation. So whatever order the properties were added to the object will be the order of the loop.
Functionality like what you are requesting seems like a code smell when viewed out of context. Typically you are not merging two objects like the way you are requesting. If you want to provide further context, a better solution might be offered up.
I am assuming that those letter values in object b are strings, but the example would also work on variables, you just have to remove the quotation marks.
My approach is:
1. Get all the keys in b and a
2. Create an empty object, Loop through the keys in b
3. Using the index of b, i can also get the index of a. This way, when we are iterating the 3rd time, i would be 2 and I can get the keys and values of a and b, which are v:10 and 3: 'z' respectively. Then I map the key of a to the value of b, so the result would be v: 'z'.
4. If b has more keys, just assign current key and value in b to c.
var a = {n: 15, b: 12, v: 10, h: 9};
var b = {1: 'e', 2: 'b', 3: 'z', 4: 'w', 24: 'a', 25: 'y', 26:'w'};
// get all the keys in a
let aKeys = Object.keys(a);
// get all the keys in b
let bKeys = Object.keys(b);
// acc is the accumulated object c,
// at the beginning value of c is {}, it gets bigger as we loop through the keys of b
// i is the ith key in b
let c = bKeys.reduce((acc, _, i) => {
// if a > b then put key value pair of b
if (i > aKeys.length - 1) {
acc[bKeys[i]] = b[bKeys[i]];
} else {
acc[aKeys[i]] = b[bKeys[i]];
}
return acc;
}, {});
console.log(c)
After doing a bit more searching and playing, something I read inspired me to make both objects into arrays instead and then join them into a map. Ended up being super easy. This was the result:
var a = ['a', 'b', 'c'];
var b = [1, 2, 3];
var map = {};
for(var i = 0; i < a.length; i += 1) {
map[ a[i] ] = b[i];
}
console.log(map); // {a: 1, b: 2, c: 3}
Thanks for those who read it!
var objectA = {n: 15, b: 12, v: 10, h: 9};
var objectB = {n: e, b: b, v: z, h: w, a: 1, c: 2};
var objectC = extend({}, objectA, objectB);
function extend(out){
out = out || {};
for (var i = 1, len = arguments.length; i < len; i++){
var obj = arguments[i];
if (!obj) continue;
for (var key in obj){
if (obj.hasOwnProperty(key))
out[key] = (typeof obj[key] === 'object') ? extend(out[key], obj[key])
: obj[key];
}
}
return out;
}
console.log(objectC);
// outputs {n: e, b: b, v: z, h: w, a: 1, c: 2}
It will throw error if e, b, z, w is not defined.
Values of objectA and objectB remain unchanged.
From extend({}, objectA, objectB), it gets the value from objectB to replace objectA, and then objectA to {} without changing the original value of objectA and objectB.
Note: You will need to change the keys in objectB to reflect keys in objectA instead of using 1, 2, 3... as keys.
I’m trying to create an array consisting of an object for each letter in the alphabet with two properties. Letter and dd_array. Right now I’m setting dd_array = [], but I would like it to be the corresponding morseDic property.
So for instance _charObjArray[0] = {letter: 'a', dd_array: [0,1]}
Can I get some tips on how to code this best possible??
alpha_array = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
morseDic = {
a: [0,1],
b: [1,0,0,0],
c: [1,0,1,0],
d: [1,0,0],
e: [0],
f: [0,0,1,0],
g: [1,1,0],
h: [0,0,0,0],
i: [0,0],
j: [0,1,1,1],
k: [1,0,1],
l: [0,1,0,0],
m: [1,1],
n: [1,0],
o: [1,1,1],
p: [0,1,1,0],
q: [1,1,0,1],
r: [0,1,0],
s: [0,0,0],
t: [1],
u: [0,0,1],
v: [0,0,0,1],
w: [0,1,1],
x: [1,0,0,1],
y: [1,0,1,1],
z: [1,1,0,0]
}
function _alpha(_char, dd_array) {
this.letter = _char;
this.dd_array = dd_array;
}
var _charObjArray = []
for (i = 0; i < alpha_array.length; i++) {
var _charNow = alpha_array[i];
var __charNow = _charNow;
var __charNow = new _alpha(_charNow, "[]") // "[]" should be replaced with the _charNow corresponding property from morseDic
_charObjArray.push(__charNow)
}
console.log(_charObjArray);
In _alpha, instead of:
this.dd_array = dd_array;
...you use _char to index into the morseDic object:
this.dd_array = morseDic[_char];
...and then don't pass a second argument to _alpha at all.
But if you want to pass it to _alpha as an argument:
var __charNow = new _alpha(_charNow, morseDic[_charNow]);
In JavaScript, you can access object properties either with dot notation and a property name literal (obj.foo, or morseDic.a), or using brackets notation and a property name string* (obj["foo"] or morseDic["a"]). In the latter case, the string can be the result of any expression, including a variable lookup.
* In ES6, it'll be strings or Symbols.