Handwritten interview questions on the front end

Please implement DOM2JSON, a function that can output a DOM node in JSON format

<div>
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>

put the top dom structure into the following JSON Format

{
  tag: 'DIV',
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}

The implementation code is as follows:

function dom2Json(domtree) {
  let obj = {};
  obj.name = domtree.tagName;
  obj.children = [];
  domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child)));
  return obj;
}

Convert to camelCase

var s1 = "get-element-by-id"

// Convert to getElementById

var f = function(s) {
    return s.replace(/-\w/g, function(x) {
        return x.slice(1).toUpperCase();
    })
}

Modify the key of a deeply nested object

// There is an object with a deep nesting level, and the key s are all in the form of a_b, which needs to be changed to the form of ab. Note that recursion cannot be used.

const a = {
  a_y: {
    a_z: {
      y_x: 6
    },
    b_c: 1
  }
}
// {
//   ay: {
//     az: {
//       yx: 6
//     },
//     bc: 1
//   }
// }

Method 1: Serialize JSON.stringify + regular matching

const regularExpress = (obj) => {
  try {
    const str = JSON.stringify(obj).replace(/_/g, "");
    return JSON.parse(str);
  } catch (error) {
    return obj;
  }
};;

Method 2: Recursive

const recursion = (obj) => {
  const keys = Object.keys(obj);
  keys.forEach((key) => {
    const newKey = key.replace(/_/g, "");
    obj[newKey] = recursion(obj[key]);
    delete obj[key];
  });
  return obj;
};

Summary of reduce usage

grammar

array.reduce(function(total, currentValue, currentIndex, arr), initialValue);
/*
  total: required. The initial value, or the return value after the calculation is completed.
  currentValue:  required. the current element.
  currentIndex:  optional. the index of the current element;                     
  arr:  optional. The array object to which the current element belongs.
  initialValue: optional. The initial value passed to the function is equivalent to the initial value of total.
*/

reduceRight() This method is actually the same as reduce(), except that the order of traversal is reversed, starting from the last item in the array and traversing forward to the first item

1. Array sum

const arr = [12, 34, 23];
const sum = arr.reduce((total, num) => total + num);

// Set the initial value to sum
const arr = [12, 34, 23];
const sum = arr.reduce((total, num) => total + num, 10);  // Summing with 10 as the initial value


// sum array of objects
var result = [
  { subject: 'math', score: 88 },
  { subject: 'chinese', score: 95 },
  { subject: 'english', score: 80 }
];
const sum = result.reduce((accumulator, cur) => accumulator + cur.score, 0); 
const sum = result.reduce((accumulator, cur) => accumulator + cur.score, -10);  // 10 points will be deducted from the total score

2. The maximum value of the array

const a = [23,123,342,12];
const max = a.reduce((pre,next)=>pre>cur?pre:cur,0); // 342

3. Array to object

var streams = [{name: 'technology', id: 1}, {name: 'design', id: 2}];
var obj = streams.reduce((accumulator, cur) => {accumulator[cur.id] = cur; return accumulator;}, {});

4. Flatten a two-dimensional array

var arr = [[1, 2, 8], [3, 4, 9], [5, 6, 10]];
var res = arr.reduce((x, y) => x.concat(y), []);

5. Array deduplication

The basic principle of implementation is as follows:

① initialize an empty array
② Find the first item in the array that needs to be deduplicated in the initialization array, if it cannot be found (it must not be found in the empty array), add the item to the initialization array
③ Find the second item in the array that needs to be deduplicated in the initialization array, if not found, continue to add the item to the initialization array
④ ......
⑤ The first in the array that needs to be deduplicated n The item is searched in the initialization array, if not found, the item is added to the initialization array
⑥ Return this initialized array
var newArr = arr.reduce(function (prev, cur) {
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);

6. Object array deduplication

const dedup = (data, getKey = () => { }) => {
    const dateMap = data.reduce((pre, cur) => {
        const key = getKey(cur)
        if (!pre[key]) {
            pre[key] = cur
        }
        return pre
    }, {})
    return Object.values(dateMap)
}

7. Find the number of occurrences of letters in a string

const str = 'sfhjasfjgfasjuwqrqadqeiqsajsdaiwqdaklldflas-cmxzmnha';

const res = str.split('').reduce((pre,next)=>{
 pre[next] ? pre[next]++ : pre[next] = 1
 return pre 
},{})
// result
-: 1
a: 8
c: 1
d: 4
e: 1
f: 4
g: 1
h: 2
i: 2
j: 4
k: 1
l: 3
m: 2
n: 1
q: 5
r: 1
s: 6
u: 1
w: 2
x: 1
z: 1

8. compose function

redux compose source code implementation

function compose(...funs) {
    if (funs.length === 0) {
        return arg => arg;
    }
    if (funs.length === 1) {
       return funs[0];
    }
    return funs.reduce((a, b) => (...arg) => a(b(...arg)))
}

Convert object array list into tree structure (processing menu)

[
    {
        id: 1,
        text: 'node 1',
        parentId: 0 //0 is used here as the top-level node
    },
    {
        id: 2,
        text: 'node 1_1',
        parentId: 1 //Use this field to determine the child parent
    }
    ...
]

Turn into
[
    {
        id: 1,
        text: 'node 1',
        parentId: 0,
        children: [
            {
                id:2,
                text: 'node 1_1',
                parentId:1
            }
        ]
    }
]

The implementation code is as follows:

function listToTree(data) {
  let temp = {};
  let treeData = [];
  for (let i = 0; i < data.length; i++) {
    temp[data[i].id] = data[i];
  }
  for (let i in temp) {
    if (+temp[i].parentId != 0) {
      if (!temp[temp[i].parentId].children) {
        temp[temp[i].parentId].children = [];
      }
      temp[temp[i].parentId].children.push(temp[i]);
    } else {
      treeData.push(temp[i]);
    }
  }
  return treeData;
}

How to generate a non-repetitive random array of length n in the specified data source? There are several methods. What is the time complexity (bytes)

The first version has a time complexity of O(n^2)

function getTenNum(testArray, n) {
  let result = [];
  for (let i = 0; i < n; ++i) {
    const random = Math.floor(Math.random() * testArray.length);
    const cur = testArray[random];
    if (result.includes(cur)) {
      i--;
      break;
    }
    result.push(cur);
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);

Version 2 Notation method / custom attribute method Time complexity is O(n)

function getTenNum(testArray, n) {
  let hash = {};
  let result = [];
  let ranNum = n;
  while (ranNum > 0) {
    const ran = Math.floor(Math.random() * testArray.length);
    if (!hash[ran]) {
      hash[ran] = true;
      result.push(ran);
      ranNum--;
    }
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);

The third version of the exchange method has a time complexity of O(n)

function getTenNum(testArray, n) {
  const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; i++) {
    debugger;
    const ran = Math.floor(Math.random() * (cloneArr.length - i));
    result.push(cloneArr[ran]);
    cloneArr[ran] = cloneArr[cloneArr.length - i - 1];
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

It is worth mentioning that the exchange method is used when manipulating arrays. This idea is very common in algorithms.

The final version deletes while traversing, and the time complexity is O(n)

function getTenNum(testArray, n) {
  const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; ++i) {
    const random = Math.floor(Math.random() * cloneArr.length);
    const cur = cloneArr[random];
    result.push(cur);
    cloneArr.splice(random, 1);
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

refer to Detailed answers to front-end advanced interview questions

Determine whether the bracket string is valid (Xiaomi)

topic description

Given a given only '(',')','{','}','[',']' String s ,Determines whether a string is valid.

A valid string must satisfy:
- An opening parenthesis must be closed with a closing parenthesis of the same type.
- Opening parentheses must be closed in the correct order.

Example 1:

enter: s = "()"
output: true

Example 2:

enter: s = "()[]{}"
output: true

Example 3:

enter: s = "(]"
output: false

Answer

const isValid = function (s) {
  if (s.length % 2 === 1) {
    return false;
  }
  const regObj = {
    "{": "}",
    "(": ")",
    "[": "]",
  };
  let stack = [];
  for (let i = 0; i < s.length; i++) {
    if (s[i] === "{" || s[i] === "(" || s[i] === "[") {
      stack.push(s[i]);
    } else {
      const cur = stack.pop();
      if (s[i] !== regObj[cur]) {
        return false;
      }
    }
  }

  if (stack.length) {
    return false;
  }

  return true;
};

Implements a Promise scheduler with parallel constraints

Title description: JS implements an asynchronous scheduler Scheduler with concurrency restrictions, ensuring that there are at most two tasks running at the same time

addTask(1000,"1");
 addTask(500,"2");
 addTask(300,"3");
 addTask(400,"4");
 The output order is: 2 3 1 4

 The entire complete execution process:

At the beginning, the two tasks 1 and 2 start to execute
500ms When , task 2 is executed, output 2, and task 3 starts to execute
800ms When , task 3 is executed, output 3, and task 4 starts to execute
1000ms When 1 task is executed, 1 is output, and only 4 tasks are left to execute
1200ms When , 4 tasks are executed, output 4

The implementation code is as follows:

class Scheduler {
  constructor(limit) {
    this.queue = [];
    this.maxCount = limit;
    this.runCounts = 0;
  }
  add(time, order) {
    const promiseCreator = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(order);
          resolve();
        }, time);
      });
    };
    this.queue.push(promiseCreator);
  }
  taskStart() {
    for (let i = 0; i < this.maxCount; i++) {
      this.request();
    }
  }
  request() {
    if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
      return;
    }
    this.runCounts++;
    this.queue
      .shift()()
      .then(() => {
        this.runCounts--;
        this.request();
      });
  }
}
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
  scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();

implement a queue

Queue based on linked list structure

const LinkedList = require('./Implement a linked list structure')

// Use linked lists to simulate queues by default using arrays for better performance
class Queue {
  constructor() {
    this.ll = new LinkedList()
  }
  // add to queue
  offer(elem) {
    this.ll.add(elem)
  }
  // view the first
  peek() {
    return this.ll.get(0)
  }
  // Queues can only be removed from the head
  remove() {
    return this.ll.remove(0)
  }
}

var queue = new Queue()

queue.offer(1)
queue.offer(2)
queue.offer(3)
var removeVal = queue.remove(3)

console.log(queue.ll,'queue.ll')
console.log(removeVal,'queue.remove')
console.log(queue.peek(),'queue.peek')

Convert tree structure to list (processing menu)

[
    {
        id: 1,
        text: 'node 1',
        parentId: 0,
        children: [
            {
                id:2,
                text: 'node 1_1',
                parentId:1
            }
        ]
    }
]
Turn into
[
    {
        id: 1,
        text: 'node 1',
        parentId: 0 //0 is used here as the top-level node
    },
    {
        id: 2,
        text: 'node 1_1',
        parentId: 1 //Use this field to determine the child parent
    }
    ...
]

The implementation code is as follows:

function treeToList(data) {
  let res = [];
  const dfs = (tree) => {
    tree.forEach((item) => {
      if (item.children) {
        dfs(item.children);
        delete item.children;
      }
      res.push(item);
    });
  };
  dfs(data);
  return res;
}

Implement thousands separator

// three decimal places
parseToMoney(1234.56); // return '1,234.56'
parseToMoney(123456789); // return '123,456,789'
parseToMoney(1087654.321); // return '1,087,654.321'
function parseToMoney(num) {
  num = parseFloat(num.toFixed(3));
  let [integer, decimal] = String.prototype.split.call(num, '.');
  integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
  return integer + '.' + (decimal ? decimal : '');
}

The longest non-repeating substring of a string

topic description

given a string s ,Please find the length of the longest substring that does not contain repeated characters.


Example 1:

enter: s = "abcabcbb"
output: 3
 explain: Since the longest substring without repeating characters is "abc",So its length is 3.

Example 2:

enter: s = "bbbbb"
output: 1
 explain: Since the longest substring without repeating characters is "b",So its length is 1.

Example 3:

enter: s = "pwwkew"
output: 3
 explain: Since the longest substring without repeating characters is "wke",So its length is 3.
     Note that your answer must be the length of the substring,"pwke" is a subsequence, not a substring.

Example 4:

enter: s = ""
output: 0

Answer

const lengthOfLongestSubstring = function (s) {
  if (s.length === 0) {
    return 0;
  }

  let left = 0;
  let right = 1;
  let max = 0;
  while (right <= s.length) {
    let lr = s.slice(left, right);
    const index = lr.indexOf(s[right]);

    if (index > -1) {
      left = index + left + 1;
    } else {
      lr = s.slice(left, right + 1);
      max = Math.max(max, lr.length);
    }
    right++;
  }
  return max;
};

Parses URL Params into an object

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* result
{ user: 'anonymous',
  id: [ 123, 456 ], // Repeated key s should be assembled into an array, and those that can be converted into numbers should be converted into digital types
  city: 'Beijing', // Chinese needs to be decoded
  enabled: true, // unspecified value key convention is true
}
*/
function parseParam(url) {
  const paramsStr = /.+\?(.+)$/.exec(url)[1]; // Take out the string after the ?
  const paramsArr = paramsStr.split('&'); // Split the string with & and store it in an array
  let paramsObj = {};
  // store params into object
  paramsArr.forEach(param => {
    if (/=/.test(param)) { // handle arguments with value
      let [key, val] = param.split('='); // Split key and value
      val = decodeURIComponent(val); // decoding
      val = /^\d+$/.test(val) ? parseFloat(val) : val; // Determine whether to convert to a number

      if (paramsObj.hasOwnProperty(key)) { // If the object has a key, add a value
        paramsObj[key] = [].concat(paramsObj[key], val);
      } else { // If the object does not have this key, create the key and set the value
        paramsObj[key] = val;
      }
    } else { // handle arguments without a value
      paramsObj[param] = true;
    }
  })

  return paramsObj;
}

Please implement an add function that satisfies the following functions

add(1);             // 1
add(1)(2);      // 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
function add(...args) {
  // Declare a function inside, save and collect all parameter values ​​​​using the characteristics of closure
  let fn = function(...newArgs) {
   return add.apply(null, args.concat(newArgs))
  }

  // Using the feature of toString implicit conversion, when the last execution is performed, the implicit conversion is performed, and the final value is calculated and returned
  fn.toString = function() {
    return args.reduce((total,curr)=> total + curr)
  }

  return fn
}

Test site:

  • Use closures and have a deep understanding of JavaScript's scope chain (prototype chain)
  • Override the toSting() method of the function
// To test, call the toString method to trigger the evaluation

add(1).toString();             // 1
add(1)(2).toString();      // 3
add(1)(2)(3).toString();// 6
add(1)(2, 3).toString(); // 6
add(1, 2)(3).toString(); // 6
add(1, 2, 3).toString(); // 6

Implement the chunk method of lodash -- the array is split according to the specified length

topic

/**
 * @param input
 * @param size
 * @returns {Array}
 */
_.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]

_.chunk(['a', 'b', 'c', 'd'], 5)
// => [['a', 'b', 'c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 0)
// => []

accomplish

function chunk(arr, length) {
  let newArr = [];
  for (let i = 0; i < arr.length; i += length) {
    newArr.push(arr.slice(i, i + length));
  }
  return newArr;
}

Determine whether it is a phone number

function isPhone(tel) {
    var regx = /^1[34578]\d{9}$/;
    return regx.test(tel);
}

Implement the getValue/setValue function to get the value corresponding to the path

// example
var object = { a: [{ b: { c: 3 } }] }; // path: 'a[0].b.c'
var array = [{ a: { b: [1] } }]; // path: '[0].a.b[0]'

function getValue(target, valuePath, defaultValue) {}

console.log(getValue(object, "a[0].b.c", 0)); // output 3
console.log(getValue(array, "[0].a.b[0]", 12)); // output 1
console.log(getValue(array, "[0].a.b[0].c", 12)); // output 12

accomplish

/**
 * Tests for a property match
 */
export function testPropTypes(value, type, dev) {
  const sEnums = ['number', 'string', 'boolean', 'undefined', 'function']; // NaN
  const oEnums = ['Null', 'Object', 'Array', 'Date', 'RegExp', 'Error'];
  const nEnums = [
    '[object Number]',
    '[object String]',
    '[object Boolean]',
    '[object Undefined]',
    '[object Function]',
    '[object Null]',
    '[object Object]',
    '[object Array]',
    '[object Date]',
    '[object RegExp]',
    '[object Error]',
  ];
  const reg = new RegExp('\\[object (.*?)\\]');

  // Exact match pattern, type should pass something like format [object Window] [object HTMLDocument] ...
  if (reg.test(type)) {
    // Exclude 12 types of nEnums
    if (~nEnums.indexOf(type)) {
      if (dev === true) {
        console.warn(value, 'The parameter type belongs to one of 12 types: number string boolean undefined Null Object Array Date RegExp function Error NaN');
      }
    }

    if (Object.prototype.toString.call(value) === type) {
      return true;
    }

    return false;
  }
}
const syncVarIterator = {
  getter: function (obj, key, defaultValue) {
    // outcome variable
    const defaultResult = defaultValue === undefined ? undefined : defaultValue;

    if (testPropTypes(obj, 'Object') === false && testPropTypes(obj, 'Array') === false) {
      return defaultResult;
    }

    // The result variable, which temporarily points to the reference held by obj, may be continuously modified later
    let result = obj;

    // get know value
    try {
      // Parse attribute hierarchy sequence
      const keyArr = key.split('.');

      // Iterate over obj object properties
      for (let i = 0; i < keyArr.length; i++) {
        // If there is a corresponding value for the i-th layer attribute, then iterate over the attribute value
        if (result[keyArr[i]] !== undefined) {
          result = result[keyArr[i]];

          // Returns undefined if not present
        } else {
          return defaultResult;
        }
      }
    } catch (e) {
      return defaultResult;
    }

    // return the fetched result
    return result;
  },
  setter: function (obj, key, val) {
    // Returns undefined if obj does not exist
    if (testPropTypes(obj, 'Object') === false) {
      return false;
    }

    // The result variable, which temporarily points to the reference held by obj, may be continuously modified later
    let result = obj;

    try {
      // Parse attribute hierarchy sequences
      const keyArr = key.split('.');

      let i = 0;

      // Iterate over obj object properties
      for (; i < keyArr.length - 1; i++) {
        // If the value corresponding to the i-th layer attribute does not exist, it is defined as an object
        if (result[keyArr[i]] === undefined) {
          result[keyArr[i]] = {};
        }

        // If the value corresponding to the i-th layer attribute is not an instance of Object (Object), an error is thrown
        if (!(result[keyArr[i]] instanceof Object)) {
          throw new Error('obj.' + keyArr.splice(0, i + 1).join('.') + 'is not Object');
        }

        // Iterate over the layer property values
        result = result[keyArr[i]];
      }

      // set attribute value
      result[keyArr[i]] = val;

      return true;
    } catch (e) {
      return false;
    }
  },
};

Use promise s to achieve

Create enhancedObject function

const enhancedObject = (target) =>
  new Proxy(target, {
    get(target, property) {
      if (property in target) {
        return target[property];
      } else {
        return searchFor(property, target); //In actual use, the value should be reset
      }
    },
  });

let value = null;
function searchFor(property, target) {
  for (const key of Object.keys(target)) {
    if (typeof target[key] === "object") {
      searchFor(property, target[key]);
    } else if (typeof target[property] !== "undefined") {
      value = target[property];
      break;
    }
  }
  return value;
}

Use the enhancedObject function

const data = enhancedObject({
  user: {
    name: "test",
    settings: {
      theme: "dark",
    },
  },
});

console.log(data.user.settings.theme); // dark
console.log(data.theme); // dark

After the above code runs, the console will output the following code:

dark
dark

By observing the above output results, we can know that using the object processed by the enhancedObject function, we can easily access the deep properties inside the ordinary object.

implement bind

What to do to implement bind

  • Return a function, bind this, and pass preset parameters
  • The function returned by bind can be used as a constructor. Therefore, when used as a constructor, this should be invalidated, but the parameters passed in are still valid
// Implementation of mdn
if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          // When this instanceof fBound === true, it means that the returned fBound is called as a new constructor
          return fToBind.apply(this instanceof fBound
                 ? this
                 : oThis,
                 // Get the parameter passed when calling (fBound). The function parameter returned by bind is often passed in this way
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // maintain prototype relationship
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    // The following line of code makes fBound.prototype an instance of fNOP, so
    // If the returned fBound is used as the constructor of new, the new object generated by new is passed to fBound as this, and the __proto__ of the new object is an instance of fNOP
    fBound.prototype = new fNOP();

    return fBound;
  };
}

Render tens of thousands of data without getting stuck on the page

When rendering large data, use createDocumentFragment and requestAnimationFrame reasonably, and divide the operation into small pieces for execution.

setTimeout(() => {
  // Insert 100,000 pieces of data
  const total = 100000;
  // data inserted once
  const once = 20;
  // Number of times required to insert data
  const loopCount = Math.ceil(total / once);
  let countOfRender = 0;
  const ul = document.querySelector('ul');
  // How to add data
  function add() {
    const fragment = document.createDocumentFragment();
    for(let i = 0; i < once; i++) {
      const li = document.createElement('li');
      li.innerText = Math.floor(Math.random() * total);
      fragment.appendChild(li);
    }
    ul.appendChild(fragment);
    countOfRender += 1;
    loop();
  }
  function loop() {
    if(countOfRender < loopCount) {
      window.requestAnimationFrame(add);
    }
  }
  loop();
}, 0)

Implement a JSON.parse

JSON.parse(text[, reviver])

Used to parse JSON strings and construct JavaScript values ​​or objects described by strings. An optional reviver function is provided to perform transformations (operations) on the resulting object before returning

The first one: call eval directly

function jsonParse(opt) {
    return eval('(' + opt + ')');
}
jsonParse(jsonStringify({x : 5}))
// Object { x: 5}
jsonParse(jsonStringify([1, "false", false]))
// [1, "false", falsr]
jsonParse(jsonStringify({b: undefined}))
// Object { b: "undefined"}

Avoid using eval unnecessarily. eval() is a dangerous function, and the code it executes has the rights of the executor. If the string code you run with eval() is manipulated and modified by a malicious party (someone with bad intentions), you could end up running malicious code on the user's computer with the permissions of your webpage/extension. It will execute JS code and has XSS vulnerability.

If you only want to remember this method, you have to verify the parameter json.

var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
if (
    rx_one.test(
        json
            .replace(rx_two, "@")
            .replace(rx_three, "]")
            .replace(rx_four, "")
    )
) {
    var obj = eval("(" +json + ")");
}

The second type: Function

Core: Function has the same string parameter characteristics as eval

var func = new Function(arg1, arg2, ..., functionBody);

In the actual application of converting JSON, only need to do

var jsonStr = '{ "age": 20, "name": "jack" }'
var json = (new Function('return ' + jsonStr))();

Both eval and Function can dynamically compile js code, but it is not recommended to use it in actual programming

Tags: Javascript

Posted by influx on Mon, 13 Feb 2023 07:58:11 +0530