- Chapter 1: Introduction
- Patterns
- JavaScript concepts
- ECMAScript 5
- JSLint
- The Console
- Chapter 2: Essentials
- Writing Maintainable Code
- Minimizing Globals
- for Loops
- for-in Loops
- (Not) Augmenting Built-in Prototypes
- switch Pattern
- Avoiding Implied Typecasting
- Avoiding eval()
- Number Conversions with parseInt()
- Coding Conventions
- Naming Conventions
- Writing Comments
- Writing API Docs
- Writing to Be Read
- Peer Reviews
- Minify...In Production
- Run JSLint
- Summary
- Chapter 3: Literals and Constructors
- Object Literal
- Custom Constructor Funtions
- Patterns for Enforcing new
- Array Literal
- JSON
- Regular Expression Literal
- Primitive Wrappers
- Error Objects
- Summary
- Chapter 4: Functions
- Background
- Callback pattern
- Returning functions
- Self-Defining functions
- Immediate functions
- Immediate Object initialization
- Init-Time Branching
- Function Properties - A Memoization Pattern
- Configuration Objects
- Curry
- Summary
- Chapter 5: Object Creation Patterns
- Namespace Pattern
- Declaring Dependencies
- Private Properties and Methods
- Module Pattern
- Sandbox Pattern
- Static Members
- Object Constants
- Chaining Pattern
-
method()
Method - Summary
-
-
Save muhammadghazali/c7ab0ff528b1c48ee3de to your computer and use it in GitHub Desktop.
muhammadghazali
commented
May 28, 2014
I just know if chain assignments is an anti pattern in JavaScript:
// antipattern, do not use
function foo() {
var a = b = 0;
// ...
}
``
When augmenting built-in prototypes:
- it can seriously hurt maintainability, because it will make your code less predictable
- it can create confusion, because other developers using your code will probably expect the built-in JavaScript methods to work consistently and will not expect your additions.
Therefore it’s best if you don’t augment built-in prototypes. You can make an exception of the rule only when all these conditions are met:
- It’s expected that future ECMAScript versions or JavaScript implementations will implement this functionality as a built-in method consistently. For example, you can add methods described in ECMAScript 5 while waiting for the browsers to catch up. In this case you’re just defining the useful methods ahead of time.
- You check if your custom property or method doesn’t exist already—maybe already implemented somewhere else in the code or already part of the JavaScript engine of one of the browsers you support.
- You clearly document and communicate the change with the team.
To avoid inconsistency and unexpected results, always specify the radix parameter when converting number with
parseInt()
For example:
var month = "06";
month = parseInt(month, 10);
Technically, if you have only one statement in an if or a for, curly braces are not required, but you should always use them anyway. It makes the code more consistent and easier to update.
always use curly braces and always put the opening one on the same line as the previous statement:
function func() {
return {
name: "Batman"
};
}
peer reviews help you write clearer code, simply because you know someone else will need to read and understand what you’re doing.
Peer reviews are a good practice not only because the resulting code is better, but also because both reviewer and creator share and exchange knowledge and learn from each other’s experience and individual approaches.
The code you write will be read (by humans), so make it easy for the maintainer to understand it quickly and let the minifier (the machine) take care of reducing the file sizes.
Literal notation patterns available in JavaScript enable more concise, more expressive, and less error-prone object definitions.
The custom objects you create in JavaScript (in other words, the user-defined native objects) are mutable at any time. Many of the properties of the built-in native objects are also mutable.
There are no classes in JavaScript and this allows for great flexibility, because you don’t have to know anything about your object in advance; you don’t need a class “blueprint.” But JavaScript also has constructor functions, which use syntax similar to the class-based object creation in Java or other languages.
An obvious benefit of the literal notation is:
- that it’s shorter to type
- emphasizes that objects are simply mutable hashes and not something that needs to be baked from a “recipe” (from a class)
This behavior of the Object() constructor can lead to unexpected results when the value you pass to it is dynamic and not known until runtime.
remember that reusable members, such as methods, should go to the prototype.
The inefficient way to add method:
var Person = function (name) {
this.name = name;
this.say = function () {
return "I am " + this.name;
};
};
the say()
method was added tothis
. The result is that
any time you call new Person()
a new function is created in memory.
The efficient way to add method:
Person.prototype.say = function () {
return "I am " + this.name;
};
As mentioned already, constructors are still just functions but invoked with new . What happens if you forget new when you invoke a constructor? This is not going to cause syntax or runtime errors but might lead to logical errors and unexpected behavior. That’s because when you forget new ,
this
inside the constructor will point to the global object. (In browsers this will point to window .)
Arrays in JavaScript, as most other things in the language, are objects. They can be created with the built-in constructor function Array() , but they also have a literal notation and, just like the object literal, the array literal notation is simpler and preferred.
It’s only a combination of the array and the object literal notation.
In JSON strings you cannot use functions or regular expression literals.
In object literals the quotes are required only when the property names are not valid identifiers, for example, they have spaces
{"first name": "Dave"}
.Use
JSON.parse()
method to parse JSON string. UseJSON.stringify()
method to serializes into a JSON string.
There is two options to create regular expressions in JavaScript:
- Using the
new RegExp()
constructor - Using the regular expression literal
// regular expression literal
var re = /\\/gm;
// constructor
var re = new RegExp("\\\\", "gm");
The good thing about the regular expression literal is makes the regular expression pattern shorter and doesn't force you to think in terms of class-like constructors. Therefore it's preferable to use the literal.
When using the RegExp()
constructor, we also need to escape quotes and often you need to double-escape backslashes, as shown in the preceding snippet, where we need four backslashes to match a single one. This makes your regular expression patterns longer and harder to read and modify.
So, it's best to stick with the literal notation when creating regular expression.
Calling RegExp()
without new
(as function, not as constructor) behaves the same as with new
.
JavaScript has five primitive value types:
number
,string
,boolean
,null
, andundefined
.With the exception of
null
andundefined
, the other three have the so-called primitive wrapper objects. The wrapper objects can be created using the built-in constructorsNumber
,String
, andBoolean
.
To illustrate the difference between a primitive number and a number object, consider the following example:
// a primitive number
var n = 100;
console.log(typeof n); // "number"
// a Number object
var nobj = new Number(100);
console.log(typeof nobj); // "object"
The wrapper objects have some useful properties and methods—for example, number objects have methods such as toFixed() and toExponential() . String objects have substring() , charAt() , and toLowerCase() methods (among others) and a length property. These methods are convenient and can be a good reason to decide to create an object, as opposed to using a primitive. But the methods work on primitives, too—as soon as you invoke a method, the primitive is temporarily converted to an object behind the scenes and behaves as if it were an object.
One reason to use the wrapper objects is when you want to augment the value and persist state. Because primitives are not objects, they cannot be augmented with properties.
When used without new , wrapper constructors convert the argument passed to them to a primitive value:
typeof
typeof
typeof
typeof
typeof
Number(1); // "number"
Number("1"); // "number"
Number(new Number()); // "number"
String(1); // "string"
Boolean(1); // "boolean"
Chapter 4. Functions
Mastering functions is an essential skill for the the JavaScript programmer because the language has many uses for them.
There are two main features of the functions in JavaScript that make them special, the first is that functions are first-class objects and the second is that they provide scope.
Functions are objects that:
- Can be created dynamically at runtime, during the execution of the program
- Can be assigned to variables, can have their references copied to other variables, can be augmented, and except for a few special cases, can be deleted.
- Can be passed as arguments to other functions and can also be returned by other functions
- Can have their own properties and methods
Using the
Function()
constructor is not a good idea though (it's as bad aseval()
) because code is passed around as a string and evaluated.The second important feature is that functions provide scope. In JavaScript there's no curly braces local scope; in other words, blocks don't create scope. There's only function scope.
Example of named function expression:
var add = function add(a, b) {
return a + b;
};
Example of unnamed function expression aka anonymous function:
var add = function (a, b) {
return a + b;
};
Example of function declarations:
function foo() {
// function body goes here
}
JavaScript is especially suited for event-driven programming, because of the callback pattern, which enables your programs to work asynchronously, in other words, out of order.
The callback is a simple and powerful pattern, which can come in handy when you’re designing a library. The code that goes into a software library should be as generic and reusable as possible, and the callbacks can help with this generalization. You don’t need to predict and implement every feature you can think of, because it will bloat the library, and most of the users will never need a big chunk of those features. Instead, you focus on core functionality and provide “hooks” in the form of callbacks, which will allow the library methods to be easily built upon, extended, and customized.
The great things about returning functions in JavaScript is we can have a function returning another more specialized function, or it can create another function on-demand, depending on some inputs.
Chapter 4: Immediate Functions
The immediate function pattern is a syntax that enables you to execute a function as it is defined.
Keep in mind, that the term immediate function is not defined in the ECMAScript standard.
Here is the step-by-steps to create immediate function:
define a function using a function expression
function() {
// TODO write enough code
}
add a set of parentheses at the end
function() {
// TODO write enough code
}()
wrap the whole function in parantheses
(function() {
// TODO write enough code
}());
The following alternative syntax is also common (note the placement of the closing parentheses):
(function () {
alert('watch out!');
})();
Parameters of an immediate function
How to pass an arguments to immediate functions:
(function(parameter1, parameter2){
// TODO write enough code
}("Argument of parameter 1", "Argument of parameter 2"));
Note that in general you shouldn't pass too many parameters to an immediate function, because it could quickly become a burden to constantly scroll to the top and top the bottom of the function to understand how it works.
Returned values from immediate functions
An immediate function can return values and these return values can be assigned to variables:
var result = (function() {
return 2 + 2;
}());
Benefits and usage
- it helps you wrap an amount of work you want to do without leaving any global variables behind.
- enables you to wrap individual features into self-contained modules.
Others
- Other names for the immediate function pattern include self-invoking or self-executing function, because the function executes itself as soon as it's defined.
Chapter 4: Configuration objects
Use configuration object pattern to provide cleaner APIs.
An example of function without configuration objects pattern:
function addPerson(first, last) { ... }
An example of function with configuration objects pattern:
// declaration
function addPerson(conf) { ... }
// usage
addPerson({
username: 'ghanoz',
age: 26
});
The pros of the configuration objects pattern are:
- No need to remember the parameters and their order
- You can safely skip optional parameters
- Easier to read and maintain
- Easier to add and remove parameters
The cons of the configuration objects are:
- You need to remember the names of the parameters
- Property names cannot always be safely minified, especially by simpler minifiers
Chapter 4: Summary
Useful patterns in JavaScript function:
- API patterns
- Initialization patterns
- Performance patterns
API patterns
These pattern help you provide better and cleaner interfaces to your functions. These patterns include:
- Callback patterns. Pass a function as an argument
- Configuration objects. Help keep the number of arguments to a function under control
- Returning functions. When the return value of one function is another function
- Currying. When new functions are created based on existing ones plus a partial list of arguments
Initialization patterns
These pattern help you perform initialization and setup tasks (very common to web pages and applications) in a clearer, structured way without polluting the global namespace with temporary variables. These patterns include:
- Immediate functions. Execute as soon as they are defined
- Immediate object initialization. Initialization tasks structured in an anonymous object that provides a method to be called immediately.
- Init-time branching. Helps branch code only once during initial code execution, as opposed to many times later during the life of the application.
Performance patterns
These patterns help speed up the code. These include:
- Memoization. Using function properties so that computed values are not computed again.
- Self-defining functions. Overwrite themselves with new bodies to do less work from the second invocation and after.