I have the below piece of code in my project. As you can see, I had to check the undefined for all the object and properties this.view && this.view.formView && this.view.formView._dapSections && this.view.formView._dapSections.scrollTop.
I'm looking for a way to check undefined for all at once.Is there any way to do that in JavaScript or dojo?
if(this.view && this.view.formView && this.view.formView._dapSections && this.view.formView._dapSections.scrollTop) {
globals.lastScrollPosition = this.view.formView._dapSections.scrollTop;
}
You might also want to try lang.exists()
https://dojotoolkit.org/reference-guide/1.10/dojo/_base/lang.html#dojo-base-lang-exists
if (lang.exists('view.view.formView._dapSections.scrollTop', this) {
globals.lastScrollPosition = this.view.formView._dapSections.scrollTop;
}
This is precisely the sort of thing that dojo/_base/lang.getObject is designed for.
var scrollTop = lang.getObject('view.formView._dapSections.scrollTop', false, this);
if (scrollTop) {
globals.lastScrollPosition = scrollTop;
}
The first argument is a string representing the properties on the object to look up
The second argument is whether to create each property if it doesn't exist (you usually don't want to do that)
The third argument is the object to use as the context for the lookup
Related
In ES5 whenever I want to get some property I need to first check that it exists like this:
if (typeof floob.flib !== 'undefined') {
// do something
}
even worse is that for nested properties you have to manually check for the existence of every property down the dotted path.
Is there a better way to do this in ES2015?
If it is just a single depth property name - you don't need typeof, you may just compare the value with undefined.
Your solution is prone to false negatives: it may think there is no a property with a given name, while there is one. Example: var o = { foo: undefined };
If you need to check if the path exists in the nested objects - you still need to implement recursion/loop/or use any library that does either for you.
ES2015 did not bring anything new to solve this problem easier.
If you have lodash available, you can use _.get(obj, path, defaultValue) (https://lodash.com/docs#get)
By using typeof,
typeof floob.flib === 'undefined'
equals to,
floob.flib === undefined
I assume you want to check whether floob.flib has a value, and if it does, you want to perform an operation with it.
However, in JS, there's almost simpler way to achieve this.
E.g.
if (floob.flib) {
// 'floob.flib' is NOT 'null', 'empty string', '0', false or 'undefined'
}
This also works well if you want to assign variable with ternary ( ?: ) operators.
var str = floob.flib ? 'exists' : 'does not exist';
Or even using logical OR ( || )
var str = floob.flib || '<= either null, empty, false, 0 or undefined';
Note that unless floob.flib does not produce ReferenceError exception, the code above should work just fine.
I have that function:
function(stringsVar) {
var stringRes = stringsVar || localize_en;
if('window.'+stringsVar === undefined) {
stringRes = localize_en;
}
...
}
and doesn't work. That was like that actually:
function(stringsVar) {
var stringRes = stringsVar || localize_en;
}
that function can take a parameter or not and the code above is checking it correctly. Parameter of that function will be a variable. I want to add that ability to my function. It will check whether that variable is defined or not. If not there is a defined variable at system, localize_en, it will be assigned as default.
How can I correct my code. The second part of my code will be that functionality:
i.e stringsVar is localize_ar and it is not a defined variable (I define that kind of variables with var keyword)
if(window.localize_ar === undefined){
alert('yes');}
else {
alert('no');
}
I will add that functionality as parametric.
Any ideas?
PS: localize_en and something like that variables are object.
EDIT: I am working on JQuery localizer plugin => source code.
I call it as
$('html').localize('localize_' + tr);
However it can not understand it as an object, it works as if I do:
$('html').localize(localize_tr);
It changes it into a string maybe the problem lays on there?
You can use the square bracket notation to refer to object members whose name is stored in a variable, so you're probably looking for this:
if (window[stringsVar] === undefined) {
}
Furthermore, the || operator will return the first truthy; what happens if an object is passed as the first parameter? That's truthy, but you specifically want a string, so whilst the || operator looks cool, you might find the following more appropiate:
if (typeof stringVar !== "string") {
stringVar = "localize_en";
}
It also looks like you're getting confused when to use a string to refer to the object your targeting, and when not to.
When you going to be doing something like:
window[someVar]
someVar needs to be a string.
It is possible to pass an object by reference in JavaScript, and after writing all the above to help you fix the problem you've currently got, a better approach will be to pass the object by reference in the first place and avoid the problem completely, rather than passing the name of the variable storing the object:
function(obj) {
if (typeof obj !== "object") {
obj = localize_en; // here we're wanting the object itself, rather than the name of the object, so we're not using a string.
};
// Now use `obj`. It'll be either the object the user passed, or the default (localize_en).
// You can even store this in a global variable if you want to:
window.selected_obj = obj;
}
Edit:
From your comment, try this:
function (stringsVar) {
if (typeof stringsVar !== "string" || typeof window[stringsVar] !== "object") {
stringsVar = "localize_en"; // Set the default of the argument, if either none is provided, or it isn't a string, or it doesn't point to a valid object
}
var stringRes = window[stringsVar];
// Now do *whatever* you want with stringRes. It will either be the *valid* localization type the parameter specified, or the default ("localize_en").
}
You should pass this function a string.
Because jQuery is a widely used and mature collaborative effort, I can't help but to look at its source for guidance in writing better Javascript. I use the jQuery library all the time along with my PHP applications, but when I look under the hood of this rather sophisticated library I realize just how much I still don't understand about Javascript. Lo, I have a few questions for the SO community. First of all, consider the following code...
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
Now, is this to say that the attr() method was designed to accept EITHER an attribute name, an attribute name and a value, or a pair-value map? Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
Moving on, the whole library is wrapped in this business...
(function(window, undefined) { /* jQuery */ })(window);
I get that the wrapped parentheses cause a behavior similar to body onLoad="function();", but what is this practice called and is it any different than using the onLoad event handler? Also, I can't make heads or tails of the (window) bit there at the end. What exactly is happening with the window object here?
Am I wrong in the assessment that objects are no different than functions in Javascript? Please correct me if I'm wrong on this but $() is the all encompassing jQuery object, but it looks just like a method. Here's another quick question with a code example...
$('#element').attr('alt', 'Adopt a Phantom Cougar from Your Local ASPCA');
... Should look something like this on the inside (maybe I'm wrong about this)...
function $(var element = null) {
if (element != null) {
function attr(var attribute = null, var value = null) {
/* stuff that does things */
}
}
}
Is this the standing procedure for defining objects and their child methods and properties in Javascript? Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
I apologize for this being a bit lengthy, but answers to these questions will reveal a great deal to me about jQuery and Javascript in general. Thanks!
1. Method overloading
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
var attr = function (key, value) {
// is first argument an object / map ?
if (typeof key === "object") {
// for each key value pair
for (var k in key) {
// recursively call it.
attr(k, key[k]);
}
} else {
// do magic with key and value
}
}
2. Closures
(function(window, undefined) { /* jQuery */ })(window);
Is not used as an onload handler. It's simply creating new scope inside a function.
This means that var foo is a local variable rather then a global one. It's also creating a real undefined variable to use since Parameters that are not specified passes in undefined
This gaurds againts window.undefined = true which is valid / allowed.
the (window) bit there at the end. What exactly is happening with the window object here?
It's micro optimising window access by making it local. Local variable access is about 0.01% faster then global variable access
Am I wrong in the assessment that objects are no different than functions in Javascript?
Yes and no. All functions are objects. $() just returns a new jQuery object because internally it calls return new jQuery.fn.init();
3. Your snippet
function $(var element = null) {
Javascript does not support default parameter values or optional parameters. Standard practice to emulate this is as follows
function f(o) {
o != null || (o = "default");
}
Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
You can access properties on an object using foo.property or foo["property"] a property can be any type including functions / methods.
4. Miscellanous Questions hidden in your question
Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
An array is created using var a = [] it simply contains a list of key value pairs where all the keys are positive numbers. It also has all the Array methods. Arrays are also objects.
A map is just an object. An object is simply a bag of key value pairs. You assign some data under a key on the object. This data can be of any type.
For attr, if you give an object instead of a key value pair it will loop on each property.
Look for attr: in jQuery's code, then you'll see it use access. Then look for access: and you will see there is a check on the type of key if it is an object, start a loop.
The wrapping in a function, is to prevent all the code inside to be accessed from outside, and cause unwanted problems. The only parameters that are passed are window that allow to set globals and access the DOM. The undefined I guess it is to make the check on this special value quicker.
I read sometimes jQuery but I didn't start with it, may be you should get some good books to make you an idea first of what some advanced features Javascript has, and then apply your knowledge to the specifics of jQuery.
1 - Yes attr can accept a attribute name for getting a value, a name and a value for setting one value or a map of attribute names and values for settings more than one attribute
2 - A map is basically a JavaScript object e.g:
var map = {
'key1' : 'value1',
'key2' : 'value2'
};
3 - (function(window, undefined) { /* jQuery */ })(window); is something called an anonymous function as it doesn't have a name. In this case it also executes straight away.
A simple example would be:
function test(){
...
}
test();
//As an anonymous function it would be:
(function(){
...
}();
//And it you wanted to pass variables:
function test(abc){
...
}
test(abc);
//As an anonymous function it would be:
(function(abc){
...
}(abc);
this would make it different to the load event, as it is a function not an event.
4 - window is passed as a variable, as it is used internally within jQuery
5 - Objects and functions the same, as everything in JavaScript is an object. jQuery does something like this:
var obj = {
"init" : function(){
}
}
6 - Yes you can use . to retrieve a value on an object but you can also use [] e.g:
var map = {
"test" : 1
}
map.test //1
map["test"] //1
I hope this answers your many questions, let me know if I've missed anything out.
jQuery 1.6.1
The test is typeof key === "object"
if that is true, then you passed a { .... }
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.attr );
},
// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
access: function( elems, key, value, exec, fn, pass ) {
var length = elems.length;
// Setting many attributes
if ( typeof key === "object" ) {
for ( var k in key ) {
jQuery.access( elems, k, key[k], exec, fn, value );
}
return elems;
}
// Setting one attribute
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
return elems;
}
// Getting an attribute
return length ? fn( elems[0], key ) : undefined;
},
I've got this JS Object:
var test = {"code_operateur":[""],"cp_cult":["",""],"annee":["2011"],"ca_cult":[""]}
When I use this function:
for (i in test) {
if ( test[i] == "" || test[i] === null ) {
delete test[i];
}
}
I get:
{"cp_cult":["",""],"annee":["2011"]}
Okay not bad, but I'd like to remove the empty "cp_cult" property (which is an array and not a string like the other).
Note: I don't want to manually delete the key!
It looks like you're asking 2 questions here.
How do I remove a property of an object; and
How can I tell if an object is actually an array.
You can delete a property of an object using the delete operator.
delete test.cp_cult;
In JavaScript arrays are objects, which means that typeof([]) unhelpfully returns object. Typically people work around this by using a function in a framework (dojo.isArray or something similar) or rolling their own method that determines if an object is an array.
There is no 100% guaranteed way to determine if an object is actually an array. Most people just check to see if it has some of the methods/properties of an array length, push, pop, shift, unshift, etc.
Try:
function isEmpty(thingy) {
for(var k in thingy){
if(thingy[k]) {
return false;
}
}
return true;
}
for(i in test) {
if ( test[i] == "" || test[i] === null || (typeof test[i] == "object" && isEmpty(test[i])) ) {
delete test[i];
}
}
However, depending on the complexity of the object, you'd need more advanced algorithms. For example, if the array can contain another array of empty strings (or even more levels) and it should be deleted, you'd need to check for that as well.
EDIT: Trying to make something to fit your needs, please have a look at: http://jsfiddle.net/jVHNe/
[Bounty Edit]
I'm looking for a good explanation when you should set/use null or undefined and where you need to check for it. Basically what are common practices for these two and is really possible to treat them separately in generic maintainable codee?
When can I safely check for === null, safely check for === undefined and when do I need to check for both with == null
When should you use the keyword undefined and when should one use the keyword null
I have various checks in the format of
if (someObj == null) or if (someObj != null) which check for both null and undefined. I would like to change all these to either === undefined or === null but I'm not sure how to guarantee that it will only ever be one of the two but not both.
Where should you use checks for null and where should you use checks for undefined
A concrete example:
var List = []; // ordered list contains data at odd indexes.
var getObject = function(id) {
for (var i = 0; i < List.length; i++) {
if (List[i] == null) continue;
if (id === List[i].getId()) {
return List[i];
}
}
return null;
}
var deleteObject = function(id) {
var index = getIndex(id) // pretty obvouis function
// List[index] = null; // should I set it to null?
delete List[index]; // should I set it to undefined?
}
This is just one example of where I can use both null or undefined and I don't know which is correct.
Are there any cases where you must check for both null and undefined because you have no choice?
Functions implicitly return undefined. Undefined keys in arrays are undefined. Undefined attributes in objects are undefined.
function foo () {
};
var bar = [];
var baz = {};
//foo() === undefined && bar[100] === undefined && baz.something === undefined
document.getElementById returns null if no elements are found.
var el = document.getElementById("foo");
// el === null || el instanceof HTMLElement
You should never have to check for undefined or null (unless you're aggregating data from both a source that may return null, and a source which may return undefined).
I recommend you avoid null; use undefined.
Some DOM methods return null. All properties of an object that have not been set return undefined when you attempt to access them, including properties of an Array. A function with no return statement implicitly returns undefined.
I would suggest making sure you know exactly what values are possible for the variable or property you're testing and testing for these values explicitly and with confidence. For testing null, use foo === null. For testing for undefined, I would recommend using typeof foo == "undefined" in most situations, because undefined (unlike null) is not a reserved word and is instead a simple property of the global object that may be altered, and also for other reasons I wrote about recently here: variable === undefined vs. typeof variable === "undefined"
The difference between null and undefined is that null is itself a value and has to be assigned. It's not the default. A brand new variable with no value assigned to it is undefined.
var x;
// value undefined - NOT null.
x = null;
// value null - NOT undefined.
I think it's interesting to note that, when Windows was first written, it didn't do a lot of checks for invalid/NULL pointers. Afterall, no programmer would be dumb enough to pass NULL where a valid string was needed. And testing for NULL just makes the code larger and slower.
The result was that many UAEs were due to errors in client programs, but all the heat went to Microsoft. Since then, Microsoft has changed Windows to pretty much check every argument for NULL.
I think the lesson is that, unless you are really sure an argument will always be valid, it's probably worth verifying that it is. Of course, Windows is used by a lot of programmers while your function may only be used by you. So that certainly factors in regarding how likely an invalid argument is.
In languages like C and C++, you can use ASSERTs and I use them ALL the time when using these languages. These are statements that verify certain conditions that you never expect to happen. During debugging, you can test that, in fact, they never do. Then when you do a release build these statements are not included in the compiled code. In some ways, this seems like the best of both worlds to me.
If you call a function with no explicit return then it implicitly returns undefined. So if I have a function that needs to say that it did its task and there is nothing result, e.g. a XMLHTTPRequest that returned nothing when you normally expect that there would be something (like a database call), then I would explicitly return null.
Undefined is different from null when using !== but not when using the weaker != because JavaScript does some implicit casting in this case.
The main difference between null and undefined is that undefined can also mean something which has not been assigned to.
undefined false
(SomeObject.foo) false false
(SomeObject.foo != null) false true
(SomeObject.foo !== null) true true
(SomeObject.foo != false) true false
(SomeObject.foo !== false) true false
This is taken from this weblog
The problem is that you claim to see the difference, but you don't. Take your example. It should really be:
var List = []; // ordered list contains data at odd indexes.
var getObject = function(id) {
for (var i = 1; i < List.length; i+=2) {
if (id === List[i].getId()) {
return List[i];
}
}
// returns undefined by default
}
Your algorithm is flawed because you check even indexes (even though you know there's nothing there), and you also misuse null as a return value.
These kind of functions should really return undefined because it means: there's no such data
And there you are in the heart of the problem. If you don't fully understand null and undefined and may use them wrongly sometimes, how can you be so sure that others will use it correctly? You can't.
Then there are Host objects with their nasty behavior, if you ask me, you better off checking for both. It doesn't hurt, in fact, it saves you some headaches dealing with third party code, or the aformentioned non-native objects.
Except for these two cases, in your own code, you can do what #bobince said:
Keep undefined as a special value for signalling when other languages might throw an exception instead.
When to set/use them...
Note that a method without a return statement returns undefined, you shouldn't force this as an expected response, if you use it in a method that should always return a value, then it should represent an error state internally.
Use null for an intentional or non-match response.
As for how/when to check...
undefined, null, 0, an empty string, NaN and false will be FALSE via coercion. These are known as "falsy" values... everything else is true.
Your best bet is coercion then testing for valid exception values...
var something; //undefined
something = !!something; //something coerced into a boolean
//true if false, null, NaN or undefined
function isFalsish(value) {
return (!value && value !== "" && value !== 0);
}
//get number or default
function getNumber(val, defaultVal) {
defaultVal = isFalsish(defaultVal) ? 0 : defaultVal;
return (isFalsish(val) || isNaN(val)) ? defaultVal : +val;
}
Numeric testing is the real bugger, since true, false and null can be coerced into a number, and 0 coerces to false.
I would treat them as 2 completely different values, and check for the one you know might occur.
If you're checking to see if something has been given a value yet, check against undefined.
If you're checking to see if the value is 'nothing,' check against 'null'
A slightly contrived example:
Say you have a series of ajax requests, and you're morally opposed to using callbacks so you have a timeout running that checks for their completion.
Your check would look something like this:
if (result !== undefined){
//The ajax requests have completed
doOnCompleteStuff();
if (result !== null){
//There is actually data to process
doSomething(result);
}
}
tldr; They are two different values, undefined means no value has been given, null means a value has been given, but the value is 'nothing'.