Related
This drives me into madness every time I have to deal with it. I cannot tell you the hours of extra coding that I encounter because of this, what I feel, is a flaw of TypeScript.
It does not make any sense to me that I have to set a property to undefined in order to then set it with actual values.
here is the example:
// why do i have to do this?
this.aClass.aInterface: ClassAndInterface = {
aProperty: undefined
}
this.aClass.aInterface.aProperty: ClassAndInterface = {
name: 'The Name',
description: 'A description'
};
I feel like there should something for this erroring out to set a property that be can be applied to mitigate this error. If I am trying to set the property the fact it is undefined isn't a concern to me especially when the value is optional.
I have what I feel is a good answer to why this is occurring and why it may be easier to come across this problem in TypeScript versus writing js on it's own.
The problem stems from working with classes and objects more readily in Typescript not that you can't obviously do the same thing with js. However, when you start using interfaces and types to interfaces and classes this can be where things have more need for understanding.
The issue truly comes from taking a property to far. People actually post about this exact issue a lot and from what I see it is a misunderstanding in its truest sense.
What's the misunderstanding exactly? As #jcalz posted in the above message
let x;
x.a = 123 // NO <<< you can't do that
It is really that simple. However, when you writing pretty and well formed objects you can quickly do something like this.
x = {
a: 3
}
x.a = 3; <<< this is OK
That is all good and understood so why does Typescript constantly get me with that error. The answer is actually when you're trying to be responsible and write classes and interfaces that are typed to properties and you go a level one too far.
What do I mean when I say a level one too far? It's when you try take a base class and or interface and set the property of an interfaced property from that base class. It could be a classed typed property just the same.
At that point you are dealing with a property that technically hasn't been defined.
What should you do that would mitigate the issue and not cause errors or mistakes in your coding?
What you should do is act upon the interface directly with a new property that is set to that interface. You can do the same if it were a class. Afterwards, you should set the base property to that new property directly that is of the interface and or class. (this is shown in the code sample below)
Also, and you may need to do this as I found out, you can set the property to undefined. Alarm bells, code smell and caveats come with this approach.
You have to set every property in that interface or class to undefined or some value (intiate)
You have deal with the fact you set every property upstream to undefined meaning you might not want to carry a bunch of undefined values in your object.
A lot of guarding (if statements) and protections are needed downstream so that you don't come across runtime errors
It feels like code smell and it probably is
What is code smell? I don't know exactly but you should do it I know that and it doesn't actually smell
So, why would you do this as opposed to doing it the right way? Well in my case I was passing along an object from class to class and I was trying to use that exact object that would return again whole.
Instead what I should have done is passed a new object with the base object and new object {base: baseObj, new: newObj} and just returned both of those.
In any event I have included code that you can go to the playground and play with the Typescript Editor and see what it is that I am speaking of and what the differences are of doing one method versus the other.
interface SomeInterface {
interFaceProp1: string|undefined;
interFaceProp2?: string;
}
class SomeClass {
public prop1: SomeInterface|undefined;
prop2: string|undefined;
prop3!: string;
}
let localProp = new SomeClass();
// this is to mitigate an issue
// localProp.prop1 = {
// interFaceProp1: undefined
// }
/** or instead do this so that it makes more sense and is accurate to the capability of the object
* and to what is the expected output of the object
*/
let otherLocalProp: SomeInterface;
otherLocalProp = {
interFaceProp1: 'Tristan'
}
console.log(otherLocalProp.interFaceProp1);
localProp.prop1 = otherLocalProp;
localProp.prop1.interFaceProp1 = 'Carlos';
console.log(localProp.prop1.interFaceProp1);
console.log(otherLocalProp.interFaceProp1);
otherLocalProp.interFaceProp1 = 'Christian'
console.log(localProp.prop1);
I'm learning Javascript and I wrote the following code:
if (mystring.len > 0) {
// do stuff
}
I accidentally used .len instead of .length. To my surprise, no error was raised. mystring.len returned undefined and this made the comparison fail but the code kept right on running. I would prefer an actual error to be raised so I can fix the code. Adding "use strict" didn't help, nor did jslint.
I know there are ways to actively check whether or not a property exists, but that's not what I'm looking for. I want Javascript to tell me when I've made a typo in a property name.
Is there a way to cause Javascript to give an error in this case?
Nope - that is how JavaScript works and it's incredibly useful. Who is to say that checking len is something that needs fixing? Consider:
if(mystring.len === undefined) {
mystring.len = "Test";
}
The best you can do is to simply check that the thing is defined before using it:
if(mystring.len !== undefined) {
}
I appreciate the strangeness, and how it doesn't feel robust (having originally come from a C# background) but there isn't a lot you can do unfortunately. The fact that JavaScript is case sensitive makes this even more frustrating. You will learn to live with it though!
If you really really wanted to run some static analysis then you could considering creating a transpiler (e.g. Babel) extension to run this sort of analysis - but it would get really difficult if you ever expected something to be undefined which I find is common place.
edit
Here's a real example that I'd use where undefined is useful. I'm working with a library that needs to move stuff from one location to another. It can't do that unless the original location has been specified, so I might write something like the following, initializing values if I don't have them for some reason:
function update(node) {
if(node.x === undefined) { node.x = 0; }
node.y = node.y || 0; // This is the shorthand way I'd actually write it
// Do some other stuff
};
"use strict" (in my experience) is used so that variables that aren't explicitly declared/instantiated that are then referenced will throw errors (else, JS would just make a new var on the fly). So that wouldn't help here.
This sounds like an error that would typically be picked up by a compiler in other languages, but since JS is interpreted, you won't have that kind of explicit error checking unless you're in a beefy IDE. Are you using a text editor or something to write JS?
Thats not the way JavaScript considers your above code. Every variable in JS is an object. So, when you do mystring.len, its actually trying to access the len property of mystring obj and when it doesn't find that property, it will return undefined - which is how it should be. Thats why you will not be able to find any error using JSLint.
Just to give you an example -
var myObj = {name: 'Hello', id: 1};
console.log(myObj.name); // Returns 'Hello'
console.log(myObj.text); // 'undefined'
In order to prevent such code from giving you any errors, you can easily use the hasOwnProperty() method like follows-
if(myObj.hasOwnProperty('text')) doSomething();
Since myObj doesn't have any property text, the doSomething() function will never be called.
This is the behaviour of JavaScript as mentioned by many/all answers. However there is an option to prevent new properties you might want to try:
Object.seal https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal
The simple answer is JavaScript is not ment to be typesafe...You shouldn't check it, but if you still want to check you can do it by:
if ('len' in mystring){
}
You should look into Typescript if you ask this question...
I have a large, messy JS codebase. Sometimes, when the app is being used, a variable is set to NaN. Because x = 2 + NaN results in x being set to NaN, the NaN it spreads virally. At some point, after it has spread pretty far, the user notices that there are NaNs all over the place and shit generally doesn't work anymore. From this state, it is very difficult for me to backtrack and identify the source of the NaN (and there could very well be multiple sources).
The NaN bug is also not easily reproducible. Despite hundreds of people observing it and reporting it to me, nobody can tell me a set of steps that lead to the appearance of NaNs. Maybe it is a rare race condition or something. But it's definitely rare and of uncertain origins.
How can I fix this bug? Any ideas?
Two stupid ideas I've thought of, which may not be feasible:
Write some kind of pre-processor that inserts isNaN checks before every time any variable is used and logs the first occurrence of NaN. I don't think this has been done before and I don't know how hard it would be. Any advice would be appreciated.
Run my code in a JS engine that has the ability to set a breakpoint any time any variable is set to NaN. I don't think anything does this out of the box, but how hard would it be to add it to Firefox or Chrome?
I feel like I must not be the first person to have this type of problem, but I can't find anyone else talking about it.
There is probably no solution for your problem aka: break, whenever any variable is set to NaN. Instead, you could try to observe your variables like this:
It was earlier stated, that the Chrome debugger offers conditional breakpoints. But, it also supports to watch expressions. In the Watch-Expressions menu you can set a condition to break, whenever the variable is set to a specific value.
Object.observe is a method that observes changes on a object. You are able to listen to all changes on the object, and call debug when any variable is set to NaN. For example, you could observe all change on the window object. Whenever any variable on the window object is set to NaN, you call debug. Please note, that Object.observe is quite cutting edge and not supported by all browsers (check out the polyfill in this case).
Take this opportunity to write a test case for every function in your code. Perform random testing and find the line of code that can create NaN values.
Another problem of yours is probably how to reproduce this error. Reloading your webpage over and over doesn't make too much sense. You could check out a so called headless browser: It starts an instance of a browser without displaying it. It can be leveraged to perform automatic tests on the website, click some buttons, do some stuff. Maybe you can script it in such a way that it finally reproduces your error. This has the advantage that you don't have to reload your webpage hundreds of times. There are several implementations for headless browsers. PhantomJS is really nice, in my opinion. You can also start a Chrome Debug Console with it (you need some plugin: remote debugger).
Furthermore, please notice that NaN is never equal to NaN. It would be a pity if you finally are able to reproduce the error, but your breakpoints don't work.
If you're doing a good job keeping things off of the global namespace and nesting things in objects, this might be of help. And I will preface this by saying this is by no means a fully complete solution, but at the very least, this should help you on your search.
function deepNaNWatch(objectToWatch) {
'use strict';
// Setting this to true will check object literals for NaN
// For example: obj.example = { myVar : NaN };
// This will, however, cost even more performance
var configCheckObjectLiterals = true;
var observeAllChildren = function observeAllChildren(parentObject) {
for (var key in parentObject) {
if (parentObject.hasOwnProperty(key)) {
var childObject = parentObject[key];
examineObject(childObject);
}
}
};
var examineObject = function examineObject(obj) {
var objectType = typeof obj;
if (objectType === 'object' || objectType === 'function') {
Object.observe(obj, recursiveWatcher);
if (configCheckObjectLiterals) {
observeAllChildren(obj);
}
} if (objectType === 'number' && isNaN(obj)) {
console.log('A wild NaN appears!');
}
};
var recursiveWatcher = function recursiveWatcher(changes) {
var changeInfo = changes[0];
var changedObject = changeInfo.object[changeInfo.name];
examineObject(changedObject);
};
Object.observe(objectToWatch, recursiveWatcher);
}
Call deepNaNWatch(parentObject) for every top level object/function you're using to nest things under as soon as they are created. Any time an object or function is created within a watched object/function, it itself will become watched as well. Any time a number is created or changed under a watched object--remember that typeof NaN == 'number'--it will check if it's NaN, and if so will run the code at console.log('A wild NaN appears!');. Be sure to change that to whatever sort of debugging output you feel will help.
This function would be more helpful if someone could find a way to force it onto the global object, but every attempt I made to do so simply told me I should sit in time out and think about what I've done.
Oh, and if it's not obvious from the above, on a large scale project, this function is bound to make pesky features like "speed" and "efficiency" a thing of the past.
Are your code communicate with your server side, or it is only client side?
You mention that it is rare problem, therfore it may happend only in some browsers (or browsers version) or on any situation which may be hard to reproduce. If we assume that any appearance of nan is problem, and that when it happend user notice bug ("there are NaNs all over the place"), then instead display popup with error, error should contain first occurence of nan (then users may raport it "Despite hundreds of people observing it and reporting it to me"). Or not show it, but send it to server. To do that write simple function which take as agument only one variable and check if variable is NaN,. Put it in your code in sensitive places (sensitive variables). And this raports maybe solate problematic code. I know that this is very dirty, but it can help.
One of your math functions is failing. I have used Number(variable) to correct this problem before. Here is an example:
test3 = Number(test2+test1) even if test1 and test2 appear to be numbers
Yeah man race conditions can be a pain, sounds like what it may be.
Debugging to the source is definitely going to be the way to go with this.
My suggestion would be to setup some functional testing with a focus on where these have been reproduced, set some test conditions with varied timeouts or such and just rerun it until it catches it. Set up some logging process to see that backtrace if possible.
What does your stack look like? I can't give too much analysis without looking at your code but since its javascript you should be able to make use of the browser's dev tools I assume?
If you know locations where the NaNs propagate to, you could try to use program slicing to narrow down the other program statements that influence that value (through control and data dependences). These tools are usually non-trivial to set up, however, so I would try the Object.observe-style answers others are giving first.
You might try WALA from IBM. It's written in Java, but has a Javascript frontend. You can find information on slicer on the wiki.
Basically, if the tool is working you will give it a program point (statement) and it will give you a set of statements that the starting point is (transitively) control- and/or data-dependent on. If you know multiple "infected" points and suspect a single source, you could use the intersection of their slices to narrow down the list (the slice of a program point can often be a very large set of statements).
(was too long for a comment)
While testing you could overwrite ALL Math functions to check if an NaN is being produced.
This will not catch
a = 'string' + 1;
but will catch things like
a = Math.cos('string');
a = Math.cos(Infinity);
a = Math.sqrt(-1);
a = Math.max(NaN, 1);
...
Example:
for(var n Object.getOwnPropertyNames(Math)){
if (typeof Math[n] === 'function') Math[n] = wrap(Math[n]);
}
function wrap(fn){
return function(){
var res = fn.apply(this, arguments);
if (isNaN(res)) throw new Error('NaN found!')/*or debugger*/;
return res;
};
}
I didn't tested, maybe an explicit list of the "wrap"ed methods is better.
BTW, you should not put this into production code.
Generally, I test whether or not a variable is set with something like this:
if (variable !== '') {
do something...
}
I know there are other methods for testing variables like typeof but I don't see any advantage - is this an appropriate way to test whether or not a variable is set? Are there problems with it that I should be aware of ?
Two reasons:
1) What if the variable is set by getting the contents of an empty input box?
if(someScenario){
var variable = $('empty-box').val(); }
Perhaps this is only done in certain cases, like when someScenario is true. Later on, you want to check if that variable was set. Your means returns false rather than true. Point is, you can come up with scenarios where you get wrong answers.
There's just no reason not to do it the accepted way.
if(typeof variable !== 'undefined')
It's no slower, has no real flaws, and is only a few characters more.
2) And most importantly, using typeof makes it totally clear what you're asking. Readability is crucial, and if another programmer read the first code, they would think you were checking that it wasn't an empty string. The method using typeof makes it perfectly clear what your conditional is looking for, and reduces the odds of mistakes later on.
If variable has been declared but might not have a value then your code:
if (variable !== '') {
tests if it is not the empty string. Is that what you want? An empty string might be a valid value. Better to test for undefined, or explicitly initialise it to a value that you can then treat as "invalid" (perhaps null, or whatever suits).
If variable has not been declared at all the above code would result in an error such that execution would stop at that point - you can't test the value of a variable that doesn't exist. So if, for example, you're trying to test a global variable that is created inside a function that may not have been called yet, or perhaps you're using several JS files and one needs to test a variable that may or may not have been created by one of the other files, then the only way to do it is with:
if (typeof variable != "undefined") {
Since you're using strict equality testing, the following will all return true:
false
undefined
null
0
The only time your check will return false is when you pass in an empty string.
Is that what you want?
Check out coffeescript's existential operator, by searching "The Existential Operator" on this page: http://coffeescript.org/
The functional problem with your approach is that is that you may inadvertently assign a blank string to variable at some point prior in your script and your logic block will now do the wrong thing.
From a stylistic standpoint your solution is less desirable because your intent to check the existence of the variable is not clear. Someone who was just reading through your code for this the first time might misunderstand what you wrote to mean "I'm expecting there to be a variable named variable set to the blank string" as opposed to "Do something if this variable does not exist."
This might be highly subjective, but my recommendation is to avoid code, that needs to check, whether a variable is set (a.o.t. has some value or type).
Consider this snipplet
var a=false;
if (some_condition) a="Blah";
if (typeof(a)=='string') ....
if (a===false) ...
this makes sure, a is always set, while keeping it easily differentiable from '', null or 0
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Lately I've been writing some JS code using jQuery and JavaScript as it is and I thought I will give JSLint a try. Let me say that the code contains various functions and jQuery usages and it works fine (without any errors ) in IE8 and latest Firefox.
The code also validatas as XHTML 1.0 Transitional (and Strict too but I mostly want it to be Transitional valid).
However, with JSLint it's like everything is wrong. While I have read about it being very strict, even if I turn on only "The Good Parts" it's still like 70+ errors in a typical HTML page.
It starts out with this (why in the world would I want to remove the type to make my documents XHTML invalid??)
Problem at line 5 character 67: type is unnecessary.
<script src="/Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
and goes on with esoteric errors like
Problem at line 41 character 41: Use the array literal notation [].
var rows = new Array();
Problem at line 42 character 30: Too many var statements.
for (var i = 0; i < data.length; i++) {
Problem at line 42 character 55: Unexpected use of '++'.
for (var i = 0; i < data.length; i++) {
Problem at line 64 character 50: ['PrettyId'] is better written in dot notation.
var item = $("#item_" + data["PrettyId"]);
If anyone can provide me answers to these errors and especially, how to make JSLint be aware of jQuery and understand it, I will appreciate it.
If not, please explain whether you use it or not and whether you advice to use it or not.
UPDATE:
I'm going to wait one more day for more answers, if any, then I'll accept the answer with the most upvotes.
A thing to remember when using JSLint is that is built on the opinion about what one person thinks is the "Good Parts".
I think is a great tool but there are rules that I don't agree with.
About the type attribute, you can find more about the opinion of the author here he says that the attribute is "required and non necessary", but if you validate your documents you clearly need it.
With the use of the Array literal notation [] vs. the Array constructor, I agree, there are differences that can make the two syntaxes behave different, for example:
[5]; // one-element array
["5"]; // one-element array
new Array(5); // empty array but its length is initialized with 5
new Array("5"); // one-element array
So, for consistency an brevity the literal notation is better.
About the "Too many var statements", JavaScript has no block-scope, the scope is at function or global level, and all var statements are evaluated before the code execution -aka hoisting- and they are initialized with undefined, while the assignments are made at runtime.
For example:
var x = 0;
if (true) {
var x = 1; // useless var, x already declared
}
x; // 1
And the "hoisting" of variable declaration can be shown in this example:
var x = 5; // global
(function () {
alert(x); // alerts `undefined`, x declared but unassigned in this scope
alert(y); // ReferenceError, y is undeclared
var x = 10;
})();
As you can see x holds undefined because it is declared before the actual code execution, the var statements are hoisted to the top of their enclosing scope:
var x = 5; // global
(function () {
var x;
alert(x); // alerts `undefined`, x declared but unassigned
alert(y); // ReferenceError, y is undeclared
x = 10; // assignment is made
})();
So that rule wants to actually make the code to resemble what will happen, all the var statements at first place.
About the "Unexpected use of '++'", this is another rule that I don't quite like, the author thinks that "those contribute to bad code by encouraging excessive trickiness".
When I use them in some expression, I try to extract the operator usage to an alone statement, for example:
array[++id] = x;
To:
id+=1;
array[id] = x;
Which is more clearer, but anyway in the case of a for statement IMO it can't cause any confusion at all...
About the last one "['PrettyId'] is better written in dot notation.", JSLint expects the usage of the bracket notation to be "dynamic", it expects to see an expression there, not a String literal that contains a valid identifier name, the bracket notation should be used only when you want to access a property with a name that clashes with a reserved word e.g.:
data.function; // SyntaxError in ECMAScript 3 based implementations
data["function"]; // Ok
Or when a property contains characters that are not a valid identifier, e.g.:
data.foo-bar; // it access the property `foo` minus a `bar` variable
data["foo-bar"]; // Ok
data.foo bar; // SyntaxError, unexpected `bar` identifier
data["foo bar"]; // Ok
I use jslint on .js files and find a combination of options and fixes to make it happy. I find it improves my code quality. I would recommend running it, even if you only use it to isolate omitted 'var' declarations.
I avoid the script tag warning by not running against html files. I use jslint systematically on .js files, but not on html. I find it is just too burdensome to declare all the global identifiers that got defined in included scripts, but aren't visible to jslint.
Crockford's book 'Javascript: The Good Parts' explains many if not all of the jslint warnings, and some of them are based on perceived bug proneness. The 'new Array()' vs ' []' warning is based on Doug's aversion to the 'new' operator. Omitting 'new' for various constructors is commonly valid code, but not correct code, and using the alternative syntax avoids that risk.
The 'too many vars' error means just that, a large number of 'var' declarations in a given function: the Crockford endorsed style is to use one or very few 'var' declarations, all at the top of the function. You can declare multiple variables in one var statement, by separating them with commas.
The '++' caution is another bug proneness based warning; Using '+=1' means the same thing, and Doug believes it to be less error prone.
jslint is thus a mixed bag. Some features (locals vs globals) are invaluable, some (script types) are just annoying, and many are of dubious benefit but harmless.
jQuery itself passes jslint checks, as described here:
http://docs.jquery.com/JQuery_Core_Style_Guidelines#JSLint
There's an old joke about a programmer who smoked. A friend said, "You're a really smart guy, can't you read the warning on the pack that says cigarettes will kill you?" Came the reply: "I'm a programmer. We only pay attention to errors, not warnings."
Sometimes JSLint tells you things that are critical, sometimes it just nags. You can get lost trying to make it happy, but you might just be lost without it. Like any other tool, its input should be taken with a grain of salt. I prefer to think of it like the spell-checker or grammar-checker in MS Word. Sometimes it's right, sometimes it's wrong, and sometimes I just don't care what it tells me.
It hurts when you start using it on your old code.
But then it will save you a lot of time.JSLint can detect many problems that you would only see when refreshing your page or worse when your users do.Now it hurts me when I have to use an editor without JSLint
Another advantage is when you start compressing your javascript. If you pass the JSLint checks, you are almost certain to compress without problems.
That being said, jquery has 23 warning, most of them about regex, but is widely used without any problems.
JSLint is a Code Quality tool. It's not like W3C validator. Consider it something like a weekly code review at a company. Coding conventions vary and JSLint is just one of them. There may be points you don't agree with, but if you work in a team and you need to manage a larger codebase JSLint can be a life saver. Why? Because it warns you about things that are confusing or error prone.
The best way to use JSLint is this: read everything it says and if you're unsure about something correct it as suggested (as it seems to be the case here).
The reason is that JSLint is meant to avoid confusion and if you're using something that can lead to errors and you don't know why, then you better off with a clear alternative.
And if you want to know the reasoning behind the suggestions watch Douglas Crockford's videos on Javascript.
Finally, you can turn off filters that you find useless.
you should use it. The fact that it works in one browser doesn't mean it will work in all browsers; some are more lenient than others. for example, having a trailing comma in an array will break in IE but work in FF.
Be aware that sometimes you get a ton of errors, but you remove the first and a dozen go away, like compiling code.
you can do
var rows = [];
for the first error.
Here are the best answers I can give. Perhaps someone can fill in some blanks. It doesn't appear as though any of these relate to jQuery, though.
Also, see this document for some explanations.
Problem at line 5 character 67: type is unnecessary.
<script src="/Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
and goes on with esoteric errors like
I believe that for modern browsers, there's no need for text/javascript when linking to external js files.
Problem at line 41 character 41: Use the array literal notation [].
var rows = new Array();
It is recommended to not call the constructor when creating an Object or Array. I'm honestly not sure why. Anyone?
Problem at line 42 character 30: Too many var statements.
for (var i = 0; i < data.length; i++) {
I suppose you have the i variable declared elsewhere in the same scope. A javascript block does not create scope, so if you have another for loop (for example) that uses i, it is using the same variable. No need to declare it again.
Problem at line 42 character 55: Unexpected use of '++'.
for (var i = 0; i < data.length; i++) {
Not sure about this one, except that if I recall correctly, Crockford doesn't like the ++ and --.
Problem at line 64 character 50: ['PrettyId'] is better written in dot notation.
var item = $("#item_" + data["PrettyId"]);
I believe . notation is preferred because it is shorter and faster (in some browsers anyway). So data.PrettyID instead.
As far as I can tell, nothing here appears to be explicitly wrong. Mostly just best practice advice from JSLint creator's perspective.