Debugging JS Part One -- Sources
Debugging is vital to success in just about any language. Odds are, eventually you'll want to investigate the contents of something or watch the step-by-step execution of your program. I'll show a few of the debugging tools available to the JS programmer in the Chrome console.
There are two main views you'l want to familiarize yourself with for basic debugging: Sources and Console. The former allows you to place breakpoints, watch expressions, and step through code line-by-line like in the Eclipse Java debugging suite. The latter allows you to rapidly test your functions, type safety, and more. Between the two of them and Google, there's virtually no bug in JavaScript you can't solve.
Open the developer tools in Chrome with F12
The first of a three part series.
Part One, "Sources"
Part Two, "Console"
Part Three, "Profiling"
Sources
After opening the developer tools and clicking on sources, you should see something like this:
There are some components of this UI that will be skipped for this basic overview. We'll cover the watch expressions, call stack, scope variables, breakpoints, and the symbolic buttons on the upper right, as well as the source panel itself.
Clicking on the small button in the upper left (the one that looks like a "play button" triangle) should show something like this:
Here, you can browse the document hierarchy. A side benefit of this is that it only has access to the loaded source files, so if you want to check if a .js file is even being loaded, this is a good place to check quickly (or, of course, the html page in question).
Opening a file, we can view it. Next, click the Play/Pause button; the one in the upper left of the right-hand pane of this view, that's highlighted in blue below. This will cause the script to pause (if you have an update loop, as in this example, it is virtually guaranteed to always stop in code that is "close to" the browser-level code. In this case, the code we arrive at after pausing is the function that's used as a callback with the requestAnimationFrame function.
From left to right, the buttons in the cluster with the play/pause button, are the step over, step into, step out, deactivate breakpoints, and pause on uncaught exceptions buttons. You can also use the F-keys to step through the code. Note also the call stack: right now, we're in engine.frame. This can be extremely useful information, knowing where we came from. The scope variables section shows all of the variables visible in the current scope. Breakpoints is empty because we didn't pause on a breakpoint; we just told the code to stop.
Let's create some breakpoints. We can do this by clicking on the line number next to a line of code:
Here, we have two breakpoints. Inside the Breakpoints section, we can see both are "checked". If we uncheck one, it will temporarily disable it without removing it entirely. You can click again on the line number or right click the breakpoint in the breakpoints list to remove it entirely. It works pretty much the same way as it does in a proper IDE.
Here's adding a couple of variables to watch in the watch expressions panel:
Note that the difference between a watch expression and a scope variable is that you can make a watch expression be anything. This means you can "tunnel" several layers deep, like watching foo.bar.goo.gah.boof.x, or evaluating a function, like watching the return value of foo(x,y). Note that, if you have side effects of functions, odd behavior may occur, so use this technique with some amount of caution!
Finally, if you click the "show/hide drawer" button (highlighted in blue below), you can have your console and search bars show up inside the sources pane. If you have the screen real estate for it, I recommend doing debugging in this way.
Next up: We look at the Console functionality, learn how to write code on the fly and insert it into our application, and use the console to test code!
Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts
Monday, March 3, 2014
Saturday, February 22, 2014
Falsy Values in Javascript
Javascript has a lot of truthy and falsy values. It can be really quite confusing, because this means your code will fail conditionals it shouldn't, and pass conditionals it shouldn't. It takes a little bit of discipline to ensure your code is always returning the right type. Here are some of my notes on the matter.
Truthy values in Javascript:
True
true
Empty object
{}
Empty list
[]
Non-empty string
"Hello, world"
Non-zero numbers
42
... (there are others, mostly variants on objects)
There are only six falsy values in Javascript, however:
False
false
Null object
null
Undefined
undefined
NaN
NaN
Zero
0
Empty string
""
There are some very odd things about these lists - the numbers and boolean keywords aside. Like, why are empty strings falsy, but empty arrays aren't? What's a string if not an array? Why aren't empty arrays and empty objects falsy? Why do we have undefined AND null?
In Javascript, there are a lot of ways to introduce bugs, and unfortunately, simple boolean algebra is one of them. Each of these values is truthy or falsy for a reason, but more importantly, they have vastly different use cases.
Empty objects and arrays are truthy because they are both objects. Objects instantiated with the array initializer will have a length attribute and "methods" for pushing, popping, reversing, and so on (because their prototype is the built in Array object). But, the Array object inherits from the base Object, so empty arrays are objects, and all objects in Javascript are truthy - they represent the existence of "something".
Empty strings, however, are an exception to this rule, as part of a conscious design choice. The exact reasoning is beyond my knowledge, but it makes sense to view empty strings as an exception to the rule that an object implies the existence of meaningful information. Not sure it's a decision I'd make, though.
A lot of problems happen because of undefined. Undefined is NOT null, and there is a reason for having both values. It is very important that programmers do not misuse these values, because it will quickly become impossible to determine where bugs are coming from and what the nature of them is.
When a name's value is null, that means it has no defined value. It is not an empty object, zero, the empty list, an empty string - it is undefined, unknown to Javascript. It should be returned when a function is asked for an object and no proper object has been found, or when an identifier needs to be declared but no object for it is available yet (like declaring "class members").
When a name is undefined, that means the name itself, the label, has never been defined in the current scope. It's not that the identifier doesn't have a value, it's that the identifier doesn't exist. There's a difference between a.x = null when x is defined, but not initialized, and a.x when, nowhere inside of a, is there anything with the name x.
In general, you should never, ever return undefined from a function. It's a language feature telling you that there is something fundamentally wrong going on, not a falsy value to let some other function deal with. Null, however, should be returned frequently; every time an object should be returned and nothing could be found, you should return null, not undefined.
Why would you return undefined accidentally? Excellent question. Undefined is the default return type for functions! If you have a void function, it's actually going to return undefined. This means if you don't make sure that every code path contains an explicit return, your function will sometimes return undefined, and sometimes not, which absolutely violates the rule about returning null if no valid answer could be found!
Unfortunately, some (many) of the built-in functions are not insulated against this. Array.pop() returns undefined if the array is empty, rather than null, for example. There's really no solution besides buckling up and learning how to be extremely careful.
NAN is confusing too, not because it's falsy, but because it doesn't equal itself. This makes perfect sense; NaN means "Not a Number", and it means that somewhere, you did a bad in your arithmetic, and wound up with something Javascript can't use. Since it's impossible to know that one non-number equals another, NaN === NaN returns false. To get around this, use the isNaN() function!
A final note: remember to use ===, not ==! This is an example of why:
var arr = [];
(arr == false) //true
(arr === false) //false
!!arr //true
This is because it evaluated arr and false to strings in the "==" comparison, and the empty string is false! BE CAREFUL.
Next post will be about why arithmetic in Javascript is terrifying.
Truthy values in Javascript:
True
true
Empty object
{}
Empty list
[]
Non-empty string
"Hello, world"
Non-zero numbers
42
... (there are others, mostly variants on objects)
There are only six falsy values in Javascript, however:
False
false
Null object
null
Undefined
undefined
NaN
NaN
Zero
0
Empty string
""
There are some very odd things about these lists - the numbers and boolean keywords aside. Like, why are empty strings falsy, but empty arrays aren't? What's a string if not an array? Why aren't empty arrays and empty objects falsy? Why do we have undefined AND null?
In Javascript, there are a lot of ways to introduce bugs, and unfortunately, simple boolean algebra is one of them. Each of these values is truthy or falsy for a reason, but more importantly, they have vastly different use cases.
Empty objects and arrays are truthy because they are both objects. Objects instantiated with the array initializer will have a length attribute and "methods" for pushing, popping, reversing, and so on (because their prototype is the built in Array object). But, the Array object inherits from the base Object, so empty arrays are objects, and all objects in Javascript are truthy - they represent the existence of "something".
Empty strings, however, are an exception to this rule, as part of a conscious design choice. The exact reasoning is beyond my knowledge, but it makes sense to view empty strings as an exception to the rule that an object implies the existence of meaningful information. Not sure it's a decision I'd make, though.
A lot of problems happen because of undefined. Undefined is NOT null, and there is a reason for having both values. It is very important that programmers do not misuse these values, because it will quickly become impossible to determine where bugs are coming from and what the nature of them is.
When a name's value is null, that means it has no defined value. It is not an empty object, zero, the empty list, an empty string - it is undefined, unknown to Javascript. It should be returned when a function is asked for an object and no proper object has been found, or when an identifier needs to be declared but no object for it is available yet (like declaring "class members").
When a name is undefined, that means the name itself, the label, has never been defined in the current scope. It's not that the identifier doesn't have a value, it's that the identifier doesn't exist. There's a difference between a.x = null when x is defined, but not initialized, and a.x when, nowhere inside of a, is there anything with the name x.
In general, you should never, ever return undefined from a function. It's a language feature telling you that there is something fundamentally wrong going on, not a falsy value to let some other function deal with. Null, however, should be returned frequently; every time an object should be returned and nothing could be found, you should return null, not undefined.
Why would you return undefined accidentally? Excellent question. Undefined is the default return type for functions! If you have a void function, it's actually going to return undefined. This means if you don't make sure that every code path contains an explicit return, your function will sometimes return undefined, and sometimes not, which absolutely violates the rule about returning null if no valid answer could be found!
Unfortunately, some (many) of the built-in functions are not insulated against this. Array.pop() returns undefined if the array is empty, rather than null, for example. There's really no solution besides buckling up and learning how to be extremely careful.
NAN is confusing too, not because it's falsy, but because it doesn't equal itself. This makes perfect sense; NaN means "Not a Number", and it means that somewhere, you did a bad in your arithmetic, and wound up with something Javascript can't use. Since it's impossible to know that one non-number equals another, NaN === NaN returns false. To get around this, use the isNaN() function!
A final note: remember to use ===, not ==! This is an example of why:
var arr = [];
(arr == false) //true
(arr === false) //false
!!arr //true
This is because it evaluated arr and false to strings in the "==" comparison, and the empty string is false! BE CAREFUL.
Next post will be about why arithmetic in Javascript is terrifying.
Thursday, February 20, 2014
Lions and Tigers and Javascript (oh my!)
Javascript is awful.
There, I said it. But we're kind of stuck with JS, and it's a good language to know, and it is pretty powerful in a lot of ways. So it's a worthwhile language, but there are a lot of things to watch out for. Since we're doing a project in Javascript, I thought I'd do a post about some of my favorite, and least favorite, things about the language.
The main thing about Javascript to keep in mind is that it was designed for small "script-y" tasks. It was never intended for software development on any kind of major scope, so the core features of the language are built around the novelty of making a website be able to do something, and not to in any way aid the comprehension of the programmer, or the design of large, modular programs. It's a language built on making "clicky button do thing", not software.
Here are some of the things about the language that pop out at me as amazing, terrible, or bizarre (I'll admit, they're mostly gotchas and problems, but there are some wicked cool things you can do with some of these double-edged features):
Object-Oriented to an extreme
This is actually a nice feature. Everything in JS is one of four types: Booleans, Numbers, Strings, and Arrays/Objects. Functions are objects. Arrays and objects are identical, but have different (but interchangable) access patterns. Numbers, booleans, and strings are all actually objects as well, interestingly - they can all be instantiated with the "new" keyword. Once you come to grips with how this works, it can be an incredibly powerful feature, allowing the elimination of tons of work compared to implementing a feature in, say, Java. It's not very secure or powerful in a low level, but it does simplify a lot of things.
Dynamic Types
This is a double edged sword, but I consider it mostly a bad thing. Being able to change the type of an object on the fly without any kind of warning can cause major bugs, like changing "x" from a Number to a String, then performing concatenation instead of addition and wondering why you get "52" instead of "7" when you output x.
Global Scope
Everything in Javascript is global, unless you specify them as local with the "var" keyword. Even then, you can still go through the top-level window element, then follow the crumb trail till you find the appropriate object. Absolutely everything is visible to absolutely everything else, as long as you know where to look. This makes modularity require careful planning, and security laughably nonexistant in JS.
Silent runtime failures
What's worse than a compilation error? A runtime error. What's worse than a runtime error? one that can happen completely silently. Javascript will (depending on the browser and the problem) sometimes spit out errors and then just keep on trucking. Obviously, this can be a major headache. Remember to keep the console open to look for errors when testing, or else silent failures can completely ruin your day.
Javascript supports functional paradigms
That's right! Because functions are objects, you can pass functions around, make lambda expressions, and more. You can make a function foo(function) which takes a function as a parameter, then call it like this "foo(bar)" and have, inside of foo: "function();", which will call "bar". You can even do "foo(function(){ //some code//})" which is a lambda in all but name. BUT before you run off to go write something big using lambdas, you might want to know that...
...Javascript does not have tail call optimization
Why support functional programming and not have tail call optimization? Who knows. Maybe the functional programming support wasn't even intentional, or maybe the tail call optimization interfered with backwards compatibility or the basic language features - the crux of the biscuit is that it doesn't have it, so before you freeze your web browser, don't write anything recursively if you can at all avoid it.
The functional stuff is still useful
Callbacks are contested as bad style by some, but they jive with javascript just fine because of the first-class function business. You can create powerful event-driven systems with callbacks in Javascript with only a few lines of code.
Eval
Just about the most dangerous command in javascript, eval("x") executes x as if it were javascript code. Besides the obvious security loopholes that can arise if you don't scrub your input properly, it's slow, obscures meaning, and is almost never actually necessary.
All Numbers are 64-bit Doubles
This means both that you pay a serious performance price for having them, and that you have absolutely no choice about integer versus floating point numbers, except to use Math.floor()
Bitwise operators are slow
In a bizarre twist, bitwise operators are incredibly inefficient. Don't use bitpacking or bit flags unless you really need to. As a general rule of thumb, trying to be super-efficient in Javascript by using the same techniques you might in C++ or Java is a good way to make things worse.
Functions can return anything, or nothing.
Since everything is an object, you should be careful about what kind of objects you get from functions, and what kind you return. You can have a function that returns a number in some places, a string in others, a complex data structure in one spot, and nothing at all otherwise.
(Global) Functions and variables can be overwritten on-the-fly.
If you redefine a system function, hijinks ensue, and it's perfectly legal. Be careful that the name you're defining isn't already in use! This applies to any variable currently in-scope. Global (top-level) names are always visible. If you overwrite the top-level Math library to say, "foo", you will no longer be able to access any of the Math functions! Make sure to use the "var" keyword to define a scope variable.
'==' and '!=' do Black Magic
They actually convert the type of the object on the left to the type on the right silently before comparing, which can have unexpected results. Instead, use the '===' and '!==' comparisons to test value AND type.
"new" does not work like in Java
This is good and bad. Prototypal inheritance is powerful, but counterintuitive to Java programmers. The notion is that you can make a "new foo" where "foo" is an object, and the new foo will have all of the properties of foo. You can fake a class system by making all objects intended for inheritance to start with a capital letter. You can also make a chain of classes by inheriting, modifying, inheriting, modifying, etc. This can be dangerous
Objects can have attributes (members) injected at any time
This is pretty cool, in my opinion, but it can be hazardous if used carelessly. You can make a new Foo called x, and then go ahead and say that x.y = "bar", and this new Foo object will now have a field, called y, containing the value "foo". Does this mean that objects of the same class can have radically different contents? ...yes, it does. Use with extreme caution.
This injection allows built-in libraries to be modified
If you decide the Math library needs linear algebra functions, you can just stick them in. Go ahead and say Math.matrixMult = function() { //some code //} and you're off to the races. This is really cool and also really dangerous if used improperly.
classes, functions, objects, methods, and arrays are the same thing
This has already been stated, but let me emphasise: you can make an array, give it some methods, start instantiating new ones with 'new', and call functions that are members ("methods") with the '.' operator. You can even use the '[]' and '.' operators semi-interchangeably. For instance, you can fill an array with a bunch of callback functions using an array syntax, then call "foo[0]()". Weird behavior can occur: strings default to using '[]' to reference a letter. Also, using the '.' syntax versus '[]' breaks down when using variables that have a Number value to reference: if foo = 1, f.foo might be different from f[foo], because f[foo] is interpreted as f[1], while f.foo refers to a field named the object foo. There are other bizarre behaviors. You can absolutely screw up if you're not careful, but this can still be amazingly powerful.
Javascript is not ECMAScript
But, when referring to javascript, most people mean ECMAScript. It is the language specification upon which Javascript is built, but javascript is built by Mozilla/Oracle, and supports features that other browsers don't. So while Javascript has list comprehensions and a boatload of other neat features, Chrome, Safari, and other browsers won't be able to interpret the code.
All functions are variadic
You can at any time pass any number of things to a function.
Careful with parameters
Because there are no type specifiers in Javascript, if you have a function that takes parameters of differing types - especially if there are a lot - they might get the order wrong, and your program will throw errors, possibly silently. Make sure you document all function headers with a type constraint so that users can see what is supposed to be passed, and try to not make a function like "function foo(num1, num2, str, num3, list, num3, str2){...}" because that will cause problems.
Semicolons are optional
foo = 1; is equivalent to foo = 1
Single and double quotes are identical
A char is just a string of size 1. It's strings all the way down.
NaN isn't NaN
Because NaN is a special value meaning not a number, no two "not numbers" can be guaranteed to be equal. Use isNaN(), not == NaN, to test for NaN-ness! This is a very good thing.
Null is an object
I wasn't kidding when I said everything is an object. However, you can't put methods and variables inside null, or change it's value. So at least there's that.
"this" refers to the object calling a function, not the object containing an object.
In other words, if we have objects A and B, and A.x() passes A.y() to B.z(), like so: B.z(this.y), when we call y, we get an error. why? because inside of B.z, it evaluates it literally; "this.y()". Since B does not contain a function y(), it fails. The standard workaround is to create a local var called "that". Example: "var that = this; B.z(that.y);". This will work, and is considered a standard practice amongst JS programmers.
0, false, '', null, undefined, and NaN all evaluate to false inside of boolean operations
That's right, all of those are "falsy". This can be bad or good, depending on your opinion, but it can lead to unexpected behavior.
This is far from a comprehensive list of all of the problems - err, I mean, the features, of Javascript. The basic tl;dr is this: it's easy to write horrible, awful, ugly javascript code that won't do what you want it to. Writing good Javascript code is entirely possible, however. I really recommend the book "Javascript: The Good Parts". Once you get past the surprising differences between it and other languages, Javascript can be an excellent language. It might just take a little while to get to that point.
There, I said it. But we're kind of stuck with JS, and it's a good language to know, and it is pretty powerful in a lot of ways. So it's a worthwhile language, but there are a lot of things to watch out for. Since we're doing a project in Javascript, I thought I'd do a post about some of my favorite, and least favorite, things about the language.
The main thing about Javascript to keep in mind is that it was designed for small "script-y" tasks. It was never intended for software development on any kind of major scope, so the core features of the language are built around the novelty of making a website be able to do something, and not to in any way aid the comprehension of the programmer, or the design of large, modular programs. It's a language built on making "clicky button do thing", not software.
Here are some of the things about the language that pop out at me as amazing, terrible, or bizarre (I'll admit, they're mostly gotchas and problems, but there are some wicked cool things you can do with some of these double-edged features):
Object-Oriented to an extreme
This is actually a nice feature. Everything in JS is one of four types: Booleans, Numbers, Strings, and Arrays/Objects. Functions are objects. Arrays and objects are identical, but have different (but interchangable) access patterns. Numbers, booleans, and strings are all actually objects as well, interestingly - they can all be instantiated with the "new" keyword. Once you come to grips with how this works, it can be an incredibly powerful feature, allowing the elimination of tons of work compared to implementing a feature in, say, Java. It's not very secure or powerful in a low level, but it does simplify a lot of things.
Dynamic Types
This is a double edged sword, but I consider it mostly a bad thing. Being able to change the type of an object on the fly without any kind of warning can cause major bugs, like changing "x" from a Number to a String, then performing concatenation instead of addition and wondering why you get "52" instead of "7" when you output x.
Global Scope
Everything in Javascript is global, unless you specify them as local with the "var" keyword. Even then, you can still go through the top-level window element, then follow the crumb trail till you find the appropriate object. Absolutely everything is visible to absolutely everything else, as long as you know where to look. This makes modularity require careful planning, and security laughably nonexistant in JS.
Silent runtime failures
What's worse than a compilation error? A runtime error. What's worse than a runtime error? one that can happen completely silently. Javascript will (depending on the browser and the problem) sometimes spit out errors and then just keep on trucking. Obviously, this can be a major headache. Remember to keep the console open to look for errors when testing, or else silent failures can completely ruin your day.
Javascript supports functional paradigms
That's right! Because functions are objects, you can pass functions around, make lambda expressions, and more. You can make a function foo(function) which takes a function as a parameter, then call it like this "foo(bar)" and have, inside of foo: "function();", which will call "bar". You can even do "foo(function(){ //some code//})" which is a lambda in all but name. BUT before you run off to go write something big using lambdas, you might want to know that...
...Javascript does not have tail call optimization
Why support functional programming and not have tail call optimization? Who knows. Maybe the functional programming support wasn't even intentional, or maybe the tail call optimization interfered with backwards compatibility or the basic language features - the crux of the biscuit is that it doesn't have it, so before you freeze your web browser, don't write anything recursively if you can at all avoid it.
The functional stuff is still useful
Callbacks are contested as bad style by some, but they jive with javascript just fine because of the first-class function business. You can create powerful event-driven systems with callbacks in Javascript with only a few lines of code.
Eval
Just about the most dangerous command in javascript, eval("x") executes x as if it were javascript code. Besides the obvious security loopholes that can arise if you don't scrub your input properly, it's slow, obscures meaning, and is almost never actually necessary.
All Numbers are 64-bit Doubles
This means both that you pay a serious performance price for having them, and that you have absolutely no choice about integer versus floating point numbers, except to use Math.floor()
Bitwise operators are slow
In a bizarre twist, bitwise operators are incredibly inefficient. Don't use bitpacking or bit flags unless you really need to. As a general rule of thumb, trying to be super-efficient in Javascript by using the same techniques you might in C++ or Java is a good way to make things worse.
Functions can return anything, or nothing.
Since everything is an object, you should be careful about what kind of objects you get from functions, and what kind you return. You can have a function that returns a number in some places, a string in others, a complex data structure in one spot, and nothing at all otherwise.
(Global) Functions and variables can be overwritten on-the-fly.
If you redefine a system function, hijinks ensue, and it's perfectly legal. Be careful that the name you're defining isn't already in use! This applies to any variable currently in-scope. Global (top-level) names are always visible. If you overwrite the top-level Math library to say, "foo", you will no longer be able to access any of the Math functions! Make sure to use the "var" keyword to define a scope variable.
'==' and '!=' do Black Magic
They actually convert the type of the object on the left to the type on the right silently before comparing, which can have unexpected results. Instead, use the '===' and '!==' comparisons to test value AND type.
"new" does not work like in Java
This is good and bad. Prototypal inheritance is powerful, but counterintuitive to Java programmers. The notion is that you can make a "new foo" where "foo" is an object, and the new foo will have all of the properties of foo. You can fake a class system by making all objects intended for inheritance to start with a capital letter. You can also make a chain of classes by inheriting, modifying, inheriting, modifying, etc. This can be dangerous
Objects can have attributes (members) injected at any time
This is pretty cool, in my opinion, but it can be hazardous if used carelessly. You can make a new Foo called x, and then go ahead and say that x.y = "bar", and this new Foo object will now have a field, called y, containing the value "foo". Does this mean that objects of the same class can have radically different contents? ...yes, it does. Use with extreme caution.
This injection allows built-in libraries to be modified
If you decide the Math library needs linear algebra functions, you can just stick them in. Go ahead and say Math.matrixMult = function() { //some code //} and you're off to the races. This is really cool and also really dangerous if used improperly.
classes, functions, objects, methods, and arrays are the same thing
This has already been stated, but let me emphasise: you can make an array, give it some methods, start instantiating new ones with 'new', and call functions that are members ("methods") with the '.' operator. You can even use the '[]' and '.' operators semi-interchangeably. For instance, you can fill an array with a bunch of callback functions using an array syntax, then call "foo[0]()". Weird behavior can occur: strings default to using '[]' to reference a letter. Also, using the '.' syntax versus '[]' breaks down when using variables that have a Number value to reference: if foo = 1, f.foo might be different from f[foo], because f[foo] is interpreted as f[1], while f.foo refers to a field named the object foo. There are other bizarre behaviors. You can absolutely screw up if you're not careful, but this can still be amazingly powerful.
Javascript is not ECMAScript
But, when referring to javascript, most people mean ECMAScript. It is the language specification upon which Javascript is built, but javascript is built by Mozilla/Oracle, and supports features that other browsers don't. So while Javascript has list comprehensions and a boatload of other neat features, Chrome, Safari, and other browsers won't be able to interpret the code.
All functions are variadic
You can at any time pass any number of things to a function.
Careful with parameters
Because there are no type specifiers in Javascript, if you have a function that takes parameters of differing types - especially if there are a lot - they might get the order wrong, and your program will throw errors, possibly silently. Make sure you document all function headers with a type constraint so that users can see what is supposed to be passed, and try to not make a function like "function foo(num1, num2, str, num3, list, num3, str2){...}" because that will cause problems.
Semicolons are optional
foo = 1; is equivalent to foo = 1
Single and double quotes are identical
A char is just a string of size 1. It's strings all the way down.
NaN isn't NaN
Because NaN is a special value meaning not a number, no two "not numbers" can be guaranteed to be equal. Use isNaN(), not == NaN, to test for NaN-ness! This is a very good thing.
Null is an object
I wasn't kidding when I said everything is an object. However, you can't put methods and variables inside null, or change it's value. So at least there's that.
"this" refers to the object calling a function, not the object containing an object.
In other words, if we have objects A and B, and A.x() passes A.y() to B.z(), like so: B.z(this.y), when we call y, we get an error. why? because inside of B.z, it evaluates it literally; "this.y()". Since B does not contain a function y(), it fails. The standard workaround is to create a local var called "that". Example: "var that = this; B.z(that.y);". This will work, and is considered a standard practice amongst JS programmers.
0, false, '', null, undefined, and NaN all evaluate to false inside of boolean operations
That's right, all of those are "falsy". This can be bad or good, depending on your opinion, but it can lead to unexpected behavior.
This is far from a comprehensive list of all of the problems - err, I mean, the features, of Javascript. The basic tl;dr is this: it's easy to write horrible, awful, ugly javascript code that won't do what you want it to. Writing good Javascript code is entirely possible, however. I really recommend the book "Javascript: The Good Parts". Once you get past the surprising differences between it and other languages, Javascript can be an excellent language. It might just take a little while to get to that point.
Effective Java
Effective C++ was on the recommended reading for the class, and I recently bought it to give it a chance. I haven't read enough of it to comment (and honestly, I'm going to be learning the language as I go) but I have read Effective Java cover-to-cover and I highly recommend it. I suggest you get a copy, read it, and then keep it as a reference book.
Every serious Java programmer ought to have a copy. Even if you're not that serious, it wouldn't hurt to look.
Every serious Java programmer ought to have a copy. Even if you're not that serious, it wouldn't hurt to look.
Subscribe to:
Posts (Atom)
.png)
.png)
.png)
.png)
.png)
.png)