JavaScript object.hasOwnProperty() with a dynamically generated property - javascript

I have an object that I am passing to a function, that I am trying to figure out if the property exists or not, and when it doesn't, ignore it.
The problem is I keep getting false even when the property is there. For sake of example, I will use an object I posted on another question earlier today...
var myObj = {
something1_max: 50,
something1_enabled: false,
something1_locked: true,
something2_max: 100,
something2_enabled: false,
something2_locked: true,
something3_max: 10,
something3_enabled: true,
something3_locked: true
}
which gets passed to a function like: buildRetentionPolicyStr('something2', myObj);
So far I’ve got everything I need with this function working perfectly. Until I tried it on live data and realized on the occasion, properties I thought were static and there with defaults otherwise aren't always actually there. So I need to do something I assume with hasOwnProperty() somehow. So in my function I can set a default of my own where if the property exists, use it..
I.e.:
function buildRetentionPolicyStr(theScope, obj)
{
var myVar = 0;
if(obj.hasOwnProperty(theScope + '_enabled'))
{
myVar = obj[theScope + '_enabled'];
}
}
In my current test case, the object does in fact exist, so I know that to be true. However, when I do (right above the if statement):
console.log(obj.hasOwnProperty(theScope + '_enabled'));
// Or
console.log(obj.hasOwnProperty([theScope + '_enabled']));
I get this output respective to the order above:
false
// Or
["something2_enabled"]
What is, if there is one, the proper way to check to see if the property exists in this fashion?

A simple way to do that is to run typeof against your property:
obj = { xxx: false }
typeof obj.xxx // 'boolean'
typeof obj.yyy // 'undefined'

I ended up doing a review of my code to figure out overall that I had some mix matched cases. While I was in all doing what I should have, I overwrote one of my variables and caused the object I was looking for to essentially to end up going missing. So in fact false was correct.
So to verify the how or which was proper for me in my case.
obj.hasOwnProperty([theScope+'_enabled']);
was the proper way.

Related

Can someone please explain in plain english what is going on in a particular part of my code for objects?

although it is a very simple code, I would like to get a full understanding of what is happening in my condition:
let getFreqOn = function(string){
//set a variable for object
let object = {}
for (let key = 0; key < string.length; key++){
// if (object.hasOwnProperty(string[key])) {
// if (object[string[key]]) {
// if (object[string[key]] !== undefined) {
if (string[key] in object) {
object[string[key]]++
}
else{
object[string[key]] = 1
}
}
return object
}
My main concern would be the first condition, I understand what it is they do but I cant put in to plain English how it is working. For example if (string[key] in object) is basically telling my that if a specific property is in the empty object I defined, then I will set then it will be set as the property and incremented. But what I'm trying to wrap my head around is that the object is empty, so how can the property be in the object?
Hoping someone can enlighten me on the conditions that I commented out as well. Sorry for the noob question.
First, the in operator returns a boolean result. It checks whether the string on the left is present as a property name in the object on the right.
Thus
if (string[key] in object)
asks whether that single character of the string is in use as a property name in the object. As you observed, the very first time through the loop that cannot possibly be true, because the object starts off empty.
Thus the if test is false, so the else part runs. There, the code still refers to object[string[key]], but it's a simple assignment. An assignment to an object property works whether or not the property name is already there; when it isn't, a new object property is implicitly created.
The key difference is right there in the two different statements from the two parts of the if - else:
object[string[key]]++; // only works when property exists
object[string[key]] = 1; // works always

Why does defining properties on process.env leads to strange conditional branching?

I'm trying to test some code that does different things depending on the environment. I thought I might be able to modify properties on process.env in my tests (although I thought it might be a bad idea), but I realized I get this really odd behavior:
let foo = function(inp) {
if (inp) {
console.log(inp + ' -> if')
} else {
console.log(inp + ' -> else')
}
}
// property starts undefined
foo(process.env.prop)
// undefined -> else
process.env.prop = true
foo(process.env.prop)
// true -> if
process.env.prop = false
foo(process.env.prop)
// false -> if !!!
process.env.prop = undefined
foo(process.env.prop)
// undefined -> if !!!
delete(process.env.prop)
foo(process.env.prop)
// undefined -> else
I expected that setting process.env.prop = false would have caused the else branch to execute, not the if branch. If I use properties on new objects, I do get the behavior I expect (Link to REPL demonstrating this: https://repl.it/#JustinKulikausk/TechnologicalThickMuse).
Has anyone else experienced this? I'm really hoping for some insight into why this is happening, not just a workaround for my tests.
Props are strings. From the docs (v10.4.1)
Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.
Your false is converted to 'false' which is "truthy" as it is a valid string of length 5. Same with keyword undefined. Your delete is legit. I'm not sure which part is deprecated, but the behavior you describe looks like it is working as expected.

Have a string value, make it get correct object

I got a data-attribute that got a string value, from that I would like to be able to get the specific json object (the value of the string). So something like this.
The example below is the stripped version (enough to make the point across), check this fiddle for full version of what I'm trying to do.
JSFiddle
<div class="js-carousel" data-conf='{"componentSettings": "CarouselSettings" }'>...</div>
or
<div class="js-carousel" data-conf='{"componentSettings": "CarouselConfig.hero" }'>...</div>
and I got this json objects that got the settings for my js module (in this case it's Slick carousel)
var CarouselSettings = {
accessibility: false,
autoplay: true
};
var CarouselConfig = {
hero: {
accessibility: false,
autoplay: true
},
product: {
accessibility: true,
autoplay: false
}
};
I'm able to have a setting with a string value and to trigger a function.
"mediaQuery": "isBase2Medium"
and that would trigger a mediaquery control function. So I thought maybe I could have a similar approach to this?
Oh my God,the code is too long,I finally find the point of entry to insert eval(...),You can try this solution by use eval(...):
function applySettings(settings) {
var componentSettings = settings.componentSettings;
componentSettings = typeof componentSettings == 'string' ? eval('(' + componentSettings + ')') : componentSettings;
settings.componentSettings = componentSettings;
return settings;
}
function getSettings($element, settings) {
settings = settings === undefined ? applySettings($element.data(elementConf)) : settings;
....
return settings;
}
I have updated your fiddle to do what (I think) you want to achieve:
https://jsfiddle.net/8a4x5y2m/3/
Please note the following changes I made:
The major change is in the getSettings() function. There I introduced a check to see if one particular setting (componentSettings) is declared as an object in the window (global) scope, and if it does, then it replaces the string parameter with the object. Which brings us to point (2)...
You are declaring your configuration objects in global scope using var, but in jsFiddle your whole script is put in a window.onload handler which makes these variables local to the handler. I removed the var keyword to make the parameters global, thus exposing them to the window object, but this is bad practice. Consider putting them either in a global configuration object, and then in the getSettings() method above, replace with window[] with myGlobalConf[].
Also, please note that I only test the componentSettings field. If you want to test every single parameter, then you'll have to iterate over them and do the same check for each.

Get object from array based on property using Lodash _.find

I have an array of objects, say memberToChange.checkboxes: ICheckbox[] like this:
Now, I have a variable, say internalNumber: string which has the value "3419". I want to get the object from the array of objects where the internalNumber matches the label property. Ultimately, I want to set the value attribute of that object to true.
My code is:
let checkboxes = _.find(scope.selectedMembers, (member: IMember) => member.member.uuid === memberId).checkboxes; //gives me array of checkboxes.
let checkboxToChange = _.find(memberToChange.checkboxes, function(checkbox: ICheckbox){
return (checkbox.label === internalNumber);
}); //gives me null, moreover, even a console.log inside the second find doesn't print. I'm thinking the two consecutive _.find statements are messing something up, not sure what.
For reference, this is my ICheckbox interface:
export interface ICheckbox {
label: string;
sublabel?: string;
value: boolean;
numberUuid: string;
}
I would expect that for internalNumber 3419, it should return me the second object from the array. But it returns undefined. I'm not sure what's going on here.
If there is a better way to find and set the value to true in one go only, I'd be happy to know that as well.
Any help is appreciated. Thank you.
Update:
After someone suggested using filter method of javascript, I tried this: (my scope is assigned to this)
scope.selectedMembers.filter(function(member) {
if (member.member.uuid === memberId) {
scope.memberCheckboxes = [];
console.log('found member'); //prints
scope.memberCheckboxes = member.checkboxes;
console.log(scope.memberCheckboxes); // print correctly, with checkboxes of the member
scope.memberCheckboxes.filter(function(checkbox) {
console.log('inside checkbox function'); //control doesnt even come here
if (checkbox.label === intNum) {
console.log('found checkbox'); // control doesnt come here
}
});
}
});
Here, I don't understand why the first console.log inside scope.memberCheckboxes.filter doesn't print? Am I missing something obvious here?
By some reason your memberToChange.checkboxes (or member.checkboxes in your updated question) have no elements.
It is the only explanation why it does not work since your code is otherwise correct. The fact that console.log('inside checkbox function') does not print confirms that.

JavaScript object detection: dot syntax versus 'in' keyword

I have seen two ways of detecting whether a UA implements a specific JS property: if(object.property) and if('property' in object).
I would like to hear opinions on which is better, and most importantly, why. Is one unequivocally better than the other? Are there more than just these two ways to do object property detection? Please cover browser support, pitfalls, execution speed, and such like, rather than aesthetics.
Edit: Readers are encouraged to run the tests at jsperf.com/object-detection
if(object.property)
will fail in cases it is not set (which is what you want), and in cases it has been set to some falsey value, e.g. undefined, null, 0 etc (which is not what you want).
var object = {property: 0};
if(object.isNotSet) { ... } // will not run
if(object.property) { ... } // will not run
if('property' in object)
is slightly better, since it will actually return whether the object really has the property, not just by looking at its value.
var object = {property: 0};
if('property' in object) { ... } // will run
if('toString' in object) { ... } // will also run; from prototype
if(object.hasOwnProperty('property'))
is even better, since it will allow you to distinguish between instance properties and prototype properties.
var object = {property: 0};
if(object.hasOwnProperty('property')) { ... } // will run
if(object.hasOwnProperty('toString')) { ... } // will not run
I would say performance is not that big of an issue here, unless you're checking thousands of time a second but in that case you should consider another code structure. All of these functions/syntaxes are supported by recent browsers, hasOwnProperty has been around for a long time, too.
Edit: You can also make a general function to check for existence of a property by passing anything (even things that are not objects) as an object like this:
function has(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
Now this works:
has(window, 'setTimeout'); // true
even if window.hasOwnProperty === undefined (which is the case in IE version 8 or lower).
It really depends what you want to achieve. Are you talking about host objects (such as window and DOM nodes)? If so, the safest check is typeof, which works for all host objects I know of:
if (typeof object.property != "undefined") { ... }
Notes:
Avoid object.hasOwnProperty() for host objects, because host objects are not obliged to inherit from Object.prototype and therefore may not have a hasOwnProperty() method (and indeed in IE < 9, they generally do not).
A simple Boolean coercion (e.g. if (object.property) { ... }) is a poor test of the existence of a property, since it will give false negatives for falsy values. For example, for an empty textarea, if (textarea.selectionStart) { ... } will not execute the block even though the property exists. Also, some host object properties throw an error in older versions of IE when attempting to coerce to a Boolean (e.g. var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... }).
The in operator is a better test of the existence of a property, but there are once again no guarantees about support for it in host objects.
I recommend against considering performance for this kind of task. Choose the safest option for your project and only optimize later. There will almost certainly be much better candidates for optimization than property existence checks.
For more background on this, I recommend this excellent article by Peter Michaux.
Definitely if ('property' in object) is the right way to go. That actually tests if the property is in the object (or in its prototype chain, more on that below).
if (object.property) on the other hand, will coerce 'property' into a truth/flase value. If the property is unset, it will return "undefined", which will be coerced into false, and appear to work. But this will also fail for a number of other set values of properties. javascript is notoriously inconsistent in what it treats as truthy and falsy.
Finally, like I said above, 'property' in 'object' will return true if it's in anywhere in the prototype chain. If you want to test that's on the object itself, and not somewhere higher up in the chain, you use the hasOwnProperty method like so:
if (object.hasOwnProperty('property')) ...
The first one would fail if "property" is false of 0. To make sure that there actually exist a property you need to check that object.property !== undefined, or use the in-keyword.
[Edit]
There is also the hasOwnProperty-function, but I've never really used that one so I can't say much about it. Though I think it won't return true if the property is set in a prototype, which sometimes you want, other times you don't want.
This allows you to use window.hasOwnProperty as either referring to itself or something else, regardless of your scripting host.
// No enclosing functions here
if (!('hasOwnProperty' in this))
function hasOwnProperty(obj, prop) {
var method = Object.prototype.hasOwnProperty;
if (prop === undefined)
return method.call(this, obj);
return method.call(obj, prop);
}
//Example of use
var global = global || this; //environment-agnostic way to get the global object
var x = 'blah';
WScript.Echo(global.hasOwnProperty('x') ? 'true' : 'false'); //true
//Use as non-object method
var y = { z: false };
WScript.Echo(hasOwnProperty(y, 'z') ? 'true' : 'false'); //true
WScript.Echo(hasOwnProperty(y, 'w') ? 'true' : 'false'); //false
// true ಠ_ಠ
WScript.Echo(hasOwnProperty(global, 'hasOwnProperty') ? 'true' : 'false');

Categories