You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2014-2-17-javascript-gotchas.md
+32-29Lines changed: 32 additions & 29 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,9 +7,9 @@ tags:
7
7
8
8
# JavaScript gotchas
9
9
10
-
JavaScript is a language that many developers are familiar with but lack a deep understanding. The language lends itself to new programmersbecause its simple syntax. Many of the core fundamentals can be avoided provided that the application being built is sufficiently simple. The goal of this lab is to give you a better understanding of some core concepts and things to look for with JavaScript.
10
+
JavaScript is a language that many developers are familiar with but lack a deep understanding. The language lends itself to new programmers, in part, because of its simple syntax. Many fundamental concepts and features of the language can be overlooked with a simple procedural approach. The goal of this lab is to give you a better understanding of some core concepts and important language features to understand about JavaScript.
11
11
12
-
## What's```this```?
12
+
## What is```this```?
13
13
14
14
Have a look at this snippet and pay special attention to the use of the keyword ```this```.
15
15
@@ -31,43 +31,46 @@ var obj = {
31
31
obj.doSomething();
32
32
{% endhighlight %}
33
33
34
-
Those unfamiliar with how ```this``` is handled may think the call to ```obj.doSomething```might think the output of running the above snippet is this:
34
+
Those unfamiliar with how ```this``` is handled may think the call to ```obj.doSomething```would output the following (assuming the snippet above is saved in a file named `this.js`:
35
35
36
-
```
36
+
{% highlight bash %}
37
+
> node this.js
37
38
Name: bob
38
39
Name: bob
39
-
```
40
+
{% endhighlight %}
41
+
42
+
This is a very common mistake. What is actually output is this:
40
43
41
-
What's actually output is this:
42
44
43
-
```
45
+
{% highlight bash %}
46
+
> node this.js
44
47
Name: bob
45
48
Name: undefined
46
-
```
49
+
{% endhighlight %}
47
50
48
-
Here's another example and then we'll explain what's going on.
51
+
Here is another example and then we will explain what is going on.
49
52
50
53
{% highlight javascript %}
51
54
function Adder (a) {
52
55
this.a = a;
53
56
};
54
-
57
+
55
58
Adder.prototype.addAsync = function (b) {
56
59
setTimeout(function () {
57
60
console.log(this.a + b);
58
61
}, 10);
59
62
};
60
-
63
+
61
64
var r = new Adder(5);
62
65
r.addAsync(10);
63
66
64
67
{% endhighlight %}
65
68
66
-
This example is supposed to add two numbers together after 10 milliseconds. What's the output of this example? Some may think it would print 15, the result of 5 + 10. The correct answer is ```NaN```. Why? The answer lies in the value of ```this```.
69
+
This example is supposed to add two numbers together after 10 milliseconds. What is the output of this example? Some may think it would print 15, the result of 5 + 10. The correct answer is ```NaN```. Why? The answer lies in the value of ```this```.
67
70
68
-
If there's anything you'll walk away from after this lab I hope you'll no longer write bugs that involve ```this```.
71
+
If there is anything you will walk away from after this lab I hope you no longer write bugs that involve ```this```.
69
72
70
-
The value of ```this``` is the object that a function is defined on. Inner functions or function calls that aren't a part of the object will have the default object set to ```this```. The default object in browsers is ```window``` and in Node.js is ```global```.
73
+
The value of ```this``` is the object that a function is defined on. Inner functions or function calls that are not a part of the object will have the default object set to ```this```. The default object in browsers is ```window``` and in Node.js is ```global```.
71
74
72
75
{% highlight javascript %}
73
76
var obj = { a: "Example" };
@@ -84,15 +87,15 @@ printer() // => undefined
84
87
obj.p() // => Example
85
88
{% endhighlight %}
86
89
87
-
Notice how the value of the call to ```printer``` that wasn't attached to an object was ```undefined```. Once we set the property p to the printer function and invoke it you'll see that this now refers to the object defined. When an object is created from a constructor function using the new keyword, a brand new object is set to ```this```. For example:
90
+
Notice how the value of the call to ```printer``` that was not attached to an object was ```undefined```. Once we set the property p to the printer function and invoke it you will see that this now refers to the object defined. When an object is created from a constructor function using the new keyword, a brand new object is set to ```this```. For example:
88
91
89
92
{% highlight javascript %}
90
93
var ctor = function (a) {
91
94
this.a = a;
92
95
};
93
96
94
97
ctor.prototype.print = function () {
95
-
console.log(this.a);
98
+
console.log(this.a);
96
99
};
97
100
98
101
var o1 = new ctor('test1');
@@ -102,7 +105,7 @@ var o2 = new ctor('test2');
102
105
o2.print(); // => test2
103
106
{% endhighlight %}
104
107
105
-
So, you've seen the default behavior of how JavaScript handles the ```this``` keyword. The value of ```this``` can be controlled in a function call via a few methods available on Function.prototype ```apply```, ```call```, and ```bind```. Each of these methods allow you to modify the value of this when the function is called. The first two options (apply and call) invoke the function immediately, whereas the third (bind) provides a new function with ```this``` bound. The value of ```this``` is the first argument to each of these methods. Here's an example:
108
+
So, you have seen the default behavior of how JavaScript handles the ```this``` keyword. The value of ```this``` can be controlled in a function call via a few methods available on Function.prototype ```apply```, ```call```, and ```bind```. Each of these methods allow you to modify the value of this when the function is called. The first two options (apply and call) invoke the function immediately, whereas the third (bind) provides a new function with ```this``` bound. The value of ```this``` is the first argument to each of these methods. Here is an example:
The difference between ```apply``` and ```call``` is that apply allows you to invoke the function with the arguments as an array; ```call`` requires the parameters to be listed explicitly.
125
+
The difference between ```apply``` and ```call``` is that `apply` allows you to invoke the function with the arguments as an array; ```call``` requires the parameters to be listed explicitly.
123
126
124
127
125
128
# Var
126
129
127
-
The keyword ```var``` is used to define variables. Unfortunately, JavaScript does not require the use of this keyword when defining variables. Forgetting to leave off the var keyword can pollute the global object with unnecessary properties. It can also create innocent looking bugs. Have a look at the following example, What's the output?
130
+
The keyword ```var``` is used to define variables. Unfortunately, JavaScript does not require the use of this keyword when defining variables. Forgetting to leave off the var keyword can pollute the global object with unnecessary properties. It can also create innocent looking bugs. Have a look at the following example, What is the output?
128
131
129
132
{% highlight javascript %}
130
133
function doStuff() {
131
134
for (i = 0; i < 5; i++) {
132
135
console.log(i);
133
136
}
134
137
}
135
-
138
+
136
139
function example() {
137
140
for (i = 0; i < 5; i++) {
138
141
doStuff();
139
142
}
140
143
}
141
-
144
+
142
145
example();
143
146
{% endhighlight %}
144
147
145
-
At first glance it looks like it would output the numbers 0 to 5 - 5 times. Sadly, it doesn't; instead it outputs the number 0 - 5 just once! What's the problem? It's the fact that this example omits the use of the var keyword. To fix this we must declare the loop control variables within the function. Fixing the above example looks like this (note the use of var):
148
+
At first glance it looks like it would output the numbers 0 to 5 - 5 times. Sadly, it does not; instead it outputs the number 0 - 5 just once! What is the problem? It is the fact that this example omits the use of the var keyword. To fix this we must declare the loop control variables within the function. Fixing the above example looks like this (note the use of var):
146
149
147
150
{% highlight javascript %}
148
151
function doStuff() {
@@ -151,22 +154,22 @@ function doStuff() {
151
154
console.log(i);
152
155
}
153
156
}
154
-
157
+
155
158
function example() {
156
159
for (var i = 0; i < 5; i++) {
157
160
doStuff();
158
161
}
159
162
}
160
-
163
+
161
164
example();
162
165
{% endhighlight %}
163
166
164
-
Using JavaScripts strict mode will prevent you from defining properties on the global object. There are other advantages to using strict mode, but this one is my favorite. Strict mode is applied within an execution context instead of over the entire JavaScript VM. To enable strict mode simple include the string ```"use strict";``` at the top of an execution context. Here's an example of using strict mode just for a single function.
167
+
Using JavaScripts strict mode will prevent you from defining properties on the global object. There are other advantages to using strict mode, but this one is my favorite. Strict mode is applied within an execution context instead of over the entire JavaScript VM. To enable strict mode simple include the string ```"use strict";``` at the top of an execution context. Here is an example of using strict mode just for a single function.
165
168
166
169
{% highlight javascript %}
167
170
var strictFunction = function () {
168
171
"use strict";
169
-
x = 1; // => Throws error because of strict mode!
172
+
x = 1; // => Throws error because of strict mode!
170
173
};
171
174
172
175
var notSoStrictFunction = function () {
@@ -179,9 +182,9 @@ var notSoStrictFunction = function () {
Locate the public ip address for the virtual machine you just created. You can ssh into it with the following command. Assuming your .pem file is in the same directory as you're running the command.
16
16
17
-
```
17
+
{% highlight bash %}
18
18
ssh -i node.pem ubuntu@54.213.246.161
19
-
```
19
+
{% endhighlight %}
20
20
21
21
## Installing Node
22
22
23
23
Node has great instructions on how to install from apt-get [here](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager). The important part is here:
24
24
25
-
```
25
+
{% highlight bash %}
26
26
sudo apt-get update
27
27
sudo apt-get install -y python-software-properties python g++ make
28
28
sudo add-apt-repository ppa:chris-lea/node.js
29
29
sudo apt-get update
30
30
sudo apt-get install nodejs
31
31
32
32
sudo ln -s /usr/bin/node /usr/bin/nodejs
33
-
```
33
+
{% endhighlight %}
34
34
35
35
This sets up a new aptitude repository where the most recent stable version of node should be available. At the time of this writing the official ubuntu repositories had an out-dated version of node.
36
36
37
37
Verify your installation
38
38
39
-
```
39
+
{% highlight bash %}
40
40
node -v
41
-
```
41
+
{% endhighlight %}
42
42
43
43
# Setting up a node process
44
44
45
45
Let's start by creating a simple node web application using express. From your home directory:
46
46
47
-
```
47
+
{% highlight bash %}
48
48
> mkdir node_app
49
49
> cd node_app
50
50
> npm init
51
-
```
51
+
{% endhighlight%}
52
52
53
53
Run through the prompts to initialize your package.json file.
54
54
55
-
```
55
+
{% highlight bash %}
56
56
npm install express --save
57
-
```
57
+
{% endhighlight %}
58
58
59
59
This will install express and update your package.json file.
60
60
@@ -81,20 +81,21 @@ console.log('Server listening on port ' + app.get('port'));
81
81
82
82
Let's start the process and run a quick curl request. Notice that the port specified is 3000.
83
83
84
-
```
84
+
{% highlight bash %}
85
85
node server.js&
86
86
curl -I localhost:3000
87
-
```
87
+
{% endhighlight %}
88
88
89
89
Now kill the process and let's continue.
90
90
91
-
```
91
+
{% highlight bash %}
92
92
killall node
93
-
```
93
+
{% endhighlight %}
94
94
95
95
## Cluster
96
96
97
-
We'll start scaling Node using a built in technique. The cluster module that's part of the core node library is an option. In the current version of node (v0.10.*) the cluster module doesn't appropriately route traffic to child processes. Node leaves the routing of incoming connections to the operating system. Unix based operating systems do a poor job of distributing new connections amongst child processes. Windows is not affected by this issue. In the next stable version of Node the distribution of incoming connections will be handled by node and by default use a round-robin approach. Despite the fact that it's not a great choice to use at this time we're going to cover how it works.
97
+
We'll start scaling Node using a built in technique. The cluster module that's part of the core node library is an option. In the current version of node (v0.10.\*) the cluster module doesn't appropriately route traffic to child processes. Node leaves the routing of incoming connections to the operating system. Unix based operating systems do a poor job of distributing new connections amongst child processes. Windows is not affected by this issue. In the next stable version of Node the distribution of incoming connections will be handled by node and by default use a round-robin approach. Despite the fact that it's not a great choice to use at this time we're going to cover how it works.
Now when we launch our process we can set the PORT environment variable. Let's try it by running passing different ports to a few node processes.
146
147
147
-
```
148
+
{% highlight bash %}
148
149
PORT=4000 node server.js&
149
150
PORT=4001 node server.js&
150
-
```
151
+
{% endhighlight %}
151
152
152
153
and test them:
153
154
154
-
```
155
+
{% highlight bash %}
155
156
curl -I localhost:4000
156
157
curl -I localhost:4001
157
-
```
158
+
{% endhighlight %}
158
159
159
160
and kill them
160
161
161
-
```
162
+
{% highlight bash %}
162
163
killall node
163
-
```
164
+
{% endhighlight %}
164
165
165
166
Alright, now we see how we can configure node process to listen on different ports via an environment variable. Let's see how to manage the lifetime several processes.
166
167
167
168
## Forever
168
169
169
170
Forever is an executable that's responsible for keeping a given process alive. If the process crashes, it's the responsibility of forever to start it again. Processes will die. This is a fundamental fact. It's worth mentioning that if a process encounters an unexpected exception it should terminate completely. This is recommended because the state of the process may be unknown. It's usually just as easy to start a brand new process than to deal with one in possibly an invalid state.
170
171
171
-
```
172
+
{% highlight bash %}
172
173
sudo npm install forever -g
173
-
```
174
+
{% endhighlight %}
174
175
175
176
Now we can use forever to ensure our node server continues running.
176
177
177
-
```
178
+
{% highlight bash %}
178
179
PORT=4000 forever start server.js
179
-
```
180
+
{% endhighlight %}
180
181
181
182
Now, let's find the process id of the newly started process and kill it.
Re-run the process grep and you should see a new process id assigned to the node process! Great! Now we have a way to keep the process running. The next step handle keeping processes running after a system restart.
0 commit comments