Quick Links:
Note: I found about it in svelte’s docs here
The structuredClone method, which deep-clones JavaScript objects, has several potential drawbacks, despite its convenience:
Limited Browser Support: While structuredClone is widely supported in modern browsers, older browsers (like some versions of Internet Explorer) do not support it, which could be an issue for applications needing compatibility with legacy systems.
Performance Overhead for Large Objects: structuredClone may be slower than alternatives (such as manual deep cloning) when handling very large or complex objects, as it has to replicate each property and handle circular references. For simple objects, the performance difference may not be noticeable, but with deeply nested or large objects, it could lead to noticeable delays.
Serialization Constraints: structuredClone only works with data types that are serializable in JavaScript. This means it cannot clone objects with:
Loss of Prototypes and Methods: The cloning process strips away prototypes, methods, and non-enumerable properties, meaning that if you rely on methods or class instances, they won’t carry over to the cloned object. Only pure data objects (without methods) are fully compatible.
Potential for Silent Errors: Because it throws errors when encountering non-cloneable data types, developers need to catch these errors. Otherwise, structuredClone may fail silently if not handled, leading to debugging challenges.
Limited Support for Circular References: While it supports circular structures in arrays and objects, certain complex circular references may not clone as expected, requiring additional handling.
For cases that need method retention, prototype inheritance, or support for non-serializable values, alternative approaches, like libraries (e.g., Lodash’s cloneDeep), custom cloning functions, or JSON serialization (if limited to simple objects), might be more suitable.
Unlike the other three Math methods: Math.floor(), Math.ceil() and Math.round(), the way Math.trunc() works is very simple. It truncates (cuts off) the dot and the digits to the right of it, no matter whether the argument is a positive or negative number.
console.log(Math.trunc(13.37));
// Expected output: 13
console.log(Math.trunc(42.84));
// Expected output: 42
console.log(Math.trunc(0.123));
// Expected output: 0
console.log(Math.trunc(-0.123));
// Expected output: -0
Math.trunc(-Infinity); // -Infinity
Math.trunc("-1.123"); // -1
Math.trunc(-0.123); // -0
Math.trunc(-0); // -0
Math.trunc(0); // 0
Math.trunc(0.123); // 0
Math.trunc(13.37); // 13
Math.trunc(42.84); // 42
Math.trunc(Infinity); // Infinity
await
and catch
keywordsMy tests works too:
process.on("unhandledRejection", (err) => {
console.log('caught rejection')
console.log('error?', err)
})
async function main() {
throw 'rock paper scissor'
}
main()
# Output:
caught rejection
error? rock paper scissor
??=
, ||=
and &&=
operators// assings only if the variable is null or undefined
??=
// assigns if null, undefined or any other falsy value
||=
// assigns only if the value already exists
&&=
# Examples:
let car
car ??= 'bar'
// car is now 'bar'
let bat = ''
bat ||= 'something'
// now bat is 'something'
let cat = ' some test with spaces on both sides '
cat &&= cat.trim()
// now cat is just 'some test with spaces on both sides'
reduce
array methodLearn: reduce
method creates a item i.e, accumulator
and does not mutate the original array at all.
Source: A comment in this answer: Click here
let arr = [
{ name: 'John', contributions: 2 },
{ name: 'Mary', contributions: 4 },
{ name: 'John', contributions: 1 },
{ name: 'Mary', contributions: 1 }
];
// we reduce our `arr` array to get `reduced array` i.e., output
let output = arr.reduce(function(accumulator, cur) {
let found = accumulator.find((elem) => elem.name == cur.name);
if (found) found.contributions = found.contributions + cur.contributions;
else accumulator.push(cur);
return accumulator;
}, []);
console.log(output) // [{"name": "John","contributions": 3},{"name": "Mary","contributions": 5}]
Object.is(a,b)
instead of ===
to check if values are equal?Source: Click here
// pros of Object.is() method
Object.is(-0, +0); // => false
Object.is(NaN, NaN); // => true
// cons of tripple equality operator
-0 === +0; // => true
NaN === NaN; // => false
for..in
loop of string type?Yes, they are! This is unexpected to most people though, but typescript will sail your boat for sure. Love typescript!
No, but they can be explored using using object methods.
String act as array with index and values like that:
Object.assign()
TLDR: Its amazing. Source: Comment on SO Question Click here
const name = 'David'
const person = { name : 'sahil' }
// instead of doing
person.name = name
// ❤️ you can simply do
Object.assign(person, { name })
// Object.assign(window, { person }) // this is equivalent to `window.person = persons`
// ❤️
Object.assign(window, { person }).person // this prints updated value of `window.person`
import defaultExport, * as name from "module-name";
import defaultExport, { export1 } from "module-name";
const { default: myDefault, foo, bar } = await import('/modules/my-module.js');
// Anonymous
let myObject = {
field1: value1,
field2: value2
};
export {myObject as default};
// above export is equivalent to below:
export default {
field1: value1,
field2: value2
};
src: [Import in js | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) |
Source: Click here
// values/value.js
let a = 1;
let b = 2;
let c = 3;
export {a, b, c};
// values/index.js
import * as values from './value';
export default values;
export * from './value';
// index.js
import values, {a} from './values';
console.log(values, a); // {a: 1, b: 2, c: 3} 1
Desirable way: node --input-type=module test.js . Refer here for all ways to do this: [Enabling ESM |
Official Docs](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_enabling). Also, tho use node test.mjs if the former seems to much. And do read about the awesomeness of convention of file extensions standard which is also followed in browsers as well and thus actualy good for real. |
Parallel execution:
You can use Promise.all
or Promise.allSettled
way. See it on mdn docs.
Serial Execution (works in nodejs as well)
const tokens = ['dai', 'bat', 'rep', 'zrx']
const traders = ['trader1', 'trader2', 'trader3', 'trader4']
const get = async (tr, tk) => await new Promise((res) => setTimeout(() => res(tk + '+' + tr), 300))
async function main() {
console.log('----- Using for-of loops')
for (const tk of tokens) {
for (const tr of traders) {
const v = await get(tk, tr)
console.log(v)
}
}
console.log('----- Using simple for loops')
for (let i = 0; i < tokens.length; i++) {
const tk = tokens[i]
for (let j = 0; j < traders.length; j++) {
const tr = traders[j]
const v = await get(tk, tr)
console.log(v)
}
}
console.log('----- Using while loops')
let i = 0
while (i < tokens.length) {
const tk = tokens[i]
let j = 0
while (j < traders.length) {
const tr = traders[j]
const v = await get(tk, tr)
console.log(v)
j++
}
i++
}
console.log('----- Using for await (unnecessary')
for await (const tk of tokens) {
for await (const tr of traders) {
const v = await get(tk, tr)
console.log(v)
}
}
}
main()
// All of above outputs like that:
//
// OUTPUT:
// bat+trader2
// bat+trader3
// bat+trader4
// rep+trader1
// rep+trader2
// rep+trader3
// rep+trader4
// zrx+trader1
// zrx+trader2
// zrx+trader3
// zrx+trader4
Make async/await cleaner with simple if checks
async function fetchData({isBad}) {
try {
if (isBad) throw 'The request is not good...'
const data = 'result data...' // for e.g., `return await anyPromsieHere()`
return [data, null]
} catch (error) {
return [null, error]
}
}
async function main() {
// src: https://youtu.be/ITogH7lJTyE
const [data, error] = await fetchData({isBad: true}) //toggle isBad to toggle different behaviour of the api.
if (data) {
console.log('got data..')
}
if (error) {
console.log('there is some error with the api...')
}
}
main()
This might look like a overkill for any simple api but if you have only two three api’s and you need to check add try/catch for each of them in a single scope it all becomes whole messy to look at … but if you use something like..
const [userData, userError] = await fetchUserData({ isBad: true });
const [locationData, locationError] = await fetchLocationData({ isBad: true });
const [friendsData, friendsError] = await fetchFriendsData({ isBad: true });
Now you can simly put 6 if checks to check for what is actually error and you code actually gets out of control (i.e., *program control) LITERALLY.
Resources:
For await of
Note: forEach expects a synchronous function. forEach does not wait for promises. Make sure you are aware of the implications while using promises (or async functions) as forEach callback.
try{}catch(e){}
syntaxread more @ https://javascript.info/promise-api#summary
let b = () => Promise.reject(20)
await Promise.allSettled([b()])
// ouput: keyPoint: It never throws error(i.e., `reject("someErrorMessage")`. Yikes!
[
{
"status": "rejected",
"reason": 20
}
]
So, now you would be tempting to re-write all your previous `try{}catch(e){}` flavoured in a more if/else like manner, don't you .?
// I mean instead of writing:
try{
const res = await fetch('ss')
await res.json()
}catch(e){
console.log('Caught program control thief :LOL: ~sahil~\n', e)
}
// ouput:
Caught program control thief :LOL: ~sahil~
SyntaxError: Unexpected token < in JSON at position 0
// you can write more synchronouse looking code, e.g.,
let res = await fetch('ss')
let [settledRequest] = await Promise.allSettled([res.json()])
if(settledRequest.status === 'fulfilled') console.log('yikes, got value', settledRequest.value)
if(settledRequest.status === 'rejected') console.log('shit, got reason', settledRequest.reason)
// isn't that the way you wanted code to be written like from a long time...?
Promsise.all
vs. Promise.allSettled
(i.e., either resolved
or rejected
)let a = () => Promise.resolve(10)
let b = () => Promise.reject(20)
// Promise.allSettled
await Promise.allSettled([a(), b()])
// output: keyPoint: It never throws error so we can use it without try and catch(what a godly thing, isn't it ?).
[
{
"status": "fulfilled",
"value": 10
},
{
"status": "rejected",
"reason": 20
}
]
// Promise.all
try{
await Promise.all([a(), b()])
}catch(e){
console.log('boom', e)
}
// output:
boom 20