Categories
JavaScript Best Practices

Better JavaScript — Prototypes and Functions

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *