Q: Parses URL Params as objects

Parse all parameters of an arbitrary URL as Object as fully and correctly as possible, paying attention to the processing of boundary conditions.

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], // Result {user: 'anonymous', id: [123, 456], // Result {user: 'anonymous', id: [123, 456], True, // not specifying worthy key convention is true} */
Copy the code

A:

function parseParam(url) {
  const paramsStr = /. + \? (. +) $/.exec(url)[1]; / / will be? I'm going to take the strings that follow
  const paramsArr = paramsStr.split('&'); // Store the string in an array, split by &
  let paramsObj = {};
  // Save params to an object
  paramsArr.forEach(param= > {
    if (/ = /.test(param)) { // Process parameters with value
      let [key, val] = param.split('='); // Separate 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)) { // Add a value if the object has a key
        paramsObj[key] = [].concat(paramsObj[key], val);
      } else { // If the object does not have this key, create the key and set the valueparamsObj[key] = val; }}else { // Process parameters without value
      paramsObj[param] = true; }})return paramsObj;
}
Copy the code

Template rendering

Q: Implement a simple template engine:

let template = 'I'm {{name}}, age {{age}}, sex {{sex}}';
let data = {
  name: 'name'.age: 18
}
render(template, data); // My name is name, age 18, gender undefined
Copy the code

The answer:

  • Simple implementation

    function render(template, data) {
      const reg = /\{\{(\w+)\}\}/; // The template string is regular
      if (reg.test(template)) { // Check whether there is a template string in the template
        const name = reg.exec(template)[1]; // Find the field of the first string in the current template
        template = template.replace(reg, data[name]); // Render the first template string
        return render(template, data); // Render recursively and return the rendered structure
      }
      return template; // If the template does not have a template string, return it directly
    }
    Copy the code
  • One-line code implementation

    function render(template, data) {
      return template.replace(new RegExp('{{(. *?) }} '.'g'), (match, key) => data[key.trim()]);
    }
    Copy the code
reference

A single line of code implements a simple template string replacement

Q: Implement a simple virtual DOM rendering

let domNode = { tagName: 'ul', props: { class: 'list' }, children: [{ tagName: 'li', children: ['item1'] }, { tagName: 'li', children: ['item1'] }] }; Dom <ul class="list"> <li>item1</li> </li> </li> </li>Copy the code

The answer:

function render(domNode) {
  if(! domNode)return document.createDocumentFragment();
  let $el
  if (typeof domNode === 'object') {
    $el = document.createElement(domNode.tagName);

    if (domNode.hasOwnProperty('props')) {
      for (let key indomNode.props) { $el.setAttribute(key, domNode.props[key]); }}if (domNode.hasOwnProperty('children')) {
      domNode.children.forEach(val= > {
        const$childEl = render(val); $el.appendChild($childEl); }}})else {
    $el = document.createTextNode(domNode);
  }

  return $el;
}
Copy the code

Q: String lookup

Use a basic traversal implementation to determine whether string A is contained in string B and return the first occurrence (-1 if not found).

Example:

a='34'; b='1234567'; / / return 2
a='35'; b='1234567'; / / return 1
a='355'; b='12354355'; / / return 5
isContain(a,b);
Copy the code

The answer:

function isContain(a, b) {
  for (let i in b) {
    if (a[0] === b[i]) {
      let tmp = true;
      for (let j in a) {
        if(a[j] ! == b[~~i + ~~j]) { tmp =false; }}if (tmp) {
        returni; }}}return - 1;
}
Copy the code

Q: Change an arbitrarily long number into a comma separated format

Example:

// Keep three decimal places
parseToMoney(1234.56); // return '1,234.56'
parseToMoney(123456789); / / return '123456789'
parseToMoney(1087654.321); / / return '1087654321'
Copy the code

A:

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 : ' ');
}
Copy the code

Q: The basic implementation of data binding

// Implement a method to add dynamic binding events to all properties of OBj, which will be triggered when the property value changes
let obj = {
  key_1: 1.key_2: 2
}
function func(key) {
  console.log(key + The value of 'has changed:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // The value of key_1 has changed: 2
obj.key_2 = 1; // The value of key_2 has changed: 1
Copy the code

A:

function bindData(obj, fn) {
  for (let key in obj) {
    Object.defineProperty(obj, key, {
      set(newVal) {
        if (this.value ! == newVal) {this.value = newVal;
          fn.call(obj, key);
        }
      },
      get() {
        return this.value; }}}})Copy the code

Q: Data structure processing

There is an ancestor tree json object. If a person has one son, the child is the son object, and if there are more than one son, the child is an array of son objects.

Implement a function that finds the names of all the people in the family who have multiple sons and outputs an array of names.

// Sample data
let data = {
  name: 'jack'.child: [{name: 'jack1' },
    {
      name: 'jack2'.child: [{
        name: 'jack2-1'.child: { name: 'jack2-1-1'}}, {name: 'jack2-2'}]}, {name: 'jack3'.child: { name: 'jack3-1'}}}]Copy the code

The answer:

  • Using a recursive

    function findMultiChildPerson(data) {
      let nameList = [];
    
      function tmp(data) {
        if (data.hasOwnProperty('child')) {
          if (Array.isArray(data.child)) {
            nameList.push(data.name);
            data.child.forEach(child= > tmp(child));
          } else {
            tmp(data.child);
          }
        }
      }
      tmp(data);
      return nameList;
    }
    Copy the code
  • non-recursive

    function findMultiChildPerson(data) {
      let list = [data];
      let nameList = [];
    
      while (list.length > 0) {
        const obj = list.shift();
        if (obj.hasOwnProperty('child')) {
          if (Array.isArray(obj.child)) {
            nameList.push(obj.name);
            list = list.concat(obj.child);
          } else{ list.push(obj.child); }}}return nameList;
    }
    Copy the code