Like any kind of apps, JavaScript apps also have to be written well.
Otherwise, we run into all kinds of issues later on.
In this article, we’ll look at ways to improve our JavaScript code.
Closures are Better than Strings for Encapsulating Code
We should never have code in strings.
If we need to run code, we should put them in a function.
For instance, if we have the repeat
function, we should never write something like:
function repeat(n, action) {
for (let i = 0; i < n; i++) {
eval(action);
}
}
eval
is always bad because of security, performance, and scoping issues.
Instead, we should write:
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action();
}
}
Then we can use it by writing:
const start = [];
repeat(1000, () => {
start.push(Date.now());
});
We passed in a callback so that we can run action
in our function.
The code should never be in a string.
Instead, it should take a callback function and run it.
Don’t Rely on toString Method of Functions
The toString
method doesn’t always return the source code of a function.
It does return the source code most of the time for functions we create.
So if we have:
(function(x) {
return x + 2;
}).toString();
Then we get:
"function(x) {
return x + 2;
}"
as a result.
If we use the toString
method on built-in native objects, then we won’t see the function’s source code.
For instance, if we have:
Math.max.toString()
Then we get:
"function max() { [native code] }"
If we do something like calling bind
to a function:
(function(x) {
return x + 2;
}).bind(16).toString();
Then we get:
"function(){return n.apply(e,t||arguments)}"
We don’t get back anything meaningful in the string.
Therefore, we can’t rely on toString
to always return the source code of a function.
Avoid Nonstandard Stack Inspection Properties
We should never use properties like arguments.callee
to get the function that calls another function.
And we shouldn’t use caller
property on the property to get the function that called the function even if the property exists.
These aren’t standard and they should be avoided.
So we should write code like:
function revealCaller() {
return revealCaller.caller;
}
These are all disallowed in ES5 strict mode, so this is a benefit of enabling it.
If we have:
function foo() {
"use strict";
return foo.caller;
}
We get ‘Uncaught TypeError: ‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode functions or the arguments objects for calls to them’.
Get the Difference Between prototype, getPrototypeOf, and proto
These objects are separate from each other.
prototype
and __proto__
all get the prototype of an object and set it.
And getPrototypeOf
is a method to get the prototype of an object.
__proto__
has become a standard so we can use it like prototype
.
prototype
is usually used for instance methods.
For instance, we can create a constructor by writing:
function Person(name) {
this.name = name;
}
Person.prototype.toString = function() {
return `Person ${this.name}`;
};
toString
is an instance method of the constructor.
Then we can write:
const person = new Person("james");
to create a new Person
instance.
The __proto__
property can be used like a regular property, so we can write:
person.__proto__
to get the prototype of the object.
We can also assign a value of it and use it as a property of an object.
Object.getPrototypeOf
can be used to get the prototype of an object, so we can write:
Object.getPrototypeOf(person)
to get the prototype.
A prototype is a JavaScript object that an object inherits from.
Conclusion
We should never run code in strings in our code.
Also, we shouldn’t use caller
and callee
in our code.
And we can get and set object prototypes in various ways.