JavaScript best practices for writing clean code. Work with Object
Alex Shulaev
Posted on June 19, 2020
Accepting style guides or coding conventions helps make your code cleaner and more predictable.
The more detailed you describe the rules for your project, the easier it will be for another developer to write code according to your vision.
Now there is a large selection of ready-made style guides from various companies and developers posted in open source. In this article I want to give my advice on adding rules for working with Objects. You can consider this as recommendations, or you can configure ESLint
to automatically check these rules.
Object creation
Use literal syntax to create objects. This is a shorter analog of Object constructor.
// bad
const product = new Object();
// good
const product = {};
ESLint rule: no-new-object
How to add to your config:
"rules": {
"no-new-object": "error"
}
Object shorthand
Use shorthand for property value and methods. This recording option is intuitive and a shorter counterpart.
// bad
const product = {
name: name,
id: id,
getPrice: function () {},
generateSpecialOffer: function* () {},
};
// good
const product = {
name,
id,
getPrice() {},
*generateSpecialOffer() {},
};
ESLint rule: object-shorthand
How to add to your config:
"object-shorthand": [
"error",
"always",
{
"ignoreConstructors": false,
"avoidQuotes": true
}
]
Quotes
Property names of objects can be written with or without quotes, both of these options are valid. By analogy with the previous rules, we can decide not to use quotes as this is a shorter record, but in fact, it is not quite so, the fact is that we have cases when the presence of quotes is mandatory. For example, when a property name has space or dash. However, this is not so common, so using quotes for all properties will be irrational. The best option is to use quotes only when it is necessary.
// bad
const product = {
"description": "",
"short-description": "",
};
// good
const product = {
description: "",
"short-description": "",
};
ESLint rule: quote-props
How to add to your config:
"quote-props": ["error", "as-needed", { "unnecessary": true }]
Object.prototypes
The Object.create() method creates a new object, using an existing object as the prototype of the newly created object. This allows you to override methods (e.g. hasOwnProperty
), which can break the logic of the application. To solve this problem, you need to always call methods from Object.prototype
// bad
const product = {
name: "name-1",
id: 1,
};
console.log(product.hasOwnProperty("name")); // true?
// good
const product = {
name: "name-1",
id: 1,
};
console.log(Object.prototype.hasOwnProperty.call(product, "name")); // true
ESLint rule: no-prototype-builtins
How to add to your config:
"no-prototype-builtins": "error"
The "extends": "eslint:recommended"
property in a configuration file enables this rule.
Destructuring
Destructuring is now very popular and indeed it has proven itself in a much more convenient way than accessing a property through expression. The main advantage of destructuring is a shorter code entry. You no longer need to create additional variables to store properties
const product = {
name: "name-1",
id: 1,
price: "100$",
};
// bad
const getPrice = (product) => {
const price = product.price;
return `Full price: ${price}`;
};
// good
const getPrice = ({ price }) => `Full price: ${price}`;
ESLint rule: prefer-destructuring
How to add to your config:
"prefer-destructuring": [
"error",
{
"VariableDeclarator": {
"array": false,
"object": true
},
"AssignmentExpression": {
"array": true,
"object": false
}
},
{
"enforceForRenamedProperties": false
}
]
Object spread
If you have a task to combine several objects or get a copy of objects, you need to use Object.assign
with special care (or even better, use Spread syntax instead). Let's look at a simple example right away
// bad
const product = {
name: "name-1",
id: 1,
};
const copyProduct = Object.assign(product, { name: "name-2", id: 2 });
console.log("copyProduct", copyProduct); // {name: "name-2", id: 2}
console.log("product", product); // {name: "name-2", id: 2}
As a result, we got a mutation of the first object. This is not a bug, everything works as it should if you read about Object.assign(), but the problem is that it creates situations where the developer can forget about this behavior and get an unexpected result. To get the expected result without mutations you need to do
// still not very good
const product = {
name: "name-1",
id: 1,
};
const copyProduct = Object.assign({}, product, { name: "name-2", id: 2 });
console.log("copyProduct", copyProduct); // {name: "name-2", id: 2}
console.log("product", product); // {name: "name-1", id: 1}
Here we solved the problem with the mutation, but this structure is very wordy. We have a better option
// good
const product = {
name: "name-1",
id: 1,
};
const copyProduct = { ...product, name: "name-2", id: 2 };
console.log("copyProduct", copyProduct); // {name: "name-2", id: 2}
console.log("product", product); // {name: "name-1", id: 1}
With spread syntax, we were able to get rid of an unexpected mutation and the solution became much more concise.
Thank you for reading! This was a spontaneous article, now I'm writing a series of articles about the development of a side project, take a look if you are interested in it. See you soon 👋
Posted on June 19, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 22, 2024