Skip to main content
hhow09's Blog

JavaScript Development Notes

Some gotchas I met in JS development.

1. Trace Call Stack [1] [2] #

function foo() {
  bar();
}

function bar() {
  baz();
}

function baz() {
  console.log(new Error().stack);
}

foo();

2. console.log an Object is pass by reference [3] #

Solution #


3. Initializing 2D array with Array.fill #

// filled each row with `same reference` of `new Array(4).fill(1)`.
const list = new Array(3).fill(new Array(4).fill(1));
// filled each row with `different reference` of `new Array(4).fill(1)`.
const list2 = new Array(3).fill(null).map(() => new Array(4).fill(1));

list[1][2] = 2;
list2[1][2] = 2;
console.log(list);
// false
//[
//  [ 1, 1, 2, 1 ],
//  [ 1, 1, 2, 1 ],
//  [ 1, 1, 2, 1 ]
//]
console.log(list2);
// correct
//[
//  [ 1, 1, 1, 1 ],
//  [ 1, 1, 2, 1 ],
//  [ 1, 1, 1, 1 ]
//]

4. Deep Copy v.s. Shallow Copy #

Shallow Copy #

  1. Array.prototype.slice()
  2. Object.assign({}, obj)
  3. Spread Syntax: A2 = {...A1}

Deep Copy #

  1. JSON.parse(JSON.stringify(object)).

    • If you do not use circular reference, Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types within your object, it is a very simple one liner to deep clone an object.
  2. with library: lodash - cloneDeep


5. Manipulate with floating-point number [4] #

JavaScript has a single and unpredictable number type, 64-bit floating point.

0.1 + 0.2 === 0.3; // false

function numbersCloseEnoughToEqual(n1, n2) {
  return Math.abs(n1 - n2) < Number.EPSILON;
}

numbersCloseEnoughToEqual(0.1 + 0.2, 0.3);

6. Key order of Object.keys(obj)? [5] #

ES5 #

  1. For each own enumerable property of O whose name String is P
  • Call the [[DefineOwnProperty]] internal method of array with arguments ToString(index), the PropertyDescriptor {[[Value]]: P, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.

  • Increment index by 1.

If an implementation defines a specific order of enumeration for the for-in statement, that same enumeration order must be used in step 5 of this algorithm.

ES6: #

const obj = {
  2: "integer: 2",
  foo: "string: foo",
  "01": "string: 01",
  1: "integer: 1",
  [Symbol("first")]: "symbol: first",
};

obj["0"] = "integer: 0";
obj[Symbol("last")] = "symbol: last";
obj["veryLast"] = "string: very last";

console.log(Reflect.ownKeys(obj));
// [ "0", "1", "2", "foo", "01", "veryLast", Symbol(first), Symbol(last) ]

7. Remove Duplicate Element in Array #

const chars = ["A", "B", "A", "C", "B"];

const uniqueChars = chars.filter((c, index) => chars.indexOf(c) === index);
//[ 'A', 'B', 'C' ]

8.DOM Element #

DOM Element is a special object #

var a = document.createElement("div");
typeof a; // "object"
Object.prototype.toString.call(a); // "[object HTMLDivElement]"
a.tagName; // "DIV"

DOM Element will produce global variable #

be careful for duplicate naming.

<div id="foo"></div>
console.log(foo); // HTML Element

9. using await inside setInterval is pointless #

async function getData (){
  return fetch("url...")
}
const timer = setInterval(
  await getData();
,1000)

above code can change into

async function getData() {
  return fetch("https://google.com");
}

async function sleep(ms) {
  return await new Promise((resolve) => setTimeout(resolve, ms));
}

function periodicGetData() {
  return new Promise(async (resolve, reject) => {
    if (some_condition) {
      resolve();
    }
    const res = await getData();
    if (res instanceof Error) {
      reject(res);
    }
    console.log("res", res);
    await sleep(1000);
    return periodicGetData();
  });
}
periodicGetData();

Reference #


  1. V8: Stack Trace API ↩︎

  2. MDN: Error.prototype.stack ↩︎

  3. MDN: Logging objects ↩︎

  4. You Don't Know JS ↩︎

  5. Property order is predictable in JavaScript objects since ES2015 ↩︎