Hi, my name is Matt Apperson, some of you might know me from my time as an Engineer with Appcelerator. Back then I used to be the point of contact for the titans program and created or helped create many of the example apps still in use today, including one of the first physics based games using Titanium called TiBall on iOS. I have sense moved on, and now own a development and consulting company specializing in Javascript based tech like Titanium Mobile and NodeJS. So lets dive in!
First off I will just come out and say... I LOVE javascript! I have used it increasingly throughout my career, and come to love it more and more every day. The flexibility of the language is such that you can do almost anything with it. The result is that it lets you build mobile apps like with Titanium, add usability and design to web pages, power back end servers using nodejs, even fly robot helicopters and... the list of what JS can do seems to just never stop growing!... in fact, in the iobridge talk later today that list will grow a little more. :)
But regardless of the power and flexibility of the language, more often then not what we see online is crap code, outdated code, and people trying to shoehorn JS to look and act like other languages, or even entirely new languages. Why is this?
Almost every developer, in some phase of her professional life, was required to use JavaScript . Due to lack of time, or lack of interest, our beloved developer finds out that it is super easy to do something with JavaScript by searching for code snippets as there are so many, what few seem to realize though is that most of these examples and snippets are outdated and junk that use really bad JavaScript code. Thus, most devs never seem to really truly learn true modern JS
A lot of times as part of a search for a how-to of Javascript, people go to this site.... don’t. I’m not saying that w3school does not have some good info, but it is not a reliable place to find information.
Go here instead (talk about it)
Now as the owner of a development shop I constantly talk with clients, and devs who are looking for a job, and again, most think they know JavaScript... what most really know 90% of the time is a framework... now for web developers that framework is jQuery, on mobile and in node that is often coffeescript. Now I don’t truly hate frameworks, but the popularity and ease of use of them cause developer laziness, and they have really no clue how the language itself works. It gets so bad that often, developers get confused and think jQuery and Javascript are interchangeable terms. The result is, most JS code ends up looking like this...
WHY?
For years, JS was ignored because developers did things like animated fireworks and well... need I say more than geo-cities?
Because of it’s legacy, and age, a lot of “example” code exists on the web, and most of it is garbage, or just not useful in the application layer on servers or in mobile apps.
Due to the flexibility of the language, it’s easy to pickup and use, but hard to master. So, if you walk into developing using JS and dont have a good understanding of the language, your application will quickly turn into a pile of unmaintainable… spaghetti code So we are going to try and go over, not tools, tricks and tips for rapid development. Rather we are going to try and learn the core language better to help us write better quality apps.
For the sake of time, we wont be able to cover everything you will need to know to write good javascript. My goal today is to set you on the correct path to learn and use JS and Titanium yourself.
Everything in JavaScript acts like an object, with the only two exceptions being null and unde fined .
A common misconception however is that numbers cannot be used as objects. That is because a flaw in JavaScript's parser tries to parse the dot notation on a number as a floating point literal. But there are a couple of workarounds that can be used to make number literals act as objects too.
So now you have objects and properties... how do you delete them? Well setting the property to undefined or null is a common way to do this, however this only removes the value associated with the property, but not the key . The only way to remove a property from an object is to use the delete operator; This code outputs both bar as undefined and foo as null - only baz was removed and is therefore missing from the output.
JavaScript does not feature a classical inheritance model; instead, it uses a prototypal one. While this is often considered to be one of JavaScript's weaknesses, the prototypal inheritance model is in fact more powerful than the classic model. It is, for example, fairly trivial to build a classic model on top of a prototypal model, while the other way around is a far more difficult task. JavaScript is the only widely used language that features prototypal inheritance, so it can take time to adjust to the differences between the two models. The first major difference is that inheritance in JavaScript uses prototype chains. In this code, the object test will inherit from both Bar.prototype and Foo.prototype; hence, it will have access to the function method that was defined on Foo. It will also have access to the property value of the one Foo instance that is its prototype. It is important to note that new Bar() does not create a new Foo instance, but reuses the one assigned to its prototype; thus, all Bar instances will share the same value property. Als o, Do not use Bar.prototype = Foo , since it will not point to the prototype of Foo, but rather to the function object Foo . So the prototype chain will go over Function.prototype and not Foo.prototype ; therefore, the method `fun` will not be on the prototype chain, thus not accessible from the Bar method.
Now simply using Bar.prototype = Foo.prototype might seem to be the correct way to inherit from another prototype, but will result in both objects sharing the same prototype. Therefore, changes to either object's prototype will affect the prototype of the other as well, which in most cases is not the desired effect. One mis-feature that is often used is to extend Object.prototype or one of the other built in prototypes. This technique is called monkey patching and breaks encapsulation . While used by popular frameworks such as Prototype , ther e is stil l no good reason for cluttering built-in types with additional non-standard functionality. This also makes it much harder to on-board new developers to the project. The only constantly good reason for extending a built-in proto type in my opinion is to back-port the features of newer JavaScript engines; for example, Array.forEach . (talk abo ut why)
Now because in Javascript, everything is an object, lets break out to functions as they are the most glaring place (in my opinion at least) that things are not what you first expect.
Now in JavaScript, there are 2 ways to declare a method or function, that are both displayed here. and both are correct... but what many don’t know is that although they are both correct, they are not the same...
You see, this first example assigns the unnamed and anonymous function to the variable foo . The second example function gets hoisted before the execution of the program starts; thus, it is available everywhere in the scope it was defined in, even if called before the actual definition in the source.
One of JavaScript's most powerful features is the availability of closures . With closures, scopes always keep access to the outer scope, in which they were defined. Since the only scoping that JavaScript has is function scope , all functions, by default, act as closures. Here, Counter returns two closures: the function increment as well as the function get. Both of these functions keep a reference to the scope of Counter and, therefore, always keep access to the count variable that was defined in that scope. Since it is not possible to reference or assign scopes in JavaScript, there is no way of accessing the variable count from the outside. The only way to interact with it is via the two closures.
One often made mistake is to use closures inside of loops, as if they were copying the value of the loop's index variable. This code will not output the numbers 0 through 9 , but will simply print the number 10 ten times. The anonymous function keeps a reference to i . At the time console.log gets called, the for loop has already finished, and the value of i as been set to 10 . In order to get the desired behavior, it is necessary to create a copy of the value of i .
In order to copy the value of the loop's index variable, it is best to use an anonymous wrapper . The anonymous outer function gets called immediately with i as its first argument and will receive a copy of the value of i as its parameter e . The anonymous function that gets passed to setTimeout now has a reference to e , whose value does not get changed by the loop.
Constructors in JavaScript are yet again different from many other languages. Any function call that is preceded by the new keyword acts as a constructor. Inside the constructor - the called function - the value of this refers to a newly created object. The prototype of this new object is set to the prototype of the function object that was invoked as the constructor. If the function that was called has no explicit return statement, then it implicitly returns the value of this - the new object. For example, in the first code sample Foo is called as constructor and sets the prototype of the newly created object to Foo.prototype . In case of an explicit return statement like in our second snippit, the function returns the value specified by that statement, but only if the return value is an Object .
In order to be able to omit the new keyword, the constructor function has to explicitly return a value. Both calls to Bar return the same thing, a newly create object that has a property called method , which is a Closure . It should also be noted that the call new Bar() does not affect the prototype of the returned object. While the prototype will be set on the newly created object, Bar never returns that new object. In this example, there is no functional difference between using and not using the new keyword.
It is often recommended to not use new because forgetting its use may lead to bugs. In order to create a new object, one should rather use a factory and construct a new object inside of that factory. While this code is robust against a missing new keyword and certainly makes the use of private variables easier, it comes with some downsides.
It is often recommended to not use new because forgetting its use may lead to bugs. In order to create a new object, one should rather use a factory and construct a new object inside of that factory. While this code is robust against a missing new keyword and certainly makes the use of private variables easier, it comes with some downsides.
My first gotcha I will point out is setTimeout, the reason being that this is probably one of the most abused JS APIs by titanium developers. I one time worked on an app that had over 600 timeouts, this resulted in a really slow app due to how many contexts were being created. A really common thing I see is people using setTimeout in Titanium apps to align animations and things... this is a bad idea. If a timer is blocked from immediately executing it will be delayed (which will be longer than the desired delay) This means that you might waist a lot of time trying to get an animation to line up, and might get it to work on your device, but your users will most likely not see the correct result.
Now this is not so much a bug as a pet-pieve I have. So many times we see examples like the first code snippet here. ECMA 6 has introduced a new const statement. It lets your variable be read only. No more accidentally overwriting an important.variable. If you have more then one dev working on your app, you don't just WANT to know about this, you NEED to know about it. It will save more debugging time then you know.
OK now this is a fun one... So JavaScript has given us this fantastic little method that can turn a string into a number. Handy!
But until very recently on android, and still today on iOS you get this... and this one might have you stumped for a while. So what causes this?
You see, until the most recent version of the v8, and JScore JS engines, parseInt’s second parameter for radix was dynamic based on the users input. If the string begins with "0x", the radix is 16 (hexadecimal) If the string begins with "0", the radix is 8 (octal). This feature is deprecated If the string begins with any other value, the radix is 10 (decimal) setting this to 10 is the default in newer engines, and most likely what you will need. Again though, iOS and until the most recent builds on android, do not have these newer engines and thus you must set the default value
With CommonJS being used in Titanium now, this is less of an issue then in times past. But still it is a big one. Forgetting to use var can lead to access of the global variable as we can see in the example above. At times this can be useful, but it is also messy and should thus be used sparingly
This would be a much safer way to do this, now if you needed to, you could pass in bar as an argument as well so as to manipulate the global variable without changing it.
You could also do something like this...
Now as we get more advanced with javascript we start doing things with prototypes, but that can cause issues if our app is not designed to work with them... Note in this example we are looping through the food argument and adding each element to an array... the issue here is if food is a prototyped array, then it’s prototyped properties and methods will ALSO be added to the stomach array in this example.
To check whether an object has a property defined on itself and not somewhere on its prototype chain , it is necessary to use the hasOwnProperty method which all objects inherit from Object.prototype. Note: It is not enough to check whether a property is undefined. The property might very well exist, but its value just happens to be set to undefined. hasOwnProperty is the only thing in JavaScript which deals with properties and does not traverse the prototype chain. Only hasOwnProperty will give the correct and expected result; this is essential when iterating over the properties of any object. There is no other way to exclude properties that are not defined on the object itself, but somewhere on its prototype chain. It is recommended that hasOwnProperty is used in every for in loop to avoid error s from extended native prototypes .