for loop gives only last value in javascript - javascript

I have created variable outside to get values from inside but I only get last value in both variables.
var categoryProductid;
var PPProducttitle;
for (var key in UpdatedCategory) {
const actual = UpdatedCategory[key]
var categoryProductid = actual.id;
var PPProducttitle = actual.title;
console.log(PPProducttitle)
console.log(categoryProductid)
}
console.log(PPProducttitle)
console.log(categoryProductid)
when I do console.logs() from inside and outside of for loop I get two different values.
Any help will be appreciated thank you!!!!!

I'm going to assume that UpdatedCategory is an object (if it's an array, please see my answer here for what to use instead of for-in to loop through it).
The basic problem with that code is that you're assigning to the same variable over and over. The reason it's the same variable is that var doesn't have block scope, so the var part of var categoryProductid = actual.id; is completely ignored (and similar for var PPProducttitle = actual.title;). Instead, you're reusing the variables you declared prior to the for loop.
A variable can only hold one value, so when you assign a new value to it, it no longer holds the old value.
If you want to hold multiple values with a variable, you can assign a container to it that can hold multiple values, such as an array, an object, a Map, or a Set.
You haven't said what end result you want, but here's an example that creates two arrays and fills them with the id and title of the products from UpdatedCategory:
// Again, I'm assuming `UpdatedCategory` is an object:
const UpdatedCategory = {
a: {
id: 1,
title: "a",
},
b: {
id: 2,
title: "b",
},
c: {
id: 3,
title: "c",
},
};
// `[]` creates a new empty array.
// We can use `const` to declare these because we never change their
// value (they only ever refer to a single array), but you could use
// `let` if you preferred. Don't use `var` in new code, it's deprecated.
// Note: I've renamed these slightly to:
// 1. Stick to standard naming conventions
// * Initial capitals are used primarily for constructor functions
// * Variables referring to arrays are generally plurals
// 2. Be consistent in capitalization
const categoryProductIds = [];
const ppProductTitles = [];
for (var key in UpdatedCategory) {
// Get this property value
const actual = UpdatedCategory[key];
// Push the `id` and `title` into the relevant arrays
categoryProductIds.push(actual.id);
ppProductTitles.push(actual.title);
}
// Show the contents of the arrays
console.log(ppProductTitles);
console.log(categoryProductIds);

Related

Alternate/better ways to initialize JavaScript object that needs multiple static values?

I have a JavaScript object with some static attribute values, dynamic attribute values and methods. Each time I need one of these objects, I will need 10 of them. Each of the 10 objects gets initialized by a dedicated object literal. That happens under 3 different contexts of a user doing something on a data entry form. User actions can cause the contexts to happen in any order, any number of times, but the same 10 objects will always be created in each context. By "same" I mean the static values for a "no_matl" object will be identical each time a "no_matl" object is created ... only a few dynamic attribute values (field value, previous value, date/time, context ID) are different for each context.
Is there a smarter way to do the initialization currently done with the const object literal? Originally I passed a bunch of params to the constructor and initialized the static attributes from those. The object literal approach seemed cleaner. Maybe there's a better way?
// object literals used to initialize a each of the 10
// different type objects.
const FIELD_NOMATERIAL = {
DispName: 'No Material',
DbName: 'NO_MATERIAL',
TrueVal: 'Yes',
InitVal: '',
DispWhenSet: 'yes',
DispWhenNotSet: ''
};
const FIELD_CPCAT = { ... same attributes, different values ...};
const FIELD_HCN = { ... same attributes, different values ...};
// ... 7 more like this ...
// context 1
var no_matl = new MyField(FIELD_NOMATERIAL),
cpcap = new MyField(FIELD_CPCAT),
hcn = new MyField(FIELD_HCN) .... 7 more like this
// object definition
function MyField() {
if (arguments.length == 1 && typeof(arguments[0]) === 'object' ) {
this.DispName = arguments[0].DispName ;
this.DbName = arguments[0].DbName ;
// .... etc for rest of static attributes ...
}
}
Sounds like what you want is a copy of the original object that can change values without changing the original. Try this:
const FIELD_NOMATERIAL = {
DispName: 'No Material',
DbName: 'NO_MATERIAL',
TrueVal: 'Yes',
InitVal: '',
DispWhenSet: 'yes',
DispWhenNotSet: ''
};
function getFreshCopy(original) {
return Object.assign({}, original);
}
var no_matl = getFreshCopy(FIELD_NOMATERIAL);
Using Object.assign({}, obj) will create a new copy that can be changed without the original values changing. no_matl can be adjusted and FIELD_NOMATERIAL remains in its original state.
Note that const means the variable cannot be assigned a new value. It does not mean that the contents of the object cannot be changed. That means the following is true:
const noChange = { a: 7 };
noChange.a = 8; // this is fine because 'a' is allowed to change
noChange = "hello"; // this gives TypeError: Assignment to constant variable.

chineseFood[array[0]] = array[array.length-1];

I don't understand the purpose of this = sign on the sixth line in the code block below. I understand how the argument grabs each index number of the array, I just don't understand why chineseFood[array[0]] = array[array.length-1]; In other words, I don't get the purpose of the equal sign as if it were almost comparing each other to be stored in the empty object that is stored in the variable chineseFood. Could someone please clarify? It would be much appreciated.
function transformFirstAndLast(array) {
var chineseFood = {};
//takes 1st element (at index 0) and sets it to the last element (nth index): array(length-1)
chineseFood[array[0]] = array[array.length - 1];
return chineseFood;
}
console.log( transformFirstAndLast(['Orange', 'Lemon', 'Pork', 'Chicken']) );
Output Below
{Orange: "Chicken"}
The equals sign is not comparison, it is assignment. chineseFood is an object, which means that it can be treated like a dictionary, and its properties can be accessed using the [] operator instead of the . operator:
myObj = {
foo: "bar"
};
console.log(myObj["foo"]); // bar
console.log(myObj.foo); // bar
Likewise, you can also assign properties this way:
myObj = {};
myObj["foo"] = 3;
console.log(myObj["foo"]); // 3
console.log(myObj.foo); // 3
This is what your code is doing. It is retrieving the value of array[array.length-1], which is "Chicken". Then it is assigning this value to the property of chineseFood that has the name represented by array[0], which happens to be "Orange". Thus, the property named Orange on chineseFood is set to array[array.length - 1], which is why chineseFood evaluates to {Orange: "Chicken"}.
This method of accessing properties is especially useful when you don't know the name of the property you will be changing in advance, as is the case with this code, or when you want to create properties that have names that would otherwise be illegal:
myObj = {
".you can't usually use with spaces or start w/ periods": false
};
myObj[".you can't usually use with spaces or start w/ periods"] = true;
console.log(myObj[".you can't usually use with spaces or start w/ periods"]);
// there is no way to read this property the normal way
Basically what is does is:
your object is :
var obj = {Orange: "Chicken"};
And Your array is :
var arr = ['Orange','Lemon','Pork','Chicken']
What this line says is pick first element of the array and check for this prop in object and change its value to last element of array, here:
arr[0] = "orange";
So this line :
obj[arr[0]] can be seen as obj['orange'].
After that you change its value:
Obj[arr[0]] = arr[arr.length-1] which can be written as obj['orange'] = 'chicken'

Generic 2D hash in JavaScript?

In other languages it is possible to create a generic 2D hash. I know creating 2d hashes is possible in javascript as well as explained here, but I can't seem to find a generic way to achieve this.
As an example of what I am looking for. In Ruby you can do this:
2dhash = Hash.new{|h, k| h[k] = Hash.new }
puts 2dhash["test"]["yes"]
#=> nil
2dhash[1][2] = "hello"
puts 2dhash[1][2]
#=> "hello"
Notice that I have not initialized the second level of hash, it happens automatically.
Is it possible to somehow achieve the same in javascript? Specifically, a way to make a 2d hash without initializing the first level of hash (or hard-coding it to be even more specific). The 2dhash will be used dynamically, so I have no clue what the first level will be.
Looks like a nice data structure excercise, let me try :D
function Hash() {
this.hash = {};
}
Hash.prototype.set = function(val) {
var paths = Array.prototype.slice.call(arguments, 1) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
if (!(hashed instanceof Hash)) {
hashed = this.hash[path] = new Hash()
}
Hash.prototype.set.apply(hashed, [val].concat(paths))
} else {
// last level
this.hash[path] = val
}
}
Hash.prototype.get = function() {
var paths = Array.prototype.slice.call(arguments, 0) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
return Hash.prototype.get.apply(hashed, paths)
} else {
// last level
return hashed
}
}
Now, let's see if it works:
var trytry = new Hash()
trytry.set('the value to store', 'key1', 'key2')
trytry.get('key1') // Hash{key2: 'the value to store'}
trytry.get('key1', 'key2') // 'the value to store'
Hooray it works!
It also works for even deeper levels:
trytry.set('the value to store', 'key1', 'key2','key3', 'key4')
trytry.get('key1', 'key2','key3') // Hash{key4: 'the value to store'}
However, a disadvantage of this approach is that you have to use instance methods get and set, rather than native object literal getter/setter.
It's still incomplete. For production environment, we need to do more, e.g. methods and properties like contains, size, etc.
If you initialize the first level of the hash with objects, then you can reference the second level without typeErrors, even if the data was not defined before.
Example:
var _2dhash = {a: {}, b: {}, c:{}}
//Note you cannot start variable names with numbers in js
_2dhash['a']['missingElement'];
// > undefined
It works because you're accessing undefined properties of defined objects. If you try to access through a missing top-level object, ie.
_2dhash['d']['whatever'];
You will get a TypeError, because _2dhash.d was not defined, and the second lookup fails, trying to read the 'whatever' property of undefined.

Accessing plugin prototype function using array square [] brackets

I am very new to JS and I was just going through the syntax of modal.js. Basically I have a small difficulty, a lot of classical JS plugins use the below skeleton code for the plugin:
var Modal = function(element , options){
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.isShown = null
this.$backdrop =
this.scrollbarWidth = 0
}
Modal.prototype.toggle = function (_relatedTarget) {
// do something
}
Modal.prototype.show = function (_relatedTarget) {
// do something
}
var data = new Modal(somthing , radnom);
// now if we assume that option is "show",
//the show function in Modal will be executed
// but my question is data is not an array, so how can we use
// [] square brackets to access the properties of Modal/data ??
data[option](_relatedtarget);
Now my question is about accessing the properties of a plugin, see how a function is being called using the following syntax:
data[option](_relatedtarget);
See my comment in the code. How can we access the properties of data using []; it's not an array, right?
[] are not just for arrays
You can use [] to access properties on an object too.
You can use
data["show"] to access the show method
OR
data.show which is the same thing
One advantage of the [] is that you can use a variable within the brackets
var option = "show";
data[option](something); // call the `show` method on `data`
If you know the method you want to call, using the . is much nicer looking in the code
data.show(something); // much quicker (to type), and prettier
JavaScript has arrays:
var anArray = [ 1, 2, 3, 4 ];
and associative arrays (also known as maps):
var anAssociativeArray = { first: "No. 1", second: 2, somethingElse: "Other" };
both of these data structures can be accessed via []:
anArray[3] // will get the element of the array in position 3
// (starting counting frrom 0).
anAssociativeArray['first'] // will get the element of the associative array with the
// key 'first'.
Associative arrays can also be accessed via the .key notation:
anAssociativeArray.first // will also get the property with key 'first'.
The . notation can be used if you know the key you want to access but if you want to dynamically select which key then you need to use the [] notation.
var whichOptionToPick = 'somethingElse';
var value = anAssociativeArray[ whichOptionToPick ]; // will get the value "Other".

pushing javascript objects to arrays

I have a loop goes through an array of objects MyArrayOfObjects and then pushes the objects to a new array like this:
var NewArray = new Array();
for (i = 0; i < MyArrayOfObjects.length; i++) {
TempObject = null;
TempObject = new Object();
// I have logic that copies certain properties but not others
// but overall it looks like this:
TempObject.prop1 = MyArrayOfObjects[i].prop1;
TempObject.prop2 = MyArrayOfObjects[i].prop2;
NewArray.push(TempObject);
}
As I loop through MyArrayOfObjects, I clear the TempObject and create a new one each time. Does NewArray contain the objects that I'm copying or just a reference to the objects copied and that then become deleted as the loop iterates?
Thanks.
It contains references to the objects themselves.
This code shows that concept in action (notice that changing the object after pushing it into the array changes the object in the array as well):
var ray = new Array();
var obj = { foo: 123 };
ray.push(obj);
obj.foo = 321;
alert(ray[0].foo);
> var NewArray = new Array();
It is generally considered better to use an array literal to create an array. Variable names starting with a capital letter are, but convention, used for constructors. Using "new" at the start of a variable name can easily slip to become "new Array", and the name should reflect its purpose, so something like the following might be better:
var objectArray = [];
.
> for (i = 0; i < MyArrayOfObjects.length; i++) {
You should always declare variables, especially counters as undeclared variables are made properties of the global object (effectively global variables) when they are first assigned a value. Also, it is considered better to store the length of the array than get it in each iteration:
for (var i = 0, iLen = MyArrayOfObjects.length; i < iLen; i++) {
.
> TempObject = null;
> TempObject = new Object();
Again, declare variables. Assigning a value of null serves no useful purpose when you're going to assign some other value immediately afterward. Just do the second assignment (and use a literal):
var TempObject = {};
.
> // I have logic that copies certain properties but not others
> // but overall it looks like this:
>
> TempObject.prop1 = MyArrayOfObjects[i].prop1;
> TempObject.prop2 = MyArrayOfObjects[i].prop2;
>
> NewArray.push(TempObject);
At this point, TempObject and NewArray[NewArray.length - 1] both reference the same object.
> }
As I loop through MyArrayOfObjects, I clear the TempObject and create
a new one each time.
There is no need to "clear" the object, just assign a new value to the variable. In javascript, all variables have a value that might be a primitive (e.g. string, number) or a reference to an object (e.g. Object, Array, Number, String)
Does NewArray contain the objects that I'm
copying or just a reference to the objects copied and that then become
deleted as the loop iterates?
It contains references to the new objects created on each iteration.
As variables hold references to objects, assigning a new value to the variable doesn't do anything to the object. When an object is no longer referenced by any variable or object property, it is made available for garbage collection and may be removed automatically at some later time when garbage collection runs.
Using map or its jquery counterpart might be a more idiomatic way of doing this. For example:
var oldArray = [
{ prop1: 1, prop2: 10 },
{ prop1: 2, prop2: 20 },
{ prop1: 3, prop2: 30 }
]
var newArray = $.map(oldArray, function(oldObj) {
return { newProp: oldObj.prop1 }
})
console.log(newArray)

Categories

Resources