Setting value of an objects property using dot notation? - javascript

I understand my title might be a little vague, but bear with me.
I was playing with localStorage, so I made some really simple thing I could just mess with in the console of Firefox.
I had the following code:
function saved(data) {
if (localStorage.getItem(data) !== null) {
return localStorage.getItem(data);
} else {
return false;
}
}
var Player = {
canOpenDoors: false ? saved('canOpenDoors') == false : saved('canOpenDoors'),
}
Player.setAbility = function(ability, value) {
Player.ability = value;
localStorage.setItem(ability, value);
}
Player.getAbility = function(ability) {
return Player[ability];
}
console.log(Player.canOpenDoors);
The part in question here is Player.ability = value inside the Player.setAbility function. Obviously, I'm expecting it to treat the ability part as the parameter passed into the function, so that if I do Player.setAbility('canOpenDoors', true) it sets Player.canOpenDoors to true. What I suspect is actually happening is it's setting Player.ability to true instead, as if I want ability to actually be a key of the object.
I can make it work by doing:
Player.setAbility = function(ability, value) {
Player[ability] = value;
localStorage.setItem(ability, value);
}
But unless I've been misinformed, it's not 'correct' to set values of an object as if it was like an associative array. Is there a way I can do this via dot notation, or perhaps I'm missing the point and there's a way to do this specifically for objects?

Related

How can I make this function recursive/run until the requirements are not met?

As of now, I can only hardcode the same snippet after every if statement, which only needs to have the argument that getAdjacentCells(id) takes changed. I haven't been able to find a way to repeat this part. I think this can be done recursively, but I don't know how to do it.
Edit: I initially typed that isCellEmpty got an array of objects: [{topLeft: null}, {topCenter: "cell-1-2"}, {topRight: "cell-1-3"}, {middleLeft: null}, {middleRight: "cell-2-3"}], when in reality it is a single object: {topLeft: null, topCenter: "cell-1-2", topRight: "cell-1-3", middleLeft: null, middleRight: "cell-2-3"}
// Gets an object that looks like this: {topLeft: null, topCenter: "cell-1-2", topRight: "cell-1-3", middleLeft: null, middleRight: "cell-2-3"}
function isCellEmpty(adjacentCells) {
Object.values(adjacentCells).forEach(id => {
// Checks that the ids in stored in the object values do not equal null
if (id !== null) {
board[getBoardPosition(id)].opened = true;
// getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
// if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
if (typeof (getAdjacentCells(id)) === "number") {
// Removes all other divs, this prevents repetition
$("#" + id).empty();
// Appends an empty div
$("#" + id).append("<div></div>");
// HERE'S WHERE IT STARTS: If getAdjacentCells(id) returns an object, do the same as above with every id in it
} else if (typeof (getAdjacentCells(id)) === "object") {
Object.values(getAdjacentCells(id)).forEach(id2 => {
if (id2 !== null) {
board[getBoardPosition(id2)].opened = true;
if (typeof (getAdjacentCells(id2)) === "number") {
$("#" + id2).empty();
$("#" + id2).append("<div></div>");
// HERE IT REPEATS:
} else if (typeof (getAdjacentCells(id2)) === "object") {
...
}
}
})
}
}
});
}
You can make the recursive call with the value you get from getAdjacentCells. Make sure however to call getAdjacentCells only once for the same id. Now it is quite inefficient as you repeat the same call.
See also some other suggestions in the code.
function isCellEmpty(adjacentCells) {
// I would move this check here, although not necessary if you prefer it in the loop.
if (typeof adjacentCells === "number") {
$("#" + id).empty().append("<div>"); // You can chain jQuery...
return;
}
for (let id of adjacentCells) { // Just use a for..of loop
if (id === null) continue; // keep IF-ELSE nesting flat.
let cell = board[getBoardPosition(id)];
if (cell.opened) continue; // Add this to avoid circling around
cell.opened = true;
isCellEmpty(getAdjacentCells(id)); // recursive call
}
}
Object.values
You write in the comments of your code that:
getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
However, your comments below this answer seem to suggest that this is not (always) the case. It maybe a plain object which would explain why you used Object.values to iterate it. If this is the case I would urge to change getAdjacentCells so that it really does return an array. Or if that is not possible then use Object.values like you already did:
function isCellEmpty(adjacentCells) {
// I would move this check here, although not necessary if you prefer it in the loop.
if (typeof adjacentCells === "number") {
$("#" + id).empty().append("<div>"); // You can chain jQuery...
return;
}
for (let id of Object.values(adjacentCells)) { // Just use a for..of loop
if (id === null) continue; // keep IF-ELSE nesting flat.
let cell = board[getBoardPosition(id)];
if (cell.opened) continue; // Add this to avoid circling around
cell.opened = true;
isCellEmpty(getAdjacentCells(id)); // recursive call
}
}
Recursion should work just fine here: at its most basic you'd call your own method with id2. However, assuming getAdjacentCells may return cells that you've already visited, you'll end up recursing infinitely unless you're able to track which IDs you've already visited, and pass that in.
function setCellState(id, visited) {
if(id === null) {
return;
}
if(visited === undefined) {
visited = new Set();
}
if(visited.has(id)) {
return;
}
visited.add(id);
board[getBoardPosition(id)].opened = true;
// getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
let adjacentCells = getAdjacentCells(id);
// if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
if (typeof (adjacentCells) === "number") {
// Removes all other divs, this prevents repetition
$("#" + id).empty()
// Appends an empty div
.append("<div></div>");
} else if (typeof (adjacentCells) === "object") {
Object.values(adjacentCells).forEach(id2 => setCellState(id2, visited));
}
I took the liberty of changing the method name to be more representative of what the method actually does. I also changed it to start with a single cell's ID, since that simplifies the recursion and that allows the comment around the behavior of getAdjacentCells to provide better context.

How to access property in function by sending values from function call

i am sending values from function call
this.checkname("models", "name");
this.checkname("designers", "name");
i want to access my object.method by using a function call=>
checkname = (key, value) =>{
const models = this.state.model;
const designers = this.state.designers;
if(key.value === ""){
console.log("Unanamed");
}
}
i am not able to access (key.value) how to do that?
You can’t use a variable to access an objects property with the „.“ notation instead use: key[value].
This of course only works, if the value supplied as „key“ argument is an object (as was pointed out in the comments).
Edit: Ok now I seem to actually understand what you’re trying to do. If you want to use either this.state.models or this.state.designers depending on what string is supplied as key, you will have to supply some kind of condition (if-else) to decide which to use. Something along the lines of:
let person;
if (key === "models") {
person = this.state.models;
} else if (key === "designers") {
person = this.state.designers;
}
if (person[value] === "") {
...
}

BEGINNER HERE If/else statements with booleans JAVASCRIPT

I am having some trouble with this current lesson on control flow with JavaScript...
The question states:
In this exercise, you will be given a variable, it will be called value.
You will also be given another variable, it will be called greaterThanFive.
Using an 'if statement' check to see if the value is greater than 5. If it is, re-assign the boolean true.
code with stars next to it is the code I was given.
**let greaterThan5 = false;**
if (value > 5 ) {
console.log("That is true");
}
**return greaterThanFive;**
I have tried a number of different ways on how to write the correct code but it obviously is not right.
I tried assigning var value = 10;and then finishing the code as above but it says value has already been assigned. I have tried changing the boolean to let greaterThanFive = true;
The hint only tells me that "should return boolean value equal to 10" and "expected true to be false"
Please help, I have been working on this simple code it may seem for a week and do not want to move on to the next lesson without fully understanding this question.
Thank You!
You have two different variables; greaterThan5 and greaterThanFive.You also have a return statement, which will only work inside of a function.
I believe what you're looking for is something like the following, which passes a value into the function, then checks whether the value is greater than five or not, setting the variable to true inside of the if conditional if it is. The function then returns the greaterThan5 variable's truthiness:
function greater(value) {
let greaterThan5 = false;
if (value > 5) {
greaterThan5 = true;
}
return greaterThan5;
}
console.log(greater(10));
console.log(greater(3));
Which can be further simplified to a simple one-line return statement:
function greater(value) {
return value > 5;
}
console.log(greater(10));
console.log(greater(3));
So, the first clue in the code is the return statement. That means you are likely being asked to write a function that, given some value, checks to see if that value is greater than 5.
Let's define it using your existing code:
function isGreaterThan5(value) {
let greaterThan5 = false;
if (value > 5 ) {
console.log("That is true");
}
return greaterThan5;
}
So right now, we're always going to return false. All you need to do is reassign the value of greaterThanFive if value > 5. So, you can simply do that in your if-statement:
function isGreaterThan5(value) {
let greaterThan5 = false;
if (value > 5 ) {
greaterThan5 = true;
}
return greaterThan5;
}
You can now test your code by calling the function with various values:
isGreaterThan5(1); // returns false
isGreaterThan5(5); // returns false
isGreaterThan5(6); // returns true
And we're done!
I'm wondering if what confused you was the use of let. You might want to read more about var, let, and const.
if (value > 5) {greaterThanFive = true;}

looping through objects to return objects with 'distinct' property - Javascript

I have a list of objects as shown in the image.
These all have the property statusCode: 62467 but the journey property goes like: 0,1,2,3,3,4,4,4,4
I want to loop through these objects and return the FIRST of the duplicated (they are not the same object, just that both have the same journey number and the same status code) objects with the same journey number.
So I want to return the bold objects: 0,1,2,3,3,4,4,4,4
$.each(points, function (index, point) {
for (i = 0; i < journeyNumber.length; i++) {
if (point.k.journey === journeyNumber[i] && point.k.statusCode === '62467') {
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
}
});
The screenshot is the log of console.log(point), so ideally I would like another loop inside which returns only the first object of the same journey number.
Hope this makes sense and thank you for your time.
Try this,
var temp = [];
$.each(points, function (index, point) {
if (temp.indexOf(point.k.journey) === -1) {
temp.push(point.k.journey);
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
});
Create a fresh object with status codes and check against that.
var journeys = {};
for(object in points){
// extract the properties you want (or use them directly, this is not necessary)
var journey = points[object].journey;
var status = points[object].statusCode;
// use the typeof operator to see if the journey has already been set before
if(typeof journeys[journey] == "undefined"){
// then define it.
journeys[journey] = status;
}
}
(Please note I am not actually correctly referencing the journey and statusCode, you'd have to do something like objects[object][k].journey to access the right property, but thats not really the point)
You can even add anything you want into the journeys object, nesting another object with the extracted latitude and longitude, or even just nesting the entire object in the journey!
journeys[journey] = points[object];
Now you can get every journey by looping through them again, and the associated first statusCode:
for(journey in journeys){
console.log("First instance of journey " + journey + " had statusCode " + journeys[journey]);
}

Javascript 'First or Default' function for 'associative arrays'/objects

Is there a better way to do this?
I'm storing values in what some would erroneously call an associated array:
The tokens object stores.... tokens and a count of documents using that token on a per-db level.
var tokens = {'db1' : { '654321': { 'docCount': 1 },
'321456': { 'docCount': 2 } },
'db2' : { '999999': { 'docCount': 1 } } };
I can add/remove dbs and tokens and update the docCounts appropriately.
We can assume, due to code omitted for brevity, that if a db exists, a token also exists with a docCount of at least 1.
If a db exists and I need to retrieve ANY of its tokens, what is the best method?
If the dbs held arrays, it would be as easy as tokens['db1'][0]... but I'm not using arrays.
I have something like the following, "inspired" by LINQ (please don't blame LINQ):
// NOTE: default not implemented here
var firstOrDefault = function(obj) {
var thing;
for (var i in obj) {
thing = i;
break;
}
return thing;
};
which would be called as so (simplified for example):
var anyToken;
if (tokens['db1') { anyToken = firstOrDefault(tokens['db1']); }
Generally returning per the above example '654321' (as this is an object, not an array, order is not guaranteed, but either value is acceptable in my code).
Is this a reasonable method to get any value?
Is there a better method?
Should I just suck it up, shove everything into an array, and wrap the storage features that way?
UPDATE: I've removed the default reference, as an unfound item will a perfectly acceptable undefined response:
// NOTE: obj.hasOwnProperty not implemented for brevity
var firstOrAny = function(obj) {
var thing;
for (var i in obj) {
thing = i;
break;
}
return thing;
};
which would be called as so (simplified for example):
var anyToken;
if (tokens['db1') { anyToken = firstOrAny(tokens['db1']); }
Slightly shorter solution:
var firstOrDefault = function(obj, d) {
for (var i in obj)
{
if (obj.hasOwnProperty(i))
{
return obj[i];
}
}
return d;
};
But yes, it is the fastest way to get any (usually first inserted) key from an object.
I also added a hasOwnProperty check to prevent cases where the values are retrieved from the prototype chain.

Categories