I'm debugging code that someone else wrote and can not figure out what they had in mind.
At the end of method there is a return statement shown below
return params[name] || null;
If params is an object (it is in this case) then
params.name
or
params['name'] would return the value of that function(method)
Two things are a mystery. In the docboc, the author stated that it this method would return a string. Clearly, it does not.
Secondly, since it is returning an object, how would I properly reference that value?
(Note: I do NOT know what the key is before hand)
Square brackets in JavaScript allow you to access Objects and Arrays by index. For an example this would be a base 0 integer for Arrays, e.g. someArray[0]. For objects this would be the key, e.g. someObject[‘key’].
Your statement return params[name] || null is looking for params (array / obj) and name (index / key)
So if your params for example is an object and name is the variable for the keys.
and you need to get its value, you would do params[name] . since name is not under quotations I am assuming its a var defined somewhere
Square Brackets ([]) allows you to access properties of any object or element of an array at a specific index
for example :
const obj = {a:true};
then obj['a'] will return true;
Or const arr = ['hello','world'];
then arr[0] will return 'hello';
Related
i know this is kind of weird question but, i was creating a guard to prevent duplicate values in array i write some part and got a little help from stackoverflow but i can't understand code meaning properly
so i created Object with null prototype and iterated for loop over it to detect duplicate values (i know Set constructor is much easier but i am doing it in my server-side code and since older browsers does not support Set it would be dangerous to use Set). here is my code
var duplicateTagsGuard = Object.create(null);
for(var co = 0; co < tags.length; co++){
let val = tags[co];
if(val in duplicateTagsGuard){
return res.status(409).send({
message: ''
})
}
duplicateTagsGuard[val] = true
}
and the part i cant understand is duplicateTagsGuard[val] = true
so if we split my code step by step and explain it would be like
1.first create null Object
2.iterate for loop on it and declare variable val and make it equal to every element in tags array
3.then check if that val is in duplicateTagsGuard object and if it is use return statement to prevent continuing for loop and if it is not then we are adding val's value to object but i don't know how it is implemented with that part of code (duplicateTagsGuard[val] = true) if anyone can explain i will be glad
first create null Object
It is not creating a null object but it is creating an object with null as the prototype check the Object.create docs:
var duplicateTagsGuard = Object.create(null);
console.log(`duplicateTagsGuard is an empty object:`);
console.log(duplicateTagsGuard);
console.log(`Prototye of duplicateTagsGuard is null: `);
console.log(Object.getPrototypeOf(duplicateTagsGuard));
iterate for loop on it and declare variable val and make it equal to every element in tags array
This part is correct every time the loop runs a new variable is created with for block scope and is assigned the value of the current coth index value of the tags array.
then check if that val is in duplicateTagsGuard object and if it is use return statement to prevent continuing for loop and if it is not then we are adding val's value to object but i don't know how it is implemented with that part of code (duplicateTagsGuard[val] = true)
It is checking whether val is a property of the duplicateTagsGuard object, if it is already present then the return is used to return the response else it is adding that property to the duplicateTagsGuard object with the bracket notation [propertyName] and assigning it's value as true.
var duplicateTagsGuard = Object.create(null); //creating a new empty object with prototype as null
let val = "hello"; //creating a new variable
duplicateTagsGuard[val] = true; //adding the property with the value of the variable val
console.log(val in duplicateTagsGuard); //checking if the added property is present in the object
The code is creating a dictionary of val. Basically, when you iterate through the tags array, it checks whether the item in the array (accessed by tags[co]) is already present in the dictionary duplicateTagsGuard. If it has been encountered before, it will perform a certain action.
At the end of the loop, it simply injects the item into the dictionary. The dictionary therefore keep track of whether an item has been encountered before in the for loop.
The injection is done by using the item as the key in the dictionary, since it is easier to look it up (you simply have to do item in dictionary, which is basically val in duplicateTagsGuard in the actual implementation of the code). It does not matter what value you use, so a true value is used as a placeholder.
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 5 years ago.
I have an array
fruit={sweet:'apple',dry:{f1:'raisin',f2:'almond'},sour:'strawberry'}
it contains simple and nested objects as items
i can reference f1 using bracket notation like fruit[0]["dry"]["f1"]
but i have a string variable that has the value var str="dry.f1"
value of "str" changes on runtime it could be "sweet" or "dry.f1" or "sour"
how do i reference the array item using "str"
if the value of str is either "sweet" or "sour" fruit[str] works fine
we can get the value of f1 using fruit[0].dry.f1 but i need to access it using the variable str
You can use split and reduce:
var fruit={sweet:'apple',dry:{f1:'raisin',f2:'almond'},sour:'strawberry'};
var str1 = "dry.f1";
var str2 = "sweet";
var example1 = str1.split('.').reduce((a, b) => a[b], fruit);
var example2 = str2.split('.').reduce((a, b) => a[b], fruit);
console.log(example1);
console.log(example2);
This will split your string on each dot into an array, and then reduce the fruit array by iterating through the values from the string, applying them to the fruit array, to get the value you are looking for.
Given array:
fruit={sweet:'apple',dry:{f1:'raisin',f2:'almond'},sour:'strawberry'}
And your string:
var str="dry.f1"
To lookup value fruit.dry.f1 you essentially need to write a parser for "dry.f1"
There are plenty of libraries out there that solve this. I give an example below.
AngularJS
Examples of such parsers exist e.g. angular 1.x's $parse: https://docs.angularjs.org/api/ng/service/$parse
var getter = $parse('dry.f1');
var setter = getter.assign;
var context = {sweet:'apple',dry:{f1:'raisin',f2:'almond'},sour:'strawberry'}
expect(getter(context)).toEqual('raisin');
Lodash
Lodash has a get method: https://lodash.com/docs/4.17.4#get
You could make a conditional, if statement that checks if the string has a dot using str.indexOf('.') and do either
fruit[str]
Or
fruit[str1][str2]
In order to access a value in an object given it's path, we must write a function that searches for that value path inside of the object.
Using split and reduce, we use split to break the path into an array of values that were dot-separated in the path (i.e. "dry.f1" becomes ["dry", "f1"]). We then use reduce to iterate over these values in the array, getting deeper into the object in each iteration until we have our value:
function findValueByPath(obj, path) {
return path.split(".").reduce(function(objSoFar, currPath) {
return objSoFar[currPath];
}, obj);
}
For example, findValueByPath( {a: { b: 5 } } , "a.b") returns 5.
Click here to read more about reduce.
Click here to read more about split.
As a side note, this problem is commonly implemented by libraries such as Lodash, which has the function get that does exactly this (click here for get documentation in Lodash).
I'm working with a JSON validator that checks a give JSON object against a schema and returns errors if it doesn't match. One of the things I need to do is add missing attributes, but these could potentially be quite deep in the structure. The validator error returns the location of a missing attribute as a string in this format:
'data.thing1.thing2.thingN'
I can strip out the "data." bit easily enough, but I don't know how to translate the rest to correct object notation, in any depth. This is what I've got so far:
var attributeLineage = newField.split(".");
obj[attributeLineage[0]][attributeLineage[1]] = "";
So obviously this only works when there are only two levels of depth. I need to loop through the values in attributeLineage and link them all together to correctly construct the missing attribute in the given object, at any depth. How can this be done?
I might be missing something totally obvious, or going about it the wrong way, but I'm not sure how to proceed.
Using reduce() method get the reference of the inner object and update the property using last element in split array.
var newField = 'data.thing1.thing2.thingN';
// split the string
var attributeLineage = newField.split("."),
// get last element and remove it from splitted array
prop = attributeLineage.pop();
var ob = {
data: {}
};
// get the object reference
var obj = attributeLineage.reduce(function(o, k) {
// return if nested object is defined
// else define and return it
return o[k] || (o[k] = {}) && o[k];
}, ob);
// update the inner object property
obj[prop] = "hi";
console.log(ob);
When you use Google Analytics DataLayer on your website you have it as a global variable dataLayer.
You can add your own events variables into it.
How can you convert all variables inside it to an object like
{var:value}
You access it like any other object:
var dataLayer = [{
myVar1: 'val1',
myVar2: 'val2
}]
var myVar1 = dataLayer[0].myVar1;
var myVar2 = dataLayer[0].myVar2;
I do not quite understand your heated response to nyuens answer. Firstly, since this is javascript so an array is also an object, secondly the dataLayer is an array of objects or, as we call it in JavaScript, an object (it's called JavaScript Object Notation after all). So you have an array with numeric indexes where every element is an object (which might in turn contain other arrays and objects).
I strongly disagress with nyuen's suggestion to adress elements in the dataLayer with the numeric index, though. If you push data to your dataLayer before the tag manager code dataLayer[0] will contain your custom data, if you don't it will contain the gtm.load event and related data. So this is not reliable.
However it seems want you really want is to flatten the object, i.e. remove the nested structure with numerical keys and have a one-dimensional structure. Luckily somebody has written a function that does this:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
This makes a "one-dimensional" object from a nested object. Usually this would mean that keys with the same name will be overwritten by the respective last element. I.e.
dataLayer = [
{'key':value1},
{'key':value2},
]
would result in a simple
{'key':value2}
since the second "key" overwrites the first. However the function above mitigates this by storing the index as part of the key name, so you would get
{'0.key':value1, '1.key':value2}
which somewhat unfortunately means you cannot use dot syntax and have to adress the elements with angled brackets:
yourvariablename['0.key']
I have a couple of these and think (know) that I'm doing something wrong (or could be simpler).
html:
<div class='item-to-select' data-global-id='55'>some</div>
var l=$(this).map(function(){
t=new Object();
t.global_id=$(this).data('global-id');
return t;
}).get();
var list=l[0]; // want to remove this
How would I remove this intermediary object? Or a better way
thx
If you mean that you don't want to have to define the l variable just so you can use it once in setting up your list variable you can do this:
var list = $(this).map(function(){
return {
global_id : $(this).data('global-id')
};
}).get()[0]; // note the [0] directly after .get()
The return from any function that returns an array (or array-like object) doesn't have to be assigned to a variable before you can use it. So:
var temp = someFuncReturnsArray();
console.log(temp[0]);
// can be replaced by
console.log(someFuncReturnsArray()[0]);
Of course if you need to do further processing on the returned array you need to put it in a variable. E.g., if you need to test its length, or if the function could possibly return null in some situations, etc. In the example above if an empty array was returned then obviously [0] will be undefined.
But if you only need the return value once you can just use it directly.
Note that I've removed the t variable from your code too. When creating an empty object it is considered good practice to say obj = {} rather than saying obj = new Object(). But you can create an object with properties in one step if the property values are already known. In the case of your function the t object you create isn't manipulated in any way other than adding a single property to it before you return it, so you can simply return an object literal directly instead of doing it in three steps.
The jQuery .get() method accepts an index.
So, you can write :
var list=$(this).map(function(){
t=new Object();
t.global_id=$(this).data('global-id');
return t;
}).get(0);