Tari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.
The “structuredClone is not defined” error occurs when you try to use the structuredClone()/ method in JavaScript, but it’s not defined.
The “structuredClone is not defined” error occuring in a terminal.
To fix it, install Node.js 17 or a newer version. Once you’ve updated Node.js, you can use structuredClone() to clone objects with all their properties and methods.
What causes the “structuredClone is not defined” error?
If you try to use the structuredClone() method in a script that’s running with a Node.js version lower than 17, you will encounter this error.
The structuredClone() method is used to create a deep copy of an object. It’s a built-in function in JavaScript and is used to clone an object with all its properties and methods.
But when the structuredClone() method is not defined, it means that the server environment doesn’t recognize the function and cannot perform the action.
Fix: update Node.js
To fix the “structuredClone is not defined” error in JavaScript, you need to install Node.js 17 or a newer version. If you’re using an older version of Node.js, it will throw an error when you try to use structuredClone().
Install from website
To download Node.js, visit the official website and opt for the LTS version, as it offers superior stability. As of the time of writing this article, the most recent LTS release of Node.js is v18.15.0.
The Node.js download page on the official website.
Install with Chocolatey
If you’re using Chocolatey, Node.js is available as the nodejs package, meaning you can easily install it in a terminal using the following command.
ShellCopied!
# Use current LTS version
choco install nodejs --version=18.5.0
After installing, you can use the structuredClone method to clone an object:
If you get the “structuredClone is not defined” error when using the structuredClone() method in JavaScript, it means that the method is unavailable. To fix the problem, update your Node.js to a version newer than 17. You can get the latest version from the official Node.js website or install the nodejs package using Chocholatey.
First, we use selector methods like document.querySelector() and document.getElementById() to get an object representing the various elements to be used in the JavaScript code.
Then, we call the addEventListener() method on the text field object to set an event listener for the keydown event. When the user types a key or input is simulated from a script, the event listener will be fired, incrementing the key press count and displaying the most recently pressed key.
We also call the addEventListener() method on the simulate button object for the click event to simulate the key press when the user clicks the button.
Simulating a keypress fires the key event.
Notice that the key is not entered in the text field. This is because of the isTrusted property, which indicates whether a user action or script generated an event. When isTrusted is false, the event is not considered trusted and does not reflect visually in the text field. Browsers do this for security reasons.
isTrusted is a readonly property and will only be true when an actual user’s action caused the event; in this case: typing on the keyboard.
Insert value into input field or textarea
If you want to enter a key into the text field programmatically, you’ll have to use other approaches. For input and textarea elements, here’s a method you can use:
This function takes the text field element and some text as arguments and inserts the text into the text field, replacing any highlighted text before the insertion.
You can also use the insert-text-at-cursor NPM package to insert text into an input field or textarea. Its default export function works like the one above.
JavaScriptCopied!
import insertTextAtCursor from 'insert-text-at-cursor';
Either function can be called like this:
JavaScriptCopied!
insertTextAtCursor(textField, 'Coding Beauty');
Simulate keypress in input field with key modifier
Sometimes, you might want to simulate a key combination that includes the modifier keys, e.g., Ctrl + A, Ctrl + Shift + C, etc. There are option properties you can set to do this.
For instance, setting the ctrlKey property to true simulates the Ctrl + {key} combination, where {key} is the value assigned to the key property.
JavaScriptCopied!
// Ctrl + c, Ctrl + o, Ctrl + d, Ctrl + e
const keysToSend = 'code';
let keyIndex = 0;
simulate.addEventListener('click', () => {
simulateKeyPress(keysToSend.at(keyIndex++) || keysToSend.at(-1));
});
function simulateKeyPress(key) {
const event = new KeyboardEvent('keydown', { key, ctrlKey: true });
textField.dispatchEvent(event);
}
Simulating various key combinations with the Ctrl modifier.
Some other important key modifier option properties are:
altKey: adds the Alt key to the key combination, e.g., Alt + Z, Ctrl + Alt + N, etc.
ctrlKey: adds the Ctrl key to the key combination, e.g., Ctrl + A, Ctrl + Shift + T, etc.
shiftKey: adds the Shift key to the key combination.
metaKey: adds the ⌘ key on MacOS and the Windows key on Windows to the key combination.
Key takeaways
We can easily simulate keypresses in JavaScript on a text field by calling the dispatchEvent() method on the element object, passing a custom-created KeyboardEvent object as an argument. While this will trigger the appropriate key events set on the element, it would not visually reflect on the text field since programmatically created events are not trusted for security reasons.
// Convert NodeList to Array with slice()
const inputs = Array.prototype.slice.call(
document.querySelectorAll('.form input')
);
inputs.forEach((input) => {
input.addEventListener('keydown', (event) => {
const num = Number(event.key);
if (num && num >= 0 && num <= 9) { // Only allow numbers
if (input.value.length >= input.maxLength) {
event.preventDefault();
focusNext();
}
}
});
});
function focusNext() {
const currInput = document.activeElement;
const currInputIndex = inputs.indexOf(currInput);
const nextinputIndex =
(currInputIndex + 1) % inputs.length;
const input = inputs[nextinputIndex];
input.focus();
}
The next input gains focus when the input limit is reached.
We use the document.querySelectorAll() method to obtain a collection of all the input elements in the form. This method in JavaScript allows you to find all the elements on a web page that match a certain pattern or characteristic, such as all elements with a particular class name or tag name.
We use the forEach() method to iterate over the array of input elements we obtained using document.querySelectorAll(). For each input element, we add an event listener to listen for the keydown event.
When a key is pressed down, we check if the key pressed is a number between 0 and 9. If it is, we check if the length of the input’s value is equal to its maxLength attribute. If it is, we prevent the default action of the event and call the focusNext() function to move the focus to the next input element.
The forEach() method is a higher-order function in JavaScript that allows you to run a function on each element of an array.
Tip: A higher-order function is a function that can take in functions as arguments and/or return a function.
In the focusNext() function, we first get the currently focused input element using document.activeElement. We then get the index of this input element in the inputs array we created earlier using inputs.indexOf(currInput).
We then calculate the index of the next input element in the array using (currInputIndex + 1) % inputs.length, where % is the modulo operator. This ensures that if the currently focused input element is the last one in the array, we wrap around to the first input element.
Finally, we get a reference to the next input element using inputs[nextinputIndex] and call the focus() method on it to move the focus to the next input element.
Set focus on next input on enter
Sometimes, we want to move the focus to the next input element when the user presses the Enter key instead of waiting for the input’s maxLength to be reached. To do this, we can add an event listener to listen for the keydown event on each input element. When the Enter key is pressed, we prevent the default action of the event and call the focusNext() function to move the focus to the next input element.
Now, when the user presses the Enter key, the focus will move to the next input element. This can be especially useful in forms where the user needs to quickly move through a series of inputs without having to manually click on each one.
The MutationObserver API allows tracking changes to the DOM tree, including when elements are added, removed, modified, or have an attribute changed. It can also track changes to an element’s contents or styles, such as the addition or deletion of text or when a style property is modified.
We’ll look at how to use the Mutation API in this article and real-world use cases to see its importance.
Mutation Observer in action
Let’s look at the Mutation Observer API in action right away:
JavaScriptCopied!
// Usage
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
const el = mutation.target;
if (el.textContent === 'Hello!') {
el.textContent = 'Welcome!';
}
}
});
const textEl = document.getElementById('info');
observer.observe(textEl, { childList: true });
// Test
const changeText = document.getElementById('change-text');
changeText.addEventListener('click', () => {
textEl.textContent = 'Hello!';
});
The displayed text is changed by Mutation Observer.
Create a Mutation Observer
We create a Mutation Observer using the MutationObserver() constructor. The constructor accepts a callback that will be called when a mutation is detected on an element.
The callback is passed an array of MutationRecord objects, each containing information about the particular mutation that just occurred.
JavaScriptCopied!
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
// Process mutations...
}
});
Two essential properties that a MutationRecord object has are the target and type property.
The target property holds the element that was mutated and type contains the type of mutation that just occurred. We can use these two properties to identify what kind of mutation happened and take the appropriate action.
For instance, we can check if the mutation was an attribute change, a child node change, or a text node change and then act accordingly. type can take the following values:
attributes: attribute change
characterData: text node change
childList: child node change
We can then use this data to take the appropriate action in our callback. For example, if a change to an element’s child nodes is detected, we can update the UI to reflect the new changes.
JavaScriptCopied!
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
const type = mutation.type;
const element = mutation.target;
console.log(`${mutation.type} mutation on element #${element.id}`);
}
});
Observe changes with Mutation Observer
Once we have created a Mutation Observer, we can use the observe() method to start observing changes in an element. The observe() method takes two arguments: the element to observe and the configuration object. The configuration object can contain options to configure what kind of mutations to watch for. These options include childList, attributes, and characterData.
For example, if we want to watch for changes in an element’s child nodes, we can set the childList option to true. Similarly, if we’re going to watch for changes to attributes and text nodes, we can set the attributes and characterData option to true respectively.
Once we have configured our Mutation Observer and started observing changes, we can react to any changes.
Stop watching for changes in element
Once we have started observing changes, we can stop watching for changes at any time by calling the disconnect() method on the Mutation Observer. This will immediately stop watching for changes in the element, and the observe() method will no longer be called. This can be useful when you no longer need to watch for changes in an element and want to free up memory and resources.
JavaScriptCopied!
observer.disconnect();
Use MutationObserver in the real-world
In many cases, you may encounter an external script that brings a range of valuable features and capabilities but brings about unwanted visual effects, like displaying text with content you’d like to customize but can’t. In this type of scenario, Mutation Observer can be used as a workaround. This tool can detect when the text content is changed in the DOM and automatically replace it with something more suitable for the task.
Get all pending mutations with takeRecords()
Mutation Observer is a powerful JavaScript API that detects changes to DOM tree elements, such as added/removed components, changed attributes, altered text content, and changed styles. A practical use is to detect and customize content set by external scripts. Create a Mutation Observer with a callback function and use observe() it to start monitoring and disconnect() to end it. takeRecords() retrieves all pending Mutation Records.
To get the current position of the mouse in JavaScript, add a mousemove event listener to the window object and access the clientX and clientY properties of the MouseEvent object in the listener to get the X and Y coordinates of the mouse respectively.
The mousemove event is triggered on an element when the mouse hovers it. To be more precise, it is fired when the mouse is moved and the cursor’s hotspot is within the element’s bounds.
We attach the event listener to the window object to trigger the event whenever the mouse has moved anywhere on the page.
The mousemove event listener receives a MouseEvent object used to access information and perform actions related to the event. We use the clientX and clientY properties of this object to get the position of the mouse on the X-coordinate and Y-coordinate respectively in the application’s viewport.
Get current mouse position relative to element in React
In the first example, we get the current mouse position in global coordinates. In global coordinates, position (0, 0) is at the top-left of the webpage and position (Xmax, Ymin) is at the bottom right.
We might instead want to get the mouse position within the region of an element.
To get the current mouse position relative to an element, set a mousemove event handler on the element, then calculate the local X and Y positions using properties of the MouseEvent object passed to the event handler.
For example:
HTMLCopied!
<div>
<div class="local">
Local
<br />
<b><span id="local-mouse-pos"></span></b>
</div>
<p>
Global
<br />
<b><span id="global-mouse-pos"></span></b>
</p>
</div>
Now the resulting X and Y coordinates will be relative to the element. For example, position (0, 0) will be at the top left of the element, not the viewport:
The current mouse position relative to the element is shown.
We subtract the offsetLeft property of the element from the clientX property of the MouseEvent object to get the position on the X-axis relative to the element.
Similarly, to get the position on the Y-axis, we subtract the offsetTop property from the clientY property of the MouseEvent object.
To check if a string contains whitespace in JavaScript, call the test() method on this regex: \s, i.e., /\s/.test(str). test() will return true if the string contains any whitespace character. Otherwise, it will return false.
The RegExptest() method searches a string for matches with a regular expression. It returns true if any matches are found. Otherwise, it returns false.
The forward slashes / and / indicate the start and end of the regular expression.
The \s matches any single whitespace character in the string.
This method will match any whitespace character, including:
Like the RegExp test() method, match() searches a string for matches with a regular expression, but it returns an array of the matches, instead of a boolean value.
In this case, match() returns an array that contains the first match of a whitespace character, along with some additional properties that provide more information on the match.
If there are no matches found in the string, match() returns null:
JavaScriptCopied!
console.log('Coding_Beauty'.match(/\s/)); // null
Because of how match() works, we can cast the return value to a boolean, whose value would indicate whether or not any matches of a whitespace character exist in the string.
The Boolean() constructor casts a truthy or false value to true or false. An array of matches from match() will be cast to true, indicating the presence of matches, and a null value from match() will be cast to false, meaning that no matches can be found.
Note: In JavaScript, there are six falsy values: undefined, null, NaN, 0, '' (empty string), and false. Every other value is truthy.
The class is added to all elements when the button is clicked.
The Dev text and Visit button are larger than other elements in font size, because font-size: 1.2em from the big class is applied to their .container parent, and also to them individually, so they each have a resulting font-size of 1.44em relative to the root element.
If any of the classes passed to add() already exists on the element, add() will ignore this, instead of throwing an error.
Add class to all child elements of element
If we want, we could instead add a class to all child elements of a parent that has a specific selector, such as an ID, class, or tag. For instance, we could have done this for the .container element.
To do this, we just need to prefix the * with the element’s selector and separate them with a space. Like we did for body * to get all the elements in the body tag.
The class is added to all elements in the .container when the button is clicked.
Remove class from all elements
Just like the classList.add() method adds one or more classes to an element, the classList.remove() remove one or more classes from an element. This means that we can use it in the forEach() method to remove a class from all DOM elements.
The “Cannot read property ‘toString’ of undefined” error occurs in JavaScript when you call the toString() on a variable that unexpectedly has a value of undefined.
To fix it, try one of the following:
Add an undefined check on the variable.
Ensure the variable is initialized.
Ensure you’re not trying to access the variable from a non-existent index in the array.
1. Add undefined check on variable
a. Use if statement
We can use an if statement to check if the variable is truthy before calling the toString() method.
JavaScriptCopied!
const obj = undefined;
let result = undefined;
if (obj) {
result = obj.toString();
}
console.log(result); // undefined
b. Use optional chaining
We also use the optional chaining operator?. to return undefined and prevent the method access if the variable is null or undefined.
JavaScriptCopied!
const obj = undefined;
const result = obj?.toString();
console.log(result);
We can use the ?. operator for as many levels as possible.
This:
JavaScriptCopied!
if (a?.b?.c?.d?.e) {
console.log('property "e" is not undefined');
}
is equivalent to the following:
JavaScriptCopied!
if (a && a.b && a.b.c && a.b.c.d && a.b.c.d.e) {
console.log('property "e" is not undefined');
}
c. Call toString() on fallback value
We can use the nullish coalescing operator (??) to provide a fallback value to call toString() on:
JavaScriptCopied!
const num = undefined;
const numStr = (num ?? 10).toString();
console.log(numStr); // 10
const date = undefined;
const dateStr = (date ?? new Date()).toString();
console.log(dateStr); // Fri Jan 13 2023 20:07:10
The null coalescing operator (??) returns the value to its left if it is not null or undefined. If it is, then ?? returns the value to its right.
The solutions above are handy when we don’t know beforehand if the variable will be undefined or not. But there are situations where the “Cannot read property ‘toString’ of undefined” error is caused by a coding error that led to the variable being undefined.
It could be that you forgot to initialize the variable:
JavaScriptCopied!
let date; // possibly missing initialized to new Date();
// code...
// ❌ Cannot read property 'toString' of undefined
console.log(date.toString());
Because an uninitialized variable has a default value of undefined in JavaScript, accessing a property/method causes the error to be thrown.
The obvious fix for the error, in this case, is to assign the variable to a defined value.
JavaScriptCopied!
let date = new Date(); // possibly missing initialized to new Date();
// ✅ toString() called, no error thrown
// Fri Jan 13 2023 20:44:22
console.log(date.toString());
3. Ensure variable is accessed from existing array index
Another common mistake that causes this error is trying to access an element at an index that doesn’t exist in the array.
For example:
JavaScriptCopied!
const dates = [new Date('2020-05-17'), new Date('2021-08-11')];
const dateStrs = [];
// ❌ Cannot read properties of undefined (reading 'toString')
for (let i = 0; i <= dates.length; i++) {
dateStrs.push(dates[i].toString());
}
console.log(dateStrs);
We get the error in the example, because the for loop’s condition makes it perform an iteration where i is equal to dates.length. As the last index if dates.length - 1, accessing index dates.length will result in undefined.
The fix in this particular case is to change the <= to <, to make the loop stop after the iteration where i is the last index.
JavaScriptCopied!
const dates = [new Date('2020-05-17'), new Date('2021-08-11')];
const dateStrs = [];
// ✅ loop executes successfully - no error
for (let i = 0; i < dates.length; i++) {
dateStrs.push(dates[i].toString());
}
console.log(dateStrs);
// ['Sun May 17 2020 00:00:00...', 'Wed Aug 11 2021 00:00:00...'];
If you’re not sure that the index exists in the array, you can use the ?. operator like we did previously.
JavaScriptCopied!
const dates = [new Date('2020-05-17'), new Date('2021-08-11')];
// No error
console.log(dates[50]?.toString()); // undefined
JavaScript has no native event for listening for URL changes in the browser, so to do this, you can create an interval listener that compares the current URL value to the previous value every X seconds.
JavaScriptCopied!
let prevUrl = undefined;
setInterval(() => {
const currUrl = window.location.href;
if (currUrl != prevUrl) {
// URL changed
prevUrl = currUrl;
console.log(`URL changed to : ${currUrl}`);
}
}, 60);
We call setInterval() with a callback and 60 to invoke the callback every 60 seconds. In the callback, we check if the current URL is the same as the last URL; if it is, we perform our desired action.
To check if a function returns a Promise in JavaScript, call the function (impossible without doing so), and use the instanceof operator to check if the return value is a Promise object.
For example:
JavaScriptCopied!
console.log(returnsPromise(func1));
console.log(returnsPromise(func2));
console.log(returnsPromise(func3));
function returnsPromise(func) {
return func() instanceof Promise;
}
function func1() {
return new Promise((resolve) => {
resolve('Coding Beauty');
});
}
async function func2() {
return 100;
}
function func3() {
return 'Coding Beauty';
}
Unfortunately, there’s no way to check if a function returns a Promise without invoking it and getting its result.
After getting the return value, we use instanceof to check if it’s a Promise instance.
Ensure Promise return value from function
If you’re checking the function’s return value to convert a possible non-Promise value to a Promise, you can simply wrap the function call in the Promise.resolve() method.
If the function’s return value is a Promise, Promise.resolve() will return that Promise object.
If the function’s return value is not a Promise, Promise.resolve() will return a Promise that will resolve that return value directly.
JavaScriptCopied!
Promise.resolve(func1()).then((value) => {
console.log(value); // Coding Beauty
});
Promise.resolve(func2()).then((value) => {
console.log(value); // JavaScript;
});
// does return Promise
function func1() {
return new Promise((resolve) => {
resolve('Coding Beauty');
});
}
// does NOT return Promise
function func2() {
return 'JavaScript';
}
Check if function is async
It’s also possible to check if a function is async, by checking if the constructor.name property of the function is 'AsyncFunction':
JavaScriptCopied!
console.log(isAsync(func1)); // false
console.log(isAsync(func2)); // true
console.log(isAsync(func3)); // false
function isAsync(func) {
return func.constructor.name === 'AsyncFunction';
}
// NOT async, but returns Promise
function func1() {
return new Promise((resolve) => {
resolve('Coding Beauty');
});
}
// async, returns Promise too
async function func2() {
return 100;
}
// NOT async, returns NON-Promise
function func3() {
return 'Coding Beauty';
}
Almost every object in JavaScript has a constructor property that returns a Function reference to the constructor function that created the object instance.
Note that this approach is not very reliable as the value of constructor.name is not fixed. It could easy be changed in a user-defined class to any value, including 'AsyncFunction':
JavaScriptCopied!
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
static name = 'AsyncFunction'
}
const person = new Person('Brandon', 'Evans');
console.log(isAsync(person)); // true (?!)
function isAsync(func) {
return func.constructor.name === 'AsyncFunction';
}