Implement lazyman

 class LazyManClass {
      constructor(name) {
        this.taskList = [];
        this.name = name;
        this.taskList.push(() = > {
          console.log(`Hi! This is ${name}! `);
          this.run();
        });
        setTimeout(() = > {
          this.run();
        }, 0);
      }
      sleepFirst(time) {
        let fn = () = > {
          setTimeout(() = > {
            console.log(` sleep first${time}Seconds... `);
            this.run();
          }, time * 1000);
        };
        this.taskList.unshift(fn);
        return this;
      }
      eat(name) {
        let fn = () = > {
          console.log(`I am eating ${name}`);
          this.run();
        };
        this.taskList.push(fn);
        return this;
      }
      sleep(time) {
        let fn = () = > {
          setTimeout(() = > {
            console.log(` slept${time}Seconds... `);
            this.run();
          }, time * 1000);
        };
        this.taskList.push(fn);
        return this;
      }
      run() {
        let fn = this.taskList.shift(); fn && fn(); }}function LazyMan(name) {
      return new LazyManClass(name);
    }
    LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(2).sleep(10).eat('junk food');
Copy the code

How is the Jquery selector implemented

    (function (window.undefined) {
      var rootjQuery = window.document;
      var jQuery = (function () {
        var jQuery = function (selector, context) {
          return new jQuery.fn.init(selector, context, rootjQuery);
        };

        jQuery.fn = jQuery.prototype = {
          construct: jQuery,
          init: function (selector, context, rootjQuery) {
            var that = this;
            that.ele = null;
            that.value = ' ';
            if (selector.charAt(0) = = =The '#') {
              console.log(selector);
              that.ele = document.getElementById(selector.slice(1));
            }
            that.getValue = function () {
              that.value = that.ele ? that.ele.innerHTML : 'No value';
              return that;
            };
            that.showValue = function () {
              returnthat.value; }; }}; jQuery.fn.init.prototype = jQuery.fn;returnjQuery; }) ();window.jQuery = window.$ = jQuery; }) (window);
Copy the code

How to improve performance by injecting 500,000 Li into a page?

Handwriting lazy loading (consider anti-shake and reloading issues)

    class lazyImage {
      constructor(selector) {
        this._throttleFn = null;
        this.imageElements = Array.prototype.slice.call(document.getElementsByTagName(selector));

        this.init();
      }

      init() {
        this.initShow();
        this._throttleFn = this.throttle(this.initShow);
        window.addEventListener('scroll'.this._throttleFn.bind(this));
      }

      initShow() {
        let len = this.imageElements.length;
        for (let i = 0; i < len; i++) {
          let imageElement = this.imageElements[i];
          const rect = imageElement.getBoundingClientRect();
          // Load images when they appear in view
          if (rect.top < document.documentElement.clientHeight) {
            imageElement.src = imageElement.dataset.src;
            imageElement.removeAttribute('data-src');
            imageElement.style.display = 'block';
            Array.prototype.splice.call(this.imageElements, i, 1);
            len--;
            i--;

            if (this.imageElements.length === 0) {
              // Remove the scroll event listener if all loads are complete
              document.removeEventListener('scroll'.this._throttleFn); }}}}throttle(fn, delay = 15) {
        if (typeoffn ! = ='function') {
          throw new Error('this is not a function');
        }

        let isStart = false;

        return function () {
          const _this = this;
          if (isStart) {
            return;
          }
          isStart = true; // Start is initialized once

          / * * *@description Use timer callback to control start flow status * */
          setTimeout(() = > {
            fn.apply(_this, arguments); // Make sure this refers to the current caller input
            isStart = false; }, delay); }; }}new lazyImage('img');
Copy the code

Difference between setTimeout and requestAnimationFrame

setTimeout

  • You need to set the interval
  • The interval is imprecise and may be blocked by other tasks
  • Implementing animations that execute after a specified time, regardless of whether the page is visible, wastes system resources
  • If the interval of animation is set too short, there will be excessive rendering and a lot of resources may be lost frames

requestAnimationFrame

  • You don’t need to set time intervals
  • Elements invisible do not cause backflow or redraw
  • Redraw a web page by frame. This method tells the browser that you want to animate and asks the browser to call a function to update the animation before the next redraw.
  • It is up to the system to determine the execution mechanism of the callback function. The callback function is added to the event queue and the browser automatically optimizes the method invocation at runtime.
  • CancelAnimationFrame (RequestAnimationFrame(callback)) cancelAnimationFrame(Callback)
  • If the page is not active, open another TAB and the current page will stop requestAnimationFrame and the animation will be paused automatically, saving CPU overhead

Juejin. Cn/post / 684490…

Ajax is different from FETCH

Ajax is essentially an XMLHttpRequest

  var xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.responseType = 'json';

  xhr.onload = function () {
    console.log(xhr.response);
  };

  xhr.onerror = function () {
    console.log('Oops, error');
  };

  xhr.send();
Copy the code

Methods on the fetch Window

  • A method of window
  • Fetch is not supported by Internet Explorer
  • The default is a GET request, which can be configured with {method: ‘POST ‘}
  • The fetch(URL, {credentials: ‘include’}) will not accept or send cookies by default.
  • The FETCH request is not considered to be an error if the HTTP return is not 200. For example, the server does not reject the 400,500 error code. The FETCH is rejected only when the request cannot be completed due to a network error
  // The first argument is the request URL
  // The second optional argument controls different init objects
  // Returns a promise by default
  var promise = fetch('http://localhost:3000/news', {
    method: 'get'
  })
    .then(function (response) {
      return response.json();
    })
    .catch(function (err) {
      // Error :(
    });
  promise
    .then(function (data) {
      console.log(data);
    })
    .catch(function (error) {
      console.log(error);
    });


  / / instance
  onfetch = () = > {
    window.fetch('http://localhost:8081').then(res= > console.log(res)).then;
    BodyUsed: false headers: headers {} OK: true redirected: false status: 200 statusText: "OK" type: "cors" url: "http://localhost:8081/" __proto__: Response * */
  };


  // node starts the service
  http
  .createServer((req, res) = > {
    // const [path, query] = req.url.split('? ')
    // const params = qs.parse(query, { ignoreQueryPrefix: true })
    console.log('The request has begun.')
    res.writeHead(300, {
      'Content-Type': 'text/javascript'.'Access-Control-Allow-Origin': The '*'.'Access-Control-Allow-Methods': 'PUT, GET, POST, DELETE, OPTIONS',})setTimeout(() = > {
      res.end('levi')},3000)
  })
  .listen(8081)

Copy the code

Write an addition function (sum) that supports both sum(x,y) and sum(x)(y)

  function currying(func, ... args) {
    if (args.length >= func.length) {
      returnfunc(... args); }return function (. args2) {
      returncurrying(func, ... args, ... args2); }; }function add(num1, num2) {
    return num1 + num2;
  }
Copy the code

JS implements an asynchronous Scheduler with concurrency limits, ensuring that up to two tasks can be run simultaneously. Refine the Scheduler class in the code so that the following programs output correctly

// JS implements an asynchronous Scheduler with concurrency limits, which ensures that up to two tasks can run simultaneously. Refine the Scheduler class in the code so that the following programs output correctly.
    class Scheduler {
      constructor() {
        this.taskList = [];
        this.count = 0;
      }

      add(promiseCreate) {
        return new Promise(resolve= > {
          this.taskList.push({
            creator: promiseCreate,
            resolve
          });

          this.run();
        });
      }

      run() {
        if (this.count >= 2) {
          return;
        }

        const task = this.taskList.shift();
        if (task) {
          this.count++;
          task.creator().then(res= > {
            this.count--;
            task.resolve();
            this.run(); }); }}}const timerPromise = (timer = 1000) = > {
      return new Promise(resolve= >
        setTimeout(() = > {
          resolve();
        }, timer)
      );
    };

    const s = new Scheduler();

    const addTask = (timer, data) = > {
      s.add(() = > timerPromise(timer)).then(() = > console.log(data));
    };
    addTask(1000.'1');
    addTask(500.'2');
    addTask(300.'3');
    addTask(400.'4');
    // output: 2 3 1 4
    // At the beginning, tasks 1 and 2 are queued
    // At 500ms, 2 completes, output 2, and task 3 enters the queue
    // at 800ms, 3 is complete, 3 is output, 4 is queued
    // At 1000ms, 1 is complete and 1 is output
    // at 1200ms, 4 is complete, output 4
Copy the code

Flat [1,2,3,[4,5,[6,7]]] -> [1,2,3,4,5,6,7]

/ / recursion
function flat(arr, prev) {
	let result = prev || []
  
  for(let i=0; i<arr.length; i++) {
  	if (Array.isArray(arr[i])) {
        result.concat(flat(arr[i], result))
    } else {
    	result.push(arr[i])
    }
  }
  
  return result
}

/ / recursive reduce
function flat (arr) {
	return arr.reduce((pre, cur) = > {
  	return pre.concat(Array.isArray(cur) ? flat(cur) : cur)
  }, [])
}

// while 
// while 
function flat (arr) {
	while (arr.some(Array.isArray)) { arr = [].concat(... arr) }return arr
}

Copy the code

Go from a one-dimensional array to a two-dimensional array

function reflat (arr, len) {
  let result = []

  let loopNums = Math.ceil(arr.length/len)

  for (let i = 0; i < loopNums; i++) {
    result.push(arr.slice(i*len, (i+1) * len))
  }

  return(result)
}
Copy the code

Const repeatFunc = repeat(alert, 4, 3000); RepeatedFunc (” hellWorld “) will alert HELLOWorld three times each time

  function repeat(func, num, time) {
  var flag = 1;
  return function timer(str) {
    func(str)
    setTimeout(() = > {
      flag++
      if(flag <= num) { timer(str) } }, time); }}Copy the code

What does script async do

Normally, scripts without any imported attributes have the following properties

  • Js scripts are divided into Fetch, parse and Execution.
  • Loading of js scripts. Parsing and execution blocks DOM tree rendering, so they are typically placed at the end

Defer and Async have the following similarities and differences

  • All belong to asynchronous load scripts
  • Defer will not be executed until DOM parsing is complete after loading, but before documentContentLoaded
async

Requests to scripts are asynchronous and do not block HTML parsing. Once the network request results are in, HMTL pauses parsing and lets JS parse and execute the code

If the HTML parsing is completed after the async request is issued, async has no effect

defer

The script loads asynchronously, and the request for the script is asynchronous. It does not block the browser from parsing the HMTL. Once the request is returned, if the HTML parsing is not complete, the browser does not parse and execute the javascript code that returns the result

If multiple defer tags exist, they are parsed in the order they are introduced, without affecting mutual U dependencies

Usage scenarios
  • If the script is modular and does not have dependencies, use Async
  • If your script relies on another script, use defer
  • If the script is small and the asynchronous script depends on it, use an inline script with no attributes

Handwritten regular expression to determine the phone number

// Mobile phone number: match the phone number starting with 1 and the second tree is 3-9
const reg = /^1[3-9]\d{9}$/ig; 

// Landline number for example: (0511-4405222, 021-87888822)
const reg = /\d{3}-\d{8}|\d{4}-\d{7}/ig; 
Copy the code

Js to thousandths

  // Object.prototype.toLocaleString
  const number = 123456789;
  console.log(number.toLocaleString()) / / 123456789


  The slice() method returns the selected element from an existing array, intercepting a method of the array
  function toThousandsNum(num) {
    var num = (num || 0).toString(),
      result = ' ';

    while (num.length > 3) {
      // The array slice method is used here. If it is negative, it specifies the position from the end of the array
      result = ', ' + num.slice(-3) + result;
      num = num.slice(0, num.length - 3);
    }
    // If the number begins with 0, no comma is required
    if (num) {
      result = num + result;
    }
    return result;
  }

  console.log(toThousandsNum(123456789123)); / / 123456789123

  // The array is traversed from the end
  function toThousandsNum(num) {
    let count = 1;
    let result = ' ';
    let price_arr = price.toString().split(' ');

    for (let i = price_arr.length - 1; i >= 0; i--) {
      result = `${price_arr[i]}${result}`;
      if (count % 3= = =0&& i ! = =0) {
        result = `,${result}`;
      }

      count++;
    }

    return result;
  }

  / / reverse transformation
  return price
  .toString()
  .split(' ')
  .reverse()
  .reduce((prev, cur, index) = > {
    return index % 3= = =0 ? `${cur}.${prev}` : `${cur}${prev}`;
  });

  console.log(toThousandsNum(123456789123)); / / 123456789123
Copy the code

sum(1)(2)(3).valueof()

  function add() {
    let args = [...arguments];
    function _sum() { args.push(... arguments);return _sum;
    }

    // Call valueOf and toString, which is overwritten first
    _sum.toString = function () {
      return args.reduce((prev, cur) = > prev + cur, 0);
    };
    return _sum;
  }
Copy the code
  function sum() {
    const args = [...arguments];
    function sum_backup() { args.push(... arguments);return sum_backup;
    }

    sum_backup.valueof = () = > {
      return args.reduce((prev, cur) = > prev + cur);
    };

    return sum_backup;
  }

  console.log(sum(1) (2) (3) (4).valueof());
Copy the code

Will setTimeout be executed on time?

SetTimeout is a macro task. The current macro task event can be executed only after the synchronization task, the micro task in the event queue, and the macro task at the top of the order are completed

SetTimeout is an asynchronous macro task. When setTimeout is executed, the callback function is put into the macro task queue after the specified time. However, if the main thread has a lot of synchronous code waiting to execute, or there are many tasks waiting to execute before the microtask queue and the current macro task queue, the setTimeout callback function will not be executed until they are completed. Therefore, there is no guarantee that the callback function will be executed immediately at the time specified in setTimeout

  setTimeout(function() {
    console.log("Timer execution") // Execute after a few seconds
  }, 0)


  for (var i = 0; i < 1000000000; i++) {
    if (i == 999999999) {
      console.log(i); }}Copy the code

Difference between hash route and history route

  • The hash mode updates the page URL by changing the anchor (#) and does not trigger a page reload. We can listen for hash changes with window.onhashchange. Changing the hash does not change the page path, and refreshing the page has no impact
  • History mode is a refreshing jump to a page by calling a series of methods on the window.history object. If you change the pathname, refreshing the page will request the server at the current path, which may result in a 404 condition
hash
  • You can change the URL, but it does not trigger a page reload (the hash change is logged in window.hisotry) and therefore is not an HTTP request, so this pattern is not conducive to SEO optimization
  • You can only change the part after #, so you can only jump to the URL of the same document as the current URL
  • Urls can only be changed by strings
  • Use window.onhashchange to listen for changes to the hash to implement a refresh free jump
  window.addEventListener('hashchange'.() = > {console.log(window.location.hash)})
Copy the code
history
  • The new URL can be any URL of the same origin as the current URL, or it can be the same as the current URL, but this will record a repeat operation on the stack
  • The stateObject parameter allows you to add any type of data to a record
  • Additional title attribute can be set for subsequent use
  • The pushState and replaceState commands enable this function
  • Server support is required, otherwise if you change history, refreshing the page will result in 404

Window provides popState to listen for history change

  • The user clicks the browser’s forward and back actions
  • Manually call the back, forward, and go methods of history

Can’t listen

  • window.history.pushState()
  • window.history.replaceState()
  window.history.pushState(initialObject, title, url)
  window.history.replaceState(initialObject, title, url);

  
  window.history.go(-1)
  window.history.back();
  window.history.forword() // Proceed to the next route
Copy the code
History is deployed with Nginx

If YOU change the history pathname. / (index.html); / (index.html); / (index.html

Implementation Principles of Front-end Routing (History)

In-depth understanding of hash and History routes in the front end

Given an array, find a combination of elements equal to the sum of the numbers

var combinationSum = function(candidates, target) {
    let res=[]
    function add(arr,sum,index){
        let num=candidates[index]
        arr=arr.concat(num)
        sum+=num
        if(sum>target){
            / / fail
        }else if(sum===target){
            / / success
            res.push(arr)
        }else{
            for(leti=index; i<candidates.length; i++){ add(arr,sum,i) } } }for(let i=0; i<candidates.length; i++){ add([],0,i)
    }
    return res
};

Copy the code