Skip to content

Commit ef66875

Browse files
committed
Further cleanup, rewriting etc.
1 parent 92b9dbd commit ef66875

File tree

5 files changed

+160
-109
lines changed

5 files changed

+160
-109
lines changed

doc/arguments.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
## Function arguments
22

3-
Inside of functions JavaScript injects a special variable into the scope of the
4-
function. This variable is called `arguments`, and holds a list of all the
5-
arguments that were passed to the function.
3+
Inside the scope of a function JavaScript injects a special variable into. This
4+
variable is called `arguments` and holds a list of all the arguments that were
5+
passed to the function.
66

7-
It's important to know that `arguments` is **not** an `Array`. It has some of
8-
the semantics of an array - namely the `length` property - but it does not
9-
inherit from `Array.prototype`, and is in fact an `Object`.
7+
This `arguments` variable is **not** an `Array`. It has some of the semantics of
8+
an array - namely the `length` property - but it does not inherit from
9+
`Array.prototype`. It is in fact an `Object`.
1010

1111
Due to this, it is not possible to use standard array methods like `push`,
12-
`pop` or `slice` on it. While iteration with a plain `for` loop works just fine,
13-
one has convert it to a real `Array` in order to use the those methods.
12+
`pop` or `slice` on `arguments`. While iteration with a plain `for` loop works
13+
just fine, one has convert it to a real `Array` in order to use the array like
14+
methods.
1415

1516
### Converting to an array
1617

doc/constructors.md

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
## Constructors
22

3-
Constructors in JavaScript are another thing many people get wrong, but actually, their
4-
workings are pretty simple to understand.
5-
6-
Any function call that is preceded by the `new` keyword acts as a constructor.
3+
Constructors in JavaScript are yet again different from many other languages. Any
4+
function call that is preceded by the `new` keyword acts as a constructor.
75

86
Inside the constructor (the called function) the value of `this` refers to a
9-
newly created `Object`. The `prototype` of this **new** object is set to the
10-
`prototype` of the function object that was called.
7+
newly created `Object`. The [`prototype`](#prototype) of this **new** object is
8+
set to the `prototype` of the function object that was called.
119

1210
If the function that was called has no explicit `return` statement, then it
1311
implicitly returns the value of `this` (the new object). Otherwise it returns
@@ -26,17 +24,15 @@ the value of the `return` statement.
2624
The above calls `Foo` as constructor and sets the `prototype` of the newly
2725
created object to `Foo.prototype`.
2826

29-
Keep in mind that if you don't use the `new` keyword the function will **not**
27+
Keep in mind that if you don not use the `new` keyword the function will **not**
3028
return a new object. While it might still work due to how
3129
[`this`](#how-this-works-in-javascript) works in JavaScript, it will use the
32-
*global* object as the value of `this` and therefore result in completely
33-
unexpected results.
30+
*global* object as the value of `this`.
3431

3532
### Factories
3633

37-
If you want to omit the `new` keyword you can do that by - as stated above -
38-
explicitly returning from the constructor, which essentially leaves you with a
39-
factory.
34+
In order to be able to omit the `new` keyword, the constructor function has to
35+
explicitly return a value.
4036

4137
function Bar() {
4238
var value = 1;
@@ -46,20 +42,60 @@ factory.
4642
}
4743
}
4844
}
45+
Bar.prototype = {
46+
foo: function() {}
47+
};
4948

5049
new Bar();
5150
Bar();
5251

53-
Now, both these calls return the exact same thing, a newly create object which
52+
Both these calls return the exact same thing, a newly create object which
5453
has a property called `method` which is a [Closure](#closures-and-references).
5554

56-
Since `Bar` doesn't make any use of `this`, the `new` keyword is superfluous
57-
here. But from a technical point of view, this is no longer a *constructor*.
55+
Also note that the call `new Bar()` does **not** affect the prototype of the
56+
returned object. While the prototype will be set on the newly created object,
57+
`Bar` never returns that object.
58+
59+
So in the above example there is no functional difference between using and
60+
omitting the `new` keyword.
61+
62+
63+
### Creating new objects via factories
64+
65+
An often made recommendation is to **not** use `new` since forgetting the use of
66+
it may lead to a lot of bugs.
67+
68+
In order to create new object one now has to use a factory and set up the new
69+
object inside it.
70+
71+
function Foo() {
72+
var obj = {};
73+
obj.value = 'blub';
74+
75+
var private = 2;
76+
obj.someMethod = function(value) {
77+
this.value = value;
78+
}
79+
80+
obj.getPrivate = function() {
81+
return private;
82+
}
83+
return obj;
84+
}
85+
86+
While the above is robust against forgetting to use `new` and makes the use of
87+
[private variables](#closures) certainly easier, it comes with some down sides.
88+
89+
1. It uses more memory since the created objects do **not** share the methods
90+
2. In order to inherit the factory needs to copy all the methods from another
91+
object
92+
3. It somehow goes against the spirit of the language, by dropping prototype
93+
chain just because a left out `new` keyword can break code
5894

59-
### Best Practices
95+
### Best practices
6096

61-
Make sure you know whether you're calling a *constructor* or a *factory*.
62-
If in doubt, always use the `new` keyword, since it doesn't have any side effect
63-
when its not required, while leaving it out can lead to subtle and
64-
hard to track down bugs.
97+
While omitting the `new` keyword might lead to bugs, it is certainly not a reason
98+
to drop the use of prototypes altogether. In the end it comes down which
99+
solution is better suited for the needs of the application, it is especially
100+
important to choose a specific style of object creation and stick with it.
65101

doc/scopes.md

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ scope*.
66

77
> **Note:** When not used in an assignment or as a function argument, the `{...}`
88
> notation will get interpreted as a block statement and **not** as an `Object`.
9-
> This, in conjunction with
10-
> [automatic insertion of semicolons](#semicolon), can lead
11-
> to subtle errors.
9+
> This, in conjunction with [automatic insertion of semicolons](#semicolon),
10+
> can lead to subtle errors.
1211
13-
Additionally, there are no distinct namespaces in JavaScript, this means that
12+
Additionally, there are no distinct namespaces in JavaScript. This means that
1413
everything gets defined in **one** globally shared namespace.
1514

16-
Each time one references a variable, JavaScript will traverse through the scopes
17-
upwards until it finds it. In the case that it reaches the global scope and still
18-
can't find the requested name it will raise a `ReferenceError`.
15+
Each time a variable is referenced, JavaScript will traverse upwards through all
16+
the scopes until it finds it. In the case that it reaches the global scope and
17+
still has not found the requested name, it will raise a `ReferenceError`.
1918

2019
### The Bane of global Variables
2120

@@ -29,8 +28,8 @@ The above two scripts do **not** have the same effect. Script A defines a
2928
variable called `foo` in the *global* scope and script B defines a `foo` in the
3029
*local* scope.
3130

32-
Again, that's **not** at all the same effect, forgetting to use a `var` can have
33-
major implications.
31+
Again, that is **not** at all the same effect, not using `var` can have major
32+
implications.
3433

3534
// global scope
3635
var foo = 42;
@@ -42,10 +41,9 @@ major implications.
4241
foo; // 21
4342

4443
Leaving out the `var` statement will override the value of `foo`, this might not
45-
seem like a big deal at first, but consider you have a ten-thousand line
44+
seem like a big deal at first, but consider having a ten-thousand line
4645
JavaScript file with lots and lots of different variable names, not using `var`
47-
will introduce bugs for sure. And additionally those bugs are very often hard to
48-
track down.
46+
will introduce hard to track down bugs.
4947

5048
For example, when using generic variable names like `i` in loops.
5149

@@ -63,43 +61,42 @@ For example, when using generic variable names like `i` in loops.
6361
}
6462

6563
The outer loop will terminate after the first call to `subLoop` since that
66-
function had overriden the global value of `i`. Using a `var` for the second
67-
`for` loop would have easily avoided this, therefore never leave out `var`
68-
unless you really want to access the variable of an outer scope.
64+
function overwrites the global value of `i`. Using a `var` for the second
65+
`for` loop would have easily avoided this error, therefore `var` should never be
66+
left out unless the desired effect **is** to affect the outer scope.
6967

70-
### Local Variables
68+
### Local variables
7169

72-
If one wants to declare a variable *local* to the current scope thes have to use
73-
the `var` keyword. **Always** use the `var` keyword when declaring variables
74-
otherwise you might **overriding** things that were already defined in outer
75-
scopes.
70+
The only source for local variables in JavaScript are [function](#functions)
71+
parameters and variables that were declared with the `var` statement.
7672

7773
// global scope
7874
var foo = 1;
7975
var bar = 2;
76+
var i = 2;
8077

81-
function test() {
82-
78+
function test(i) {
8379
// local scope of the function test
80+
i = 5;
81+
8482
var foo = 3;
8583
bar = 4;
8684
}
85+
test(10);
8786

88-
In the above, `var foo` inside of `test` will create a new variable that is in
89-
the *local* scope. Therefore the value of the *global* `foo` does **not** get
90-
changed. But the assignment `bar = 4` will override the value of the *global*
91-
`bar` due to the missing `var` keyword.
87+
While `foo` and `i` are local variables inside the scope of the function `test`,
88+
the assignment of `bar` will override the global variable.
9289

93-
### Name Resolution Order
90+
### Name resolution order
9491

95-
All scopes in JavaScript - including the global one, have the name
96-
[this](#this) defined in them, which refers to the
97-
"current object". Function scopes also have the name
98-
[arguments](#arguments) defined, which contains the arguments that were
99-
passed to a function.
92+
All scopes in JavaScript - including the global one - have the name
93+
[this](#this) defined in them, which refers to the "current object".
10094

101-
For example, when you try to access a variable named `foo` inside a function
102-
scope, JavaScript will lookup the name in the following order:
95+
Function scopes also have the name [arguments](#arguments) defined, which
96+
contains the arguments that were passed to a function.
97+
98+
For example, when trying to access a variable named `foo` inside the scope of a
99+
function, JavaScript will lookup the name in the following order:
103100

104101
1. In case there's a `var foo` statement in the current scope use that.
105102
2. If one of the function parameters is named `foo` use that.
@@ -111,9 +108,9 @@ scope, JavaScript will lookup the name in the following order:
111108
112109
### Namespaces
113110

114-
One common problem of having only one global namespace is, that its very easy to
115-
run into problems where variable names clash. Luckily this can be easily avoided
116-
with the help of *anoynmous function wrappers*.
111+
A common problem of having only one global namespace is that it is very easy to
112+
run into problems where variable names clash. But this can be easily avoided
113+
with the help of anonymous *function wrappers*.
117114

118115
(function() {
119116
// a self contained "namespace"
@@ -124,16 +121,29 @@ with the help of *anoynmous function wrappers*.
124121

125122
})(); // execute the function immediately
126123

127-
By default you cannot just call a function, you need to **evaluate** it first.
128-
In this example, this is done by wrapping the
129-
[function expression](#functions) in parenthesis. While this is
130-
the most common style to do this, everything else that forces the function to be
131-
evaluated works just as well, like for example `+function(){}()`.
124+
125+
Since a unnamed functions are not considered as [statement](#functions), they
126+
get interpreted as expression, in order to run those functions they must fist be
127+
evaluate and then called.
128+
129+
( // evaluate the function inside the paranthesis
130+
function() {}
131+
) // and return the function object
132+
() // call the result of the evaluation
133+
134+
There are other ways for evaluating and calling the function expression which -
135+
while different in syntax - do the exact same thing.
136+
137+
// Two other ways
138+
+function(){}();
139+
(function(){}());
132140

133141
### Best Practices
134142

135-
Always use the *anonymous wrapper* to encapsulate your code in case there's any
136-
chance it might get used by someone else in their project. Also never define any
137-
variables in the *global* namespace, always use `var` to limit the scope of your
138-
variables.
143+
It is recommended to always use an *anonymous wrapper* for encapsulating code in
144+
its own namespace. This does not only protect against name clashes, but it also
145+
allows for better modularization.
146+
147+
Additionally the use of global variables is consider **bad practice**, any use
148+
of them indicates badly written, hard to maintain code.
139149

doc/this.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
## How `this` works
22

3-
JavaScript has, at first glance, a very strange concept of what `this` refers to.
4-
There are exactly five different ways in which the value of `this` can get set.
3+
JavaScript has a different concept of what `this` refers to than most other
4+
languages do. There are exactly **five** different ways in which the value of `this`
5+
can be bound in the language.
56

67
### The global scope
78

@@ -25,32 +26,33 @@ In this example `this` will refer to `test`.
2526

2627
new foo();
2728

28-
A function call that's preceded by the `new` keyword acts as
29+
A function call that is preceded by the `new` keyword acts as
2930
a [constructor](#constructors). Inside the function `this` will refer to a newly
3031
created `Object`.
3132

3233
### Explicit setting
3334

34-
function foo(a, b, c) {
35-
}
35+
function foo(a, b, c) {}
3636
3737
var bar = {};
3838
foo.call(bar, [1, 2, 3]);
3939
foo.apply(bar, 1, 2, 3);
4040

41-
When using the `call` or `apply` methods of `Function.prototype`, one can
42-
explicitly set the value of `this` inside the called function, so in the above
43-
case the *method case* does **not** apply, and `this` inside of `foo` will be
44-
set to `bar`.
41+
When using the `call` or `apply` methods of `Function.prototype`, the value of
42+
`this` inside the called function gets explicitly set to the first arguments of
43+
those function calls.
44+
45+
In the above example the *method case* does **not** apply, and `this` inside of
46+
`foo` will be set to `bar`.
4547

4648
> **Note:** `this` **cannot** be used to refer to the object inside of an `Object`
4749
> literal. So `var obj = {me: this}` will **not** result in `me` referring to
4850
> `obj`, since `this` gets determined by one of the above cases.
4951
50-
### Common Pitfalls
52+
### Common pitfalls
5153

5254
While most of these cases make sense, the first one is considered a mis-design
53-
by many people since it's **never** of any practical use, but leads to many bugs.
55+
by many people as it is **never** of any practical use.
5456

5557
Foo.method = function() {
5658
function test() {
@@ -73,20 +75,20 @@ variable inside of `method` which refers to `Foo`.
7375
test();
7476
}
7577

76-
`that` is just a normal name, but it's a common idiom to use it as a reference
77-
to an outer `this`. In combination with [Closures](#closures),
78-
this can also be used to pass `this` around.
78+
`that` is just a normal name, but it is commonly used for the reference to an
79+
outer `this`. In combination with [Closures](#closures), it can also be used to
80+
pass `this` values around.
7981

80-
### Assigning Methods
82+
### Assigning methods
8183

82-
Another thing that does **not** work in JavaScript is **assigning** a method to
83-
a variable.
84+
Another thing that does **not** work in JavaScript is **assigning** a method
85+
reference to a variable.
8486

8587
var test = someObject.methodTest();
8688
test();
8789

88-
Again due to the first case, `test` now acts like like a plain function call
89-
therefore the `this` inside it will not refer to `someObject` any more.
90+
Again due to the first case, `test` now acts like like a plain function call and
91+
therefore the `this` inside it will no longer refer to `someObject`.
9092

9193
While the late binding of `this` might seem like a bad thing, it is fact what
9294
makes [prototypical inheritance](#prototype) work.
@@ -102,8 +104,9 @@ makes [prototypical inheritance](#prototype) work.
102104
When `method` gets called on a instance of `Bar`, `this` will now refer to that
103105
instance.
104106

105-
### Best Practices
107+
### Best practices
108+
109+
Understand the exact workings of `this` and not trying to work around them is a
110+
requirement for writing efficient, well designed code that can make use of
111+
features such as [prototypical inheritance](#prototype) and [closures](#closures).
106112

107-
Don't try to work around the behavior of `this` in JavaScript. Instead,
108-
**understand** how and why it works the way it does. Otherwise you'll end up with
109-
a lot of bugs that seem to be there for no good reason.

0 commit comments

Comments
 (0)