Hi~ Long time no see.

After the 100 front end questions I sorted out last time became popular, many friends complained that it was not convenient to read the answers. In fact, the main reason was that the answers I sorted out and the analysis content was very comprehensive, leading to a long length of each question and not a good reading experience, so I put the answers on Github.

I’ve recently unlocked a new feature for Nuggets, folding content, and I’ll try to place as many answers and explanations as possible in this post.

1. How do I get the actual style values of HTML elements?

Company: JINGdong

Classification: JavaScript

Check the parsing

Code implementation

The actual style value can be interpreted as the browser’s computed style

The Style object contains the style information that the element that supports the style property sets for that property, but not the cascading style information from other stylesheets that also affects the element.

DOM2 Style adds the getComputedStyle() method to document.defaultView. This method takes two arguments: the element to get the computed style and a pseudo-element string (such as “:after”). The second argument can be passed null if no pseudo-element query is required. The getComputedStyle() method returns a CSSStyleDeclaration object (of the same type as the style property) containing the element’s computed style.

<! DOCTYPEhtml>
<html>
  <head>
    <title>Computed Styles Example</title>
    <style type="text/css">
      #myDiv {
        background-color: blue;
        width: 100px;
        height: 200px;
      }
    </style>
  </head>
  <body>
    <div
      id="myDiv"
      style="background-color: red; border: 1px solid black"
    ></div>
  </body>
  <script>let myDiv = document.getElementById("myDiv"); let computedStyle = document.defaultView.getComputedStyle(myDiv, null); console.log(computedStyle.backgroundColor); // "red" console.log(computedStyle.width); // "100px" console.log(computedStyle.height); // "200px" console.log(computedStyle.border); */ function getStyleByAttr(obj, name) {return window.getcomputedStyle? window.getComputedStyle(obj, null)[name] : obj.currentStyle[name]; } let node = document.getElementById("myDiv"); console.log(getStyleByAttr(node, "backgroundColor")); console.log(getStyleByAttr(node, "width")); console.log(getStyleByAttr(node, "height")); console.log(getStyleByAttr(node, "border</script>
</html>
Copy the code

2. Explain your understanding of React Hook, its implementation principle, and the difference between React Hook and its life cycle.

Company: Autonavi, Toutiao

Classification: the React

Check the parsing

A, the React of hooks

1.1 What is React Hook

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class.

In the past, functional components could not have their own state. They could only render their UI through props and context. In the business logic, some scenes must use state. Then we can only define functional components as class components. Now, with hooks, we can easily maintain our state in functional components without changing to class components.

React16.8 adds hooks to make React functional components more flexible

React had a lot of problems before hooks

  1. Reusing state logic between components is difficult
  2. Complex components become difficult to understand, and higher-order and functional components are nested too deeply.
  3. The class component’s this points to the problem
  4. Difficult to remember life cycle

Hooks solve this problem very well. Hooks provide many methods

  1. UseState returns a stateful value and a function to update that value
  2. UseEffect accepts functions that contain imperative code that may have side effects.
  3. UseContext takes the context object (the value returned from react.createcontext) and returns the current context value,
  4. An alternative to useReducer useState. Accept the Reducer of type (state, action) => newState and return the current state matched with the Dispatch method.
  5. UseCallback returns a Memoized version of the memory that changes only if one of the inputs changes. Input and output determinism of pure functions
  6. UseMemo is a pure memory function
  7. UseRef returns a mutable ref object whose.current property is initialized as the passed parameter
  8. UseImperativeMethods Specifies the instance value exposed to the parent component when ref is used
  9. Before useMutationEffect updates its sibling, it fires synchronously at the same stage as React performs its DOM changes
  10. UseLayoutEffect DOM changes after synchronization is triggered. Use it to read the layout from the DOM and synchronize rerendering

1.2. What problems does React Hook solve

React Hooks address the issue of state sharing, in which state logic reuse is only shared, not data sharing. We know that before React Hooks, we used higher-order Components and render props for state logic reuse.

Why did the React developers introduce React Hook when they already had these two solutions? What are the advantages of React Hook for higher-Order Components and render-props?

PS: The biggest advantage of Hook is the convenient reuse of state logic, the simplicity of code, and the enhancement of function components.

Let’s take a look at the React Hook demo

import { useState } from "React";

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>Click me</button>
    </div>
  );
}
Copy the code

React Hook Is not used

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0}; }render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>); }}Copy the code

In React Hook, the class Example component becomes a functional component. However, the functional component has its own state and can update its state. This is all thanks to the Hook useState, which returns a pair of values: the current state and a function that lets you update it, which you can call in an event handler or some other place. It is similar to the this.setState of the class component, but it does not merge the new state with the old state

1.3 Implementation Principles

Basic types of Hooks:

type Hooks = {
  memoizedState: any, // Point to the current render node Fiber
  baseState: any, // Initialize initialState, already newState after each dispatch
  baseUpdate: Update<any> | null.// The Update that needs to be updated is assigned to the last Update after each Update, so react can render errors on the edge and backtrack data
  queue: UpdateQueue<any> | null./ / UpdateQueue through
  next: Hook | null.// link to the next hooks, concatenate each hooks with next
};

type Effect = {
  tag: HookEffectTag, // effectTag marks which phase of life-Cycles the current hook is used in
  create: () = > mixed, // Initialize callback
  destroy: (() = > mixed) | null./ / uninstall the callback
  deps: Array<mixed> | null.next: Effect, / / same as above
};
Copy the code

The React Hooks maintains a global workInProgressHook variables, each new Hooks API to be obtained first createWorkInProgressHooks function to be obtained.

function createWorkInProgressHook() {
  if (workInProgressHook === null) {
    // This is the first hook in the list
    if (firstWorkInProgressHook === null) {
      currentHook = firstCurrentHook;
      if (currentHook === null) {
        // This is a newly mounted hook
        workInProgressHook = createHook();
      } else {
        // Clone the current hook.
        workInProgressHook = cloneHook(currentHook);
      }
      firstWorkInProgressHook = workInProgressHook;
    } else {
      // There's already a work-in-progress. Reuse it.currentHook = firstCurrentHook; workInProgressHook = firstWorkInProgressHook; }}else {
    if (workInProgressHook.next === null) {
      let hook;
      if (currentHook === null) {
        // This is a newly mounted hook
        hook = createHook();
      } else {
        currentHook = currentHook.next;
        if (currentHook === null) {
          // This is a newly mounted hook
          hook = createHook();
        } else {
          // Clone the current hook.hook = cloneHook(currentHook); }}// Append to the end of the list
      workInProgressHook = workInProgressHook.next = hook;
    } else {
      // There's already a work-in-progress. Reuse it.workInProgressHook = workInProgressHook.next; currentHook = currentHook ! = =null ? currentHook.next : null; }}return workInProgressHook;
}
Copy the code

Suppose we need to execute the following hooks code:

function FunctionComponet() {

  const [ state0, setState0 ] = useState(0);
  const [ state1, setState1 ] = useState(1);
  useEffect(() = > {
  	document.addEventListener('mousemove', handlerMouseMove, false); . . .return () = >{... . .document.removeEventListener('mousemove', handlerMouseMove, false); }})const [ satte3, setState3 ] = useState(3);
  return [state0, state1, state3];
}
Copy the code

When we understand the simple principle of React Hooks, we get that the Hooks are concatenated not as an array, but as a chained data structure, from the root workInProgressHook down through next. This is why Hooks cannot be nested, cannot be used in conditional judgments, cannot be used in loops. Otherwise you break the chain.

Two, and the difference between the life cycle

Function components are functions in nature, there is no concept of state, so there is no lifecycle, just a render function.

This is different with the introduction of Hooks, which allow components to have state without using classes, so the concept of a lifecycle is useState, useEffect(), and useLayoutEffect().

That is, Hooks components (function components that use Hooks) have a life cycle, while function components (function components that do not use Hooks) have no life cycle.

Here is the specific lifecycle correspondence between class and Hooks:

3. Specific implementation and comparison of mobile terminal adaptation schemes

Company: Top Story

Classification: Css

Check the parsing

Common mobile adaptation solutions

  • media queries
  • Flex layout
  • rem + viewport
  • vh vw
  • The percentage

A, Meida Queries

The method of Meida Queries can be said to be the layout method I used in the early stage. It mainly executes different CSS codes by querying the width of the device, and finally achieves the configuration of the interface.

Core syntax:

@media only screen and (max-width: 374px) {
  /* iphone5 or smaller size, scale to iphone5 width (320px) */
}
@media only screen and (min-width: 375px) and (max-width: 413px) {
  /* iphone6/7/8 and iPhone X */
}
@media only screen and (min-width: 414px) {
  /* iphone6p or larger size, scale to iphone6p width (414px) */
}
Copy the code

Advantages:

  • Media Query can be used to determine device pixel ratio in a simple and low-cost way, especially when maintaining the same set of code for mobile and PC. Currently frameworks like Bootstrap use this layout
  • Images are easy to modify, just by modifying the CSS file
  • Adjust the screen width for responsive display without refreshing the page

Disadvantages:

  • Large amount of code, maintenance is not convenient
  • Trying to accommodate a large screen or HD device wastes resources on other devices, especially loading images
  • In order to give consideration to the responsive display effect of mobile terminal and PC terminal, it is inevitable to lose their unique interaction modes

Two, Flex Flex layout

Illustrated by the implementation of Tmall:

The height is fixed, the width is adaptive, and the element uses PX as the unit.

As the screen width changes, the page will also change, the effect is similar to the FLUID layout of the PC page, in which the width needs to adjust the use of responsive layout on the line (such as netease news), so as to achieve “adaptation”.

Rem + ViewPort zoom

Implementation principle:

Enlarge the page by DPR according to REM, and then set the viewport to 1/ DPR.

  • For example, if the DPR of iphone6 Plus is 3, the page will be enlarged 3 times as a whole, and 1px(CSS units) will default to 3px(physical pixels) under Plus.
  • Then the viewPort is set to 1/3 so that the entire page shrinks back to its original size. To achieve hd.

The width of the entire page displayed on the device is equal to the device’s logical pixel size (device-width). The device-width is calculated by:

Device physical resolution /(devicePixelRatio * Scale), in the case of scale 1, device-width = device physical resolution /devicePixelRatio.

Fourth, REM implementation

Rem is a unit of relative length, and the style design in REM scheme is a multiple of the calculated value relative to the font size of the root element. The font size of THE HTML tag is set according to the width of the screen, and rem unit layout is used in the layout to achieve the purpose of self-adaptation.

Control the REM reference values with the following code (the actual size of the design is 720px wide)

! (function (d) {
  var c = d.document;
  var a = c.documentElement;
  var b = d.devicePixelRatio;
  var f;
  function e() {
    var h = a.getBoundingClientRect().width,
      g;
    if (b === 1) {
      h = 720;
    }
    if (h > 720) h = 720; // Set the limit of the base value
    g = h / 7.2;
    a.style.fontSize = g + "px";
  }
  if (b > 2) {
    b = 3;
  } else {
    if (b > 1) {
      b = 2;
    } else {
      b = 1;
    }
  }
  a.setAttribute("data-dpr", b);
  d.addEventListener(
    "resize".function () {
      clearTimeout(f);
      f = setTimeout(e, 200);
    },
    false); e(); }) (window);
Copy the code

$px: (1/100)+ REM;

Advantages:

  • Good compatibility, the page will not be deformed because of expansion, adaptive effect is better.

Disadvantages:

  • Not a pure CSS mobile adaptation, you need to embed a section in the headerjsThe script listens for resolution changes to dynamically change the font size of the root element,cssThe style andjsThe code has some coupling and must changefont-sizeThe code in thecssStyle before.
  • The smallest unit of browser rendering is pixels, and the element ADAPTS to the screen width throughremThere may be decimal pixels that the browser will round and render as integers, which may not be quite as accurate.

5. Pure VW scheme

Viewports are the areas of the browser used to render web pages.

  • Vw: 1VW is equal to 1% of the viewport width
  • Vh: 1vh equals **1% ** of the viewport height
  • Vmin: Choose the smallest of vw and vH
  • Vmax: Pick the largest of vw and vH

Although VW can be more elegantly adapted, there is still a small problem, that is, the width and height cannot be limited.

$base_vw = 375;
@function vw ($px) {
    return ($px/$base_vw) * 100vw
};
Copy the code

Advantages:

  • purecssMobile adaptation solution, there is no script dependency problem.
  • Relative to theremDefining the size of an element as a multiple of the font size of the root element is logical and simple.

Disadvantages:

  • There are some compatibility issues and some browsers do not support it

Vi. Vw + REM scheme

/ / SCSS syntax
// Set the HTML root element size to 750px->75 640px->64
// Divide the screen into 10 pieces, each as the size of the root element.
$vw_fontsize: 75
@function rem($px) {
    For example, if a div is 100px wide, its corresponding rem unit is 100/ the size of the root element * 1rem
    @return ($px / $vw_fontsize) * 1rem;
}
$base_design: 750
html {
    // REM is associated with VW
    font-size: ($vw_fontsize / ($base_design / 2)) * 100vw;
    // At the same time, use Media Queries to limit the maximum and minimum values of root elements@media screen and (max-width: 320px) { font-size: 64px; } @media screen and (min-width: 540px) { font-size: 108px; }}// Body also adds a Max/min width limit to avoid the default 100% width block element being too large or too small to follow body
body {
    max-width: 540px;
    min-width: 320px;
}

Copy the code

Vii. Percentage

Use percentage % to define the width, and use px to fix the height. Adjust according to the real-time size of the visible area to accommodate as many resolutions as possible. Usually use max-width/min-width to control the size range to be too large or too small.

Advantages:

  • The principle is simple and there are no compatibility problems

Disadvantages:

  • If the screen scale is too large, the screen that is too large or too small compared to the design draft cannot be displayed properly. In large-screen mobile phone or vertical screen switching scenarios, page elements may be stretched and deformed, and the font size cannot change with the screen size.
  • When setting different attributes of the box model, the reference element for its percentage setting is not unique, which can easily complicate the layout problem.

4.Var arr = [[' A ', 'B'], [' A ', 'B'], [1, 2]]For two dimensional array of permutation and combination Results: Aa1 and Aa2, Ab1, Ab2, Ba1, Ba2, Bb2, Bb2

Company: Meituan

Classification: Algorithms

Check the parsing

Reference code implementation

  • Implementation Method 1
function foo(arr) {
  // It is used to record the initial array length. It is used to intercept the first two groups of arrays that have obtained the full array
  var len = arr.length;
  // Return arr[0] if the array length is 1
  if (len >= 2) {
    Arr [0]; arr[1]; arr[0]
    var len1 = arr[0].length;
    var len2 = arr[1].length;
    var items = new Array(len1 * len2); // Create an array of possible permutations and combinations
    var index = 0; // Record the array subscript after each permutation
    for (var i = 0; i < len1; i++) {
      for (var j = 0; j < len2; j++) {
        if (Array.isArray(arr[0]) {// The first element of the array must be an array enclosing an array
          items[index] = arr[0][i].concat(arr[1][j]); // Append all permutations that have already been recursed for the second time
        } else {
          items[index] = [arr[0][i]].concat(arr[1][j]); Arr [0]; arr[1]; arr[0]
        }
        index++; // Update the subscript of all permutations and combinations}}// If the array is greater than 2, here the new newArr does a recursive operation
    var newArr = new Array(len - 1); // The recursive array is one less than the array passed in. The arr[0] and arr[1] of the array passed in are all permutations and combinations, so newArr[0] is the array item passed in
    for (var i = 2; i < arr.length; i++) {
      // The for loop is used to intercept the array after subscript 1 and assign it to newArr
      newArr[i - 1] = arr[i];
    }
    newArr[0] = items; Arr[0] and arr[1] are all permutations, so newArr[0] is the array item that is all permutations
    // The reassembled array performs recursive operations
    return foo(newArr);
  } else {
    // Return arr[0] when the array length is 1,
    return arr[0]; }}var arr = [
  ["A"."B"],
  ["a"."b"],
  [1.2]];console.log(foo(arr));
Copy the code
  • Implementation Method 2
const getResult = (arr1, arr2) = > {
  if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
    return;
  }
  if(! arr1.length) {return arr2;
  }
  if(! arr2.length) {return arr1;
  }
  let result = [];
  for (let i = 0; i < arr1.length; i++) {
    for (let j = 0; j < arr2.length; j++) {
      result.push(String(arr1[i]) + String(arr2[j])); }}return result;
};

const findAll = (arr) = >
  arr.reduce((total, current) = > {
    returngetResult(total, current); } []);var arr = [
  ["A"."B"],
  ["a"."b"],
  [1.2]];console.log(findAll(arr));
Copy the code
  • Implementation Method 3
var arr = [
  ["A"."B"],
  ["a"."b"],
  [1.2]];let res = [],
  lengthArr = arr.map((d) = > d.length);
let indexArr = new Array(arr.length).fill(0);
function addIndexArr() {
  indexArr[0] = indexArr[0] + 1;
  let i = 0;
  let overflow = false;
  while (i <= indexArr.length - 1) {
    if (indexArr[i] >= lengthArr[i]) {
      if (i < indexArr.length - 1) {
        indexArr[i] = 0;
        indexArr[i + 1] = indexArr[i + 1] + 1;
      } else {
        overflow = true;
      }
    }
    i++;
  }
  return overflow;
}
function getAll(arr, indexArr) {
  let str = "";
  arr.forEach((item, index) = > {
    str += item[indexArr[index]];
  });
  res.push(str);
  let overflow = addIndexArr();
  if (overflow) {
    return;
  } else {
    return getAll(arr, indexArr);
  }
}
getAll(arr, indexArr);
console.log(res);
Copy the code

5. Talk about workflow (development process, code specification, packaging process, etc.)

Company: Tencent Weishi

Classification: Engineering

Check the parsing

First, get the prototype diagram, first self-analysis requirements, draw a mind map, flow chart

  • Before we get the PSD given by the UI, we can first clarify our requirements
    • Dependent external resources
      • Interfaces provided by the back end
      • The general layout of the UI output diagram
      • Frequent changes in the later period
  • The effect that needs to be achieved
    • The drop-down refresh
    • Animation effects
    • The effect of suction a top
    • Lazy loading, preloading, anti – shaking, throttling

Ii. Convene project related personnel, hold demand discussion, and explain product prototype

  1. Understand the requirements of the product and ask questions: what is it, how is it done, and why
  2. Assess the difficulty and cost of implementation and whether there are potential technical issues/risks
  3. Compare your own requirements and ask questions if there are any that do not match what you think
  4. Understand PM’s purpose for this requirement, and know which content is important and which is secondary, and can make appropriate trade-offs
  5. If the product requires to provide time, simple projects can be estimated, complex projects can not be given time immediately, need to be carefully evaluated, including development, self-testing, testing by testers, bug fixing, ready to go online

Iii. Further sorting out requirements after the meeting

  1. Refine the details, sort out the questions, and check with others about the product, design, etc
  2. Assess project completion time — Influencing factors: manpower required, in-between requirements, development, self-testing, tester testing, bug fixing, launch preparation, other risks (such as technical selection errors, etc.)
  3. Make a preliminary schedule

Iv. Secondary confirmation of requirements (In case of uncertainty during development, it is still necessary to find relevant personnel for confirmation of requirements to eliminate useless efforts)

  1. Confirm IM communication
  2. Email confirmation
  3. Small requirements/project related seminar
  4. Determine the final schedule

Five, develop

  1. Technology selection
  2. Setting up the development environment: toolchain
  3. Build the project structure
  4. Business module division
    • Priority sorting
    • The involvement of new projects requires the Pk priority of the relevant person in charge of the current project and the involved project, and then the project schedule will be adjusted
    • During the development process, it is found that the workload is seriously different from the expected, so it is necessary to give feedback to other project staff as soon as possible so that they can modify the schedule
  5. Custom development specification
    • The development of specification
      • Commit format:[Change file type] : [Change description]
      • Single-branch development or multi-branch development
        1. Small projects, less parallel development, only in the master branch development
        2. Large and medium-sized projects with complex requirements and many parallel functions need to be divided into master, Developer and developer branches. Developers need to create a branch development, merge into developer, confirm no problem, release to master, finally online
    • Code specification
      1. jsconfig.json
      2. .postcssrc.js
      3. .babelrc
      4. .prettierrcPrettier-code fomatter (vscode plug-in prettier-code fomatter) — be consistent with eslint
      5. .editorconfig
      6. .eslintrc.js(Forcibly enable authentication mode)
    • Source code management
    • Version management
    • The safety management

Six, self-test

  1. Manual testing
  2. Unit testing
  3. Integration testing

Seven, test — the tester test

  1. Developers fix bugs
  2. Do not take on time-consuming requirements during this period
  3. When there are demands with uncertain priority levels, each demander needs to pk each other’s priorities and then decide whether to do or not to do it. Therefore, the completion point of the project cannot be delayed
  4. Testing to fix bugs can take longer than development, so developers can’t be optimistic about development time

Eight, online

  1. A. Domain name application B. Record application C. Server application D. The deployment of

  2. Test line environment

    • Back to fixing bugs
  3. Log monitoring

    1. The call stack
    2. sourcemap
    3. The local log
    4. User environment and IP address
    5. Low-cost access
    6. statistics
    7. Alarm function

Nine, maintenance,

  1. Technology innovation (optimization of existing technology areas and specific project implementation methods)
    1. Improve efficiency: e.g. Jenkins build deployment
    2. To reduce the cost
    3. Lifting stability
    4. security

6. Can the parent component listen to the life cycle of the child component in Vue?

Company: Shuidi Chip

Classification: Vue

Check the parsing

implementation

Use on and emit

// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
  this.$emit("mounted");
}
Copy the code

Use the hook function

// Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('Parent listens to mounted hook function... ');
},
// Child.vue
mounted(){
   console.log('Child component triggers mounted hook function... ');
},
// The output sequence is as follows:
// The child triggers the mounted hook function...
// The parent listens to the mounted hook function...
Copy the code

7. How to define global methods for Vue

Classification: Vue

Check the parsing

implementation

Mount the method to Vue.prototype

Disadvantages: This method is called without prompting

// global.js
const RandomString = (encode = 36, number = -8) = > {
  return Math.random() // Generate a random number, eg: 0.123456
    .toString(encode) // Convert to base 36: "0.4fzyo82mvyr"
    .slice(number);
},
export default {
	RandomString,
  ...
}
Copy the code
// Configure it in main.js of the project entry
import Vue from "vue";
import global from "@/global";
Object.keys(global).forEach((key) = > {
  Vue.prototype["$global" + key] = global[key];
});
Copy the code
App.vue = app.vue = app.vue = app.vue = app.vue = app.vue = app.vue
export default {
  mounted() {
    this.$globalRandomString(); }};Copy the code

Second, use global mixins

Advantages: Because methods in mixins are merged with every single file component created. This has the advantage of being prompted when the method is called

// mixin.js
import moment from 'moment'
const mixin = {
  methods: {
    minRandomString(encode = 36, number = -8) {
      return Math.random() // Generate a random number, eg: 0.123456
        .toString(encode) // Convert to base 36: "0.4fzyo82mvyr".slice(number); },... }}export default mixin
Copy the code
// Configure it in main.js of the project entry
import Vue from 'vue'
import mixin from '@/mixin'
Vue.mixin(mixin)
Copy the code
export default {
 mounted() {
   this.minRandomString()
 }
}
Copy the code

3. Use Plugin

The vue. use implementation has no mount functionality, just triggers the install method of the plug-in, essentially using vue. prototype.

// plugin.js
function randomString(encode = 36, number = -8) {
  return Math.random() // Generate a random number, eg: 0.123456
    .toString(encode) // Convert to base 36: "0.4fzyo82mvyr"
    .slice(number);
}
const plugin = {
  // install is the default method.
  // When the component or function is used, the install method itself is called and a Vue class argument is passed.
  install: function(Vue){ Vue.prototype.$pluginRandomString = randomString ... }},export default plugin
Copy the code
// Configure it in main.js of the project entry
import Vue from 'vue'
import plugin from '@/plugin'
Vue.use(plugin)
Copy the code
export default {
 mounted() {
   this.$pluginRandomString()
 }
}
Copy the code

Write global functions in any VUE file

// Create a global method
this.$root.$on("test".function () {
  console.log("test");
});
// Destroy the global method
this.$root.$off("test");
// Call the global method
this.$root.$emit("test");
Copy the code

8. Explain the vm.$set principle

Company: Aurora Push

Classification: Vue

Check the parsing

vm.$set()What problem was solved

In Vue. Js, only properties that already exist in data are considered responsive by Observe. If you add a property, it is not considered responsive.

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Vue Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  </head>
  <body>
    <div id="app">
      {{user.name}} {{user.age}}
      <button @click="addUserAgeField">Add an age field</button>
    </div>
    <script>
      const app = new Vue({
        el: "#app".data: {
          user: {
            name: "test",}},mounted() {},
        methods: {
          addUserAgeField() {
            // this.user.age = 20 so it does not work and will not be used by the Observer
            this.$set(this.user, "age".20); // It should be used,}}});</script>
  </body>
</html>
Copy the code

The principle of

Vm. $set() is injected into the Vue prototype when new Vue() is created.

Source location:vue/src/core/instance/index.js

import { initMixin } from "./init";
import { stateMixin } from "./state";
import { renderMixin } from "./render";
import { eventsMixin } from "./events";
import { lifecycleMixin } from "./lifecycle";
import { warn } from ".. /util/index";

function Vue(options) {
  if(process.env.NODE_ENV ! = ="production" && !(this instanceof Vue)) {
    warn("Vue is a constructor and should be called with the `new` keyword");
  }
  this._init(options);
}

initMixin(Vue);
// Bind the prototype to the prop property $props, $data
$watch, vm.$set, and vm.$delete
stateMixin(Vue);
$on, vm.$once,vm.$off,vm.$emit
eventsMixin(Vue);
// Bind the Vue prototype to lifecycle specific instance methods: vm.$forceUpdate, vm.destroy, and the private _update method
lifecycleMixin(Vue);
// Bind the Vue prototype to lifecycle specific instance methods: VVM.$nextTick, and the private _render method, as well as a bunch of utility methods
renderMixin(Vue);

export default Vue;
Copy the code
  • stateMixin()
Vue.prototype.$set = set;
Vue.prototype.$delete = del;
Copy the code
  • set()

Source location: vue/SRC/core/observer/index. Js

export function set(target: Array<any> | Object, key: any, val: any) :any {
  // 1
  // If the first argument to set is undefined or null or a primitive value, a warning message will be printed in non-production environments
  // This API is intended for objects and arrays
  if( process.env.NODE_ENV ! = ="production" &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(
      `Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`
    );
  }
  // 2. Array processing
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    $vm.set(vm.$data. Arr, 0, 3)
    // Change the length of the array to avoid index > array length errors caused by splcie()
    // If length is not set, splice will not add a blank item if index exceeds the original number
    target.length = Math.max(target.length, key);
    // Use the array splice mutation method to trigger the response, as described earlier
    target.splice(key, 1, val);
    return val;
  }
  //3. Object, and key is not a property on the prototype
  // Target is the object. Key is on target or target.prototype.
  // Must not be on Object.prototype
  / / changes directly, are interested can look at issue: https://github.com/vuejs/vue/issues/6845
  if (key intarget && ! (keyin Object.prototype)) {
    target[key] = val;
    return val;
  }
  If none of the above is true, start creating a new property for target
  // Get an Observer instance
  const ob = (target: any).__ob__;
  // Vue instance objects have _isVue attributes, that is, attributes cannot be added to Vue instance objects
  Vue. Set /$set is also not allowed to add attributes to the root data object (vm.$data)
  if(target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV ! = ="production" &&
      warn(
        "Avoid adding reactive properties to a Vue instance or its root $data " +
          "at runtime - declare it upfront in the data option."
      );
    return val;
  }
  //5. Target is non-responsive data
  // Target itself is not reactive data, directly assigned
  if(! ob) { target[key] = val;return val;
  }
  //6. Target is responsive data
  // Define a responsive object
  defineReactive(ob.value, key, val);
  / / watcher
  ob.dep.notify();
  return val;
}
Copy the code
  • Tool function
// Determine if a given variable is undefined. If the value is null, it is also considered undefined
export function isUndef(v: any) :boolean %checks {
  return v === undefined || v === null;
}

// Determine whether the given variable is a primitive value
export function isPrimitive(value: any) :boolean %checks {
  return (
    typeof value === "string" ||
    typeof value === "number" ||
    // $flow-disable-line
    typeof value === "symbol" ||
    typeof value === "boolean"
  );
}

// Determine if the value of the given variable is a valid array index
export function isValidArrayIndex(val: any) :boolean {
  const n = parseFloat(String(val));
  return n >= 0 && Math.floor(n) === n && isFinite(val);
}
Copy the code
  • About (OB && OB.vmCount)
export function observe(value: any, asRootData: ? boolean) :Observer | void {
  / / to omit...
  if (asRootData && ob) {
    // If the vue is already observed and is the root data object, vmCount will ++
    ob.vmCount++;
  }
  return ob;
}
Copy the code
  • During Vue initialization there are
export function initState(vm: Component) {
  vm._watchers = [];
  const opts = vm.$options;
  if (opts.props) initProps(vm, opts.props);
  if (opts.methods) initMethods(vm, opts.methods);
  if (opts.data) {
    //opts.data is an object attribute
    initData(vm);
  } else {
    observe((vm._data = {}), true /* asRootData */);
  }
  if (opts.computed) initComputed(vm, opts.computed);
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch);
  }
}
Copy the code
  • initData(vm)
function initData(vm: Component) {
  let data = vm.$options.data;
  data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};

  / / to omit...

  // observe data
  observe(data, true /* asRootData */);
}
Copy the code

The main logic of set is as follows:

  1. Type judgment
  2. Target is array: call the splice method
  3. Target is an object, and key is not an attribute on the prototype: modify directly
  4. Target cannot be the Vue instance or the root data object of the Vue instance; otherwise, an error is reported
  5. When a target is non-responsive data, we treat it as if we were adding attributes to a normal object
  6. Target is the response data, and key is the new attribute. We set key as responsive, and manually trigger the update of its attribute value

conclusion

Vm.$set(target, key, value)

  • When target is an array, splice is called directly.
  • If the target is an object, the presence of the attribute and whether the object is reactive is checked first
  • Finally, if you want to do reactive processing for attributes, you do it by calling the defineReactive method
    • DefineReactive is what Vue calls when it initializes an Object and dynamically adds getters and setters to Object properties using Object.defineProperty

9. How does deep copy solve circular references?

Company: Aurora Push

Classification: JavaScript

Check the parsing

Circular reference problem

Look at an example

function deepCopy(obj){
    const res = Array.isArray(obj) ? [] : {};
    for(let key in obj){
        if(typeof obj[key] === 'object'){
            res[key] = deepCopy(obj[key]);
        }else{ res[key] = obj[key]; }}return res
}
var obj = {
    a:1.b:2.c: [1.2.3].d: {aa:1.bb:2}}; obj.e = obj;console.log('obj',obj); // No error will be reported

const objCopy = deepCopy(obj);
console.log(objCopy); //Uncaught RangeError: Maximum call stack size exceeded
Copy the code

As you can see from the example, deepCopy will report an error when there is a circular reference, and the stack will overflow.

  • Obj objects with circular references are printed without stack overflow
  • Deep copy obJ will cause stack overflow

Loop application problem solving

  • That is, the target object has a circular application error processing

As we all know, the key of an object cannot be an object.

{{a:1} :2}
// Uncaught SyntaxError: Unexpected token ':'
Copy the code

Solution 1: Use weekmap:

To solve the problem of circular reference, we can create an extra storage space to store the corresponding relationship between the current object and the copied object

This storage space needs to be able to store key-value data, and the key can be a reference type,

We can choose WeakMap as a data structure:

  • checkWeakMapIs there any cloned object in
  • Yes, go straight back
  • No, take the current object askey, clone the object asvalueFor storage
  • Continue to clone
function isObject(obj) {
    return (typeof obj === 'object' || typeof obj === 'function') && obj ! = =null
}
function cloneDeep(source, hash = new WeakMap(a)) {
  if(! isObject(source))return source;
  if (hash.has(source)) return hash.get(source); // add code to check hash table

  var target = Array.isArray(source) ? [] : {};
  hash.set(source, target); // Add code, hash table set value

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (isObject(source[key])) {
        target[key] = cloneDeep(source[key], hash); // Add code to pass in hash table
      } else{ target[key] = source[key]; }}}return target;
}
Copy the code

Refer to solution two:

You can use Set to find the same object and assign it directly, or you can use Map

const o = { a: 1.b: 2 };
o.c = o;

function isPrimitive(val) {
    return Object(val) ! == val; }const set = new Set(a);function clone(obj) {
    const copied = {};
    for (const [key, value] of Object.entries(obj)) {
        if (isPrimitive(value)) {
            copied[key] = value;
        } else {
            if(set.has(value)) { copied[key] = { ... value }; }else{ set.add(value); copied[key] = clone(value); }}}return copied;
}
Copy the code

10. How are unit tests tested? What about code coverage?

Company: Programming Cat

Classification: Engineering

Check the parsing

Why unit tests?

Having the strength of unit testing ensures the quality of the code delivered and builds confidence in yourself and others. When we choose third-party libraries, don’t we also prefer those with test protection? Future code changes can also save time for regression testing.

Two, how to measure?

When doing unit tests, we should focus on integration tests. We should do unit tests for a small amount of codes that are difficult to be covered by integration tests or need to be distributed. At the same time, we can also have a small amount of end-to-end testing assistance.

Try not to test code implementations, which can quickly make test cases fail. For example, if the name of an assertion variable is changed, the test will fail, but the functionality may not have changed.

2.1 What tests should be written?

Test application functionality from the user’s perspective, not god’s.

Passing in different parameters to a component renders the DOM so that the user can see certain words or do certain things. At this point, you can assert whether certain words appear in the DOM and whether actions (such as clicking, typing, submitting a form, etc.) have the correct response.

2.2 What tests should not be written?

Do not test implementation details. For example, check the data on Redux Store and state data from the perspective of God, but these do not exist in the eyes of the end user, and the user can perceive only the function presented.

Three, test frame and peripheral supporting

Jest is a testing framework produced by Facebook. Right out of the box, it comes with assertion libraries, mocks, coverage reports, and more.

Because the front end tests the UI and renders the DOM in a simulated browser environment, you need such a library. Enzyme, @testing-library/react;

Iv. Test coverage/efficiency report

Jest comes with test reports, but there are too many projects scattered around GitLab to view the reports. Consider having a central place to view test reports. This combines sonar and reportportal to gather test reports so you can view test reports for all projects in one central place.

The code scanning function with Sonar can check test coverage and other report information. You can view the test execution rate in ReportPortal, and the official AI analysis report is available to provide multi-dimensional statistics.

React state logic reuse

Company: Programming Cat

Classification: the React

Check the parsing

React State logic reuse

A, Mixins

Although React itself was somewhat functional, early on only the React.createclass () API was provided to define components to suit user habits: inheritance naturally became an intuitive endeavor. In JavaScript’s prototype-based extension mode, inherited mixin-like schemes are preferred:

/ / define a Mixin
var Mixin1 = {
  getMessage: function () {
    return "hello world"; }};var Mixin2 = {
  componentDidMount: function () {
    console.log("Mixin2.componentDidMount()"); }};// Enhance existing components with mixins
var MyComponent = React.createClass({
  mixins: [Mixin1, Mixin2],
  render: function () {
    return <div>{this.getMessage()}</div>; }});Copy the code

But there are many drawbacks

There are implicit dependencies between components and mixins (mixins often rely on a particular method of the component but are not aware of that dependency when defining the component). There can be conflicts between multiple mixins (such as defining the same state field). Mixins tend to add more state, This reduces The more state in your application, The harder it is to reason about it.

Implicit dependencies lead to opaque dependencies and rapidly rising maintenance and understanding costs: it is difficult to quickly understand the behavior of components, and it requires a comprehensive understanding of all the extended behaviors that depend on mixins and their interactions. The component’s own methods and state fields are not easy to delete, because it is difficult to determine whether mixins depend on them, and mixins are also difficult to maintain, because the Mixin logic will eventually be flattened and merged together, making it difficult to figure out the input and output of a Mixin.

There’s no doubt that these issues are fatal, so React V0.13.0 ditches Mixin in favor of HOC.

B, higher-order Components

// Define higher-order components
var Enhance = (ComposedComponent) = >
  class extends Component {
    constructor() {
      this.state = { data: null };
    }
    componentDidMount() {
      this.setState({ data: "Hello" });
    }
    render() {
      return <ComposedComponent {. this.props} data={this.state.data} />; }};class MyComponent {
  render() {
    if (!this.data) return <div>Waiting...</div>;
    return <div>{this.data}</div>; }}// Use higher-order components to enhance common components for logical reuse
export default Enhance(MyComponent);
Copy the code

Theoretically, any function that takes a Component type argument and returns a Component is a higher-order Component ((Component,… Args) => Component), but for ease of composition, we recommend HOC in the form of Component => Component, passing in additional arguments via partial function applications, such as: React Redux’s connect const ConnectedComment = connect(commentSelector, commentActions)(CommentList);

Advantages:

  • Component tree structure reduces coupling and complexity;
  • Code reuse, logic abstraction
  • Renderjacking, property brokering, props and state for jacking components
  • Decorator, can be used as decorator;
  • The function is currified

Cons: While HOC doesn’t have as many fatal problems, it does have a few minor drawbacks:

  • Scalability limitation
  • Do not use in Render, as each render recreates a higher-order component, causing state loss of components and sub-components, affecting performance;
  • Static methods are lost. New components do not have static methods and need to be handled manually.
  • Refs are not passed down; the forwardRef is required
  • Multiple nesting, increasing complexity and cost of understanding;
  • If namespaces are not used, naming conflicts may occur, overwriting old attributes.
  • Invisibility, don’t know what’s on the outside, black box;

Three, Render the Props

“Render Prop” is a simple technique for sharing code between React components using a prop with a value of function;

class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0.y: 0 };
  }
  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY,
    });
  }
  render() {
    return (
      <div style={{ height: "100%}}"onMouseMove={this.handleMouseMove}>
        {/* Instead of providing a static representation of what <Mouse> renders, use the `render` prop to dynamically determine what to render. */}
        {this.props.render(this.state)}
      </div>); }}Copy the code

Advantages: Data sharing, code reuse, passing state in the component as props to the caller, rendering logic to the caller

Disadvantages: Unable to access data outside the return statement, not elegant nesting;

Fourth, the Hooks

function MyResponsiveComponent() {
  const width = useWindowWidth();
  // Our custom Hook
  return <p>Window width is {width}</p>;
}
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() = > {
    const handleResize = () = > setWidth(window.innerWidth);
    window.addEventListener("resize", handleResize);
    return () = > {
      window.removeEventListener("resize", handleResize);
    };
  });
  return width;
}
Copy the code

In contrast to the other solutions mentioned above, Hooks are really trying to solve the reuse problem of fine-grained logic from below by making logic reuse within components not tied to component reuse.

In addition, this declarative logic reuse scheme extends the idea of explicit data flow and composition between components to components, which is in line with the React concept.

The advantages are as follows:

  • React-hooks fix HOC and Render Props for nested functions
  • Decouple: React Hooks allow for more complete decoupling by making it easier to separate UI from state
  • Combination: You can use Hooks from other Hooks to form new Hooks, which can be combined in any number of ways
  • React Hooks are designed for function components, which solve several major problems with class components:
    • This is error-prone
    • The business logic is split into different declaration cycles, making the code difficult to understand and maintain
    • High cost of code reuse (high-order components tend to increase code volume)

Hooks are not perfect, but for now, they have the following shortcomings:

  • There are also two class components whose lifecycle functions cannot be replaced by hooks, getSnapshotBeforeUpdate and componentDidCatch
  • Additional learning costs (confusion between Functional Component and Class Component)
  • It can only be used at the top level of functions, which increases the cost of refactoring old code. React uses the call sequence to update state and call hook functions; Placing them in loops or conditional branches can result in out-of-order calls, resulting in strange bugs;
  • – Broken performance optimizations for shallow comparisons of PureComponent and React.memo (to get the latest props and state, each render() function is recreated at the event)
  • In closure scenarios, references to old props and state values are not intuitive (depending on a mutable global state, which is no longer “pure”).
  • React.memo does not completely replace shouldComponentUpdate (_ change).
  • The useState API is not perfect in design
  • When using useState, array objects updated with push, pop, and splice are invalid. Such asLet [nums, setNums] = useState([0,1,2]); Nums.push (1) is invalid, nums=[...nums, 1] must be usedAnd then setNums (nums); A direct push in a class component is fine
  • Decorators cannot be used
  • The ref function component requires the forwardRef

12. What are the principles of component library design?

Company: Programming Cat

Classification: JavaScript

Check the parsing

Component library design principles

1.1 standard

Every component should adhere to a set of standards that will enable developers in different regions to develop a uniform set of components

1.2 independence

  • It describes the granularity of components, following the single responsibility principle, and keeping components pure
  • Apis such as property configuration are open to the outside world, and component internal state is closed to the outside world, with as little coupling to the business as possible

1.3 Reuse and ease of use

  • UI differences are digested inside components (note not writing a bunch of if/else)
  • Input and output friendly, easy to use

1.4 Apply the SPOT rule

Single Point Of Truth is The Art Of Unix Programming.

1.5 Avoid exposing component internal implementations

1.6 Avoid direct DOM manipulation and refs

Use the state of the parent component to control the state of the child component rather than manipulating the child component directly through the REF

1.7 Check the validity of parameters at the entrance and check the correctness of returned parameters at the exit

1.8 Acyclic Dependency Principle (ADP)

1.9 Stable Abstraction Principle (SAP)

  • The degree of abstraction of a component is proportional to its degree of stability,
  • A stable component should be abstract (logically independent)
  • An unstable component should be concrete (logically related)
  • To reduce coupling between components, we program for abstract components rather than business implementations

1.10 Avoid redundancy

  • If a data can be obtained by another state transformation, then the data is not a state, and you only need to write a transformation handler. You can use computed properties in Vue
  • If a piece of data is a fixed, unchanging constant, it is not state, just like HTML’s fixed site title, written dead or as a global configuration property
  • If the sibling component has the same state, then that state should be passed to both components at a higher level using props

1.11 Reasonable dependencies

The parent component does not depend on the child component, and removing a child component does not cause a functional exception

1.12 Flattening parameters

In addition to data, avoid complex objects and try to accept only primitive values

1.13 Good interface design

  • To maximize what can be done inside a component, while embracing change is encouraged, more interfaces are not always better
  • If a constant becomes props for more scenarios, it can be used as props, and the original constant can be used as the default.
  • If you need to write a lot of code for a particular requirement for a particular caller, consider building a new component, for example through extensions.
  • Ensure that component properties and events are sufficient for most components to use.

1.14 APIS are as consistent as possible with known concepts

13. Write code output values and explain why

function F() {
  this.a = 1;
}
var obj = new F();
console.log(obj.prototype);
Copy the code

Company: Futu

Classification: JavaScript

Check the parsing

The answer

undefined
Copy the code

Reference analysis

Constructor instances generally do not have the Prototype attribute. Except for the Function constructor

Only functions have the Prototype property, not if the value is an object instance object

The instance object uses the __proto__ internal attribute ([[prototype]]) to string a prototype chain through which attributes can be found,

When a method initializes a function object with the new operator, it builds an instance object,

The prototype property of the function object points to the prototype object of the instance object, that is, the object __proto__ points to

Classic and prototype chain diagrams

14. What happens when you insert 100,000 for loops in the middle of HTML? How to solve the phenomenon of stuck? When will the script execute after the defer attribute is added? After adopting Defer, what happens when the user clicks on the page? Is there another way to disable WebWoker?

Company: Futu

Classification: JavaScript

Check the parsing

Insert the loop code into the body 100, 000 times, and the page freezes

After inserting the loop code into the body 100,000 times, the page will stall and the DOM node after the code cannot be loaded

Second, the solution

Set the script tag defer property, and the script will be downloaded by other threads of the browser until the document has been parsed.

After adopting defer, the user clicks on the question

  • If the click event in the Button was defined before the defer script, the click event will be responded to after the defer script has loaded.

  • If the click event in the button is defined after the defer script, the user will not respond when clicking the button. After the script is loaded, the user will respond when clicking the button again.

  • Code sample

<! -- test.html -->
<! DOCTYPEhtml>
<html>
  <head>
    <title></title>
  </head>

  <body>
    <div class="test1">test1</div>
    <div id="hello"></div>
    <script>
      // Defer to respond after the script has been downloaded
      function alertMsg() {
        alert("123");
      }
    </script>
    <input type="button" id="button1" onclick="alertMsg()" />
    <script src="./test.js" defer></script>
    <div class="test2">test2</div>
  </body>
  <style>
    .test1 {
      color: red;
      font-size: 50px;
    }

    .test2 {
      color: yellow;
      font-size: 50px;
    }
  </style>
</html>
Copy the code
// test.js

for (let i = 0; i < 100000; i++) {
  console.log(i);
}
document.getElementById("hello").innerHTML = "hello world";
Copy the code

Is there any other way to disable WebWoker?

4.1 use the Concurrent. Thread. Js

  • Concurrent.thread. js is used to simulate multi-threading for multi-threading development.
Concurrent.Thread.create(function () {$("#test").click(function () {
    alert(1);
  });
  for (var i = 0; i < 100000; i++) {
    console.log(i); }});Copy the code

4.2 Using the Virtual List

If the situation is rendering 100,000 pieces of data, you can use a virtual list. The virtual list renders only the data in the visible area, reducing DOM rendering in the case of large data volumes and allowing the list to scroll smoothly and indefinitely.

Implementation scheme:

Based on virtual lists is a feature of rendering visual areas, we need to do the following three things

  1. It is necessary to calculate the height of the blank space at the top and bottom of the invisible area to support the height of the whole list so that it is the same as that without truncation of data. These two heights are named topHeight and bottomHeight respectively
  2. Slice (start,end);
  3. During scrolling, you need to update topHeight, bottomHeight, start and end to update the visual area view. Of course, we need to compare the old start and end to determine whether to update.

TopHeight =scrollTop

The calculation of start depends on the topHeight and the height of each item itemHeight. Suppose we move up two list items, then start is 2, so we have start = math.floor (topHeight/itemHeight).

VisibleCount = math.ceil (clientHeight/itemHeight) End = start + visibleCount is rounded up to avoid a small calculation that does not show enough content on the screen. BottomHeight requires that we know the height of the entire list before it was truncated, so subtract the height of the top, and compute the height of the top and it’s easy with end, so let’s say we have a totalItem for the entire list, BottomHeight = (totalitem-end-1) \* itemHeight.

Problems that may arise:

But when this is implemented, there are two problems:

  1. White space appears at the top or bottom of the viewable area when scrolling.
  2. Each scroll to need to put the blanks to replace the actual list item, page will appear jitter, the reason is that each list item height is not consistent, to be replaced, replace the list item than itemHeight big or small, and is replaced in the visible region, the browser will jitter, this solution can advance the timing of replacement, That is, replace it at the top where we can’t see it.

To analyze, to the first question, there will be a white space, then we can have a certain amount of position at the top or bottom, and the second question, can also be through a certain amount of space at the top and bottom, so to solve this problem as long as a solution can be solved, that is at the top and bottom are set aside a certain position.

If “reserveTop” is the number of positions reserved for the top and “reserveBottom” is the number of positions reserved for the bottom, then the calculation of the above data will be redefined.

“ReserveTop” and “reserveBottom” should be as large as possible (but not too large), or if you know what the maximum height of the list item is, stick to it. Increase reserveTop when you see white space at the top and reserveBottom when you see white space at the bottom.

15. There are 100 bottles of water, one of which is poisoned. Mice will die after 3 days if they taste a little of the poisoned water.

Company: Futu

Category: Others

Check the parsing

The answer

7Copy the code

Analysis of the

Each mouse has only two states, dead or alive, so each mouse can be regarded as a bit. 0 or 1N mice can be regarded as N bits, which can express 2^N states (where the NTH state represents the NTH toxic bottle). Therefore, the number of states that all mice can represent can be greater than or equal to 100.

Code implementation

let n = 1;
while (Math.pow(2, n) < 100) {
  n++;
}
console.log(n);
Copy the code

Popular point of understanding:

Label each of the 100 bottles with the following labels (7-bit length) : 0000001 (1st bottle) 0000010 (2nd bottle) 0000011 (3rd bottle)…… 1100100 (Bottle 100)

Take 1 drop from all the bottles with the last digit 1 and mix it together (e.g., from bottle 1, bottle 3… Take a drop and mix it together) and mark it as 1. In this way, take a drop from all the bottles with the number starting with 1, mix it together and mark it as 7. Now you get a mixture of 7 numbers, and the rats line up, 7, 6,… Number 1, and each of them was given the corresponding number of mixture. Three days have passed, come to the autopsy:

From left to right, the dead mice were labeled with a 1, the ones that weren’t were labeled with a 0, and finally a serial number was changed to base 10, the number of the poisoned water bottle.

Check: if the first bottle is toxic, according to 0000001 (the first bottle), it means that the 1st mixture is toxic, so the life and death symbol of the mouse is 0000001 (the mouse numbered 1 died), 0000001 binary label converted to decimal = the 1st bottle is toxic; If bottle 3 is toxic, 0000011 (bottle 3), the mixture of bottle 1 and 2 is toxic, so the mouse’s symbol of life and death is 0000011 (the mouse brother numbered 1 and 2 died), 0000011 binary label converted to decimal = bottle 3 is toxic.

So 2^7 = 128 >= 100, at least 7 mice.

16.Promise. AllSettled? Written Promise. AllSettled

Company: Fast hand

Classification: JavaScript

Check the parsing

Promise.allSettled(可迭代) concept

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
/ / /
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
Copy the code
  1. Promise.allSettled()Method accepts a set ofPromiseInstance as an argument, returns a new Promise instance.
  2. Wait until all of these parameter instances return results, either wayfulfilledorrejected, the wrapping instance will end.
  3. Returns a newPromiseInstance, once finished, the state is alwaysfulfilledWill not becomerejected 。
  4. The newPromiseThe instance passes an array to the listener functionresults. Each member of the array is an object that is passed inPromise.allSettledPromise instance of. Each object has a status property that corresponds tofulfilled  和 rejected 。 fulfilledWhen, the object hasvalueProperties,rejectedFrom time to tomereasonProperty corresponding to the return values of the two states.
  5. This can be useful when we don’t care about the outcome of an asynchronous operation, just whether the operation ends.

Handwritten implementation

const formatSettledResult = (success, value) = >
  success
    ? { status: "fulfilled", value }
    : { status: "rejected".reason: value };

Promise.all_settled = function (iterators) {
  const promises = Array.from(iterators);
  const num = promises.length;
  const resultList = new Array(num);
  let resultNum = 0;

  return new Promise((resolve) = > {
    promises.forEach((promise, index) = > {
      Promise.resolve(promise)
        .then((value) = > {
          resultList[index] = formatSettledResult(true, value);
          if (++resultNum === num) {
            resolve(resultList);
          }
        })
        .catch((error) = > {
          resultList[index] = formatSettledResult(false, error);
          if(++resultNum === num) { resolve(resultList); }}); }); }); };const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
Promise.all_settled([resolved, rejected]).then((results) = > {
  console.log(results);
});
Copy the code

17. Why do browsers block cross-domain requests? How to resolve cross-domain? Does every cross-domain request need to reach the server?

Company: Fast hand

Classification: JavaScript

Check the parsing

First, what is cross-domain

Cross-domain is a term for the same origin policy of browsers. The reason for the same origin policy is network security. The so-called same-origin policy focuses on three things:

  1. Protocol (http:www.baidu.com & https.www.baidu.com httpDifferent protocols, cross domain)
  2. Domain name (https://www.aliyun.com & https://developer.aliyun.comDifferent domain names, cross domain)
  3. Port (http://localhost:8080 & http://localhost:8000Different port numbers, cross-domain)

Which network resources are involved in cross-domain

The same Origin policy is very clear for cross-domain network resources.

These scenarios involve cross-domain disallow operations:

  1. Cookies, localStorage, and indexedDB of non-homogeneous web pages cannot be obtained.
  2. DOM (IFrame) of non-cognate web pages cannot be accessed.
  3. You cannot send AJAX requests or FETCH requests to non-same-origin addresses (you can send, but the browser refuses to accept the response).

Why block cross-domains? As mentioned above, this is based on security policies: for example, if a malicious website’s page has an iframe embedded in the bank’s login page (which has different sources), if there is no same-origin restriction, the javascript script on the malicious website can obtain the user’s username and password when the user logs in to the bank.

3. How to solve cross-domain problems

For how to solve the leapfrog problem, the mainstream solutions are as follows:

Hash + iframe 4. Window. name + iframe 5. PostMessage 6. Cross-domain resource sharing (CORS) 7, Cross-domain nginx proxy 8, cross-domain NodeJS middleware proxy 9, cross-domain WebSocket protocol

4. Issues that need to be clarified across domains

Cross-domain is not restricted by the browser, but cross-site requests can be initiated normally, but the return result is blocked by the browser.

Each time a request is issued, the server responds, but the browser intercepts the response based on the same origin policy.

Note: Some browsers, such as Chrome and Firefox, do not allow cross-domain access to HTTP from the HTTPS domain, and these browsers block requests before they are sent, which is a special case.

18. Browser cache? Where do strong caches reside? How to solve the performance cost of calculating the entire file to get etag? What if I don’t want to use the cache anymore and request the latest one every time? What is the difference between no-store and no-cache?

Company: Fast hand

Category: Network & Security

Check the parsing

First, browser cache

Browser caching is divided into four phases:

  1. Forced cache phase: the resource is searched locally. If the resource is found and has not expired, the resource is used without sending HTTP requests to the server.
  2. Consultation stage cache: if find corresponding resource in the local cache, but don’t know whether the resource is expired or already expired, it sends an HTTP request to the server, and then the server to judge the request, if the request of the resource on the server is not altered, it returns 304, the browser to use the resources found locally.
  3. Heuristic cache phase: When none of the cache expiration fields are available, the browser does not enter the negotiation phase directly next time. Instead, the browser enters the heuristic cache phase, which takes 10% of the time difference between the Date and Last-Modified time fields in the response header as the cache period. That is, when the last-Modified field exists, even after the network is down and the strong cache fails, there is a certain amount of time for the cache file to be read directly. Etag does not have this stage.
  4. Cache failure phase: When the server discovers that the requested resource has been modified, or that it is a new request (the resource was not found), the server returns the data for the resource and returns 200, 404 if the resource was found.

2. Where is the strong cache generally placed

Strong caches are stored in the Memory Cache or Disk Cache.

3, Calculate the entire file to obtain etag will cost performance, how to solve the problem

Etag can be calculated by last-Modified and Content-Length of the file.

Nginx’s default ETag calculation method is “file last modified time hexadecimal – file length hexadecimal”. Example: ETag: “59E72C84-2404”

Note:

No matter what the algorithm is, it has to be calculated on the server side, which has overhead and performance loss. So in order to squeeze out that little bit of performance, many sites have completely disabled Etag (Yahoo! This is actually against HTTP/1.1, which encourages the server to turn on Etag as much as possible.

Fourth, do not use the cache method, so that each request is up to date

The common way to not use caching is to set no-cache by random URL concatenation or cache-control.

No-stroe & no-cache

  • No-store disables browser and intermediate server caching. Get it from the server every time.
    • Note that no-store is really a complete ban on local caching.
  • No-cache verifies that the cache is expired on each request. It can be cached locally, it can be cached on a proxy server, but this cache requires server authentication to be used
    • Note that no-cache does not mean no cache.

19. Tell me how to optimize the usual project. How is it measured after optimization? How is the first screen time calculated?

Company: Fast hand

Category: Others

Check the parsing

Optimize for each process

Web pages go through a series of processes from loading to rendering, and are optimized for each process

  • The network connection
  • Request to optimize
  • Response optimization
  • Browser rendering

Using the Performance. Timing API, you can obtain the execution time of each phase:

{
  navigationStart: 1578537857229; // The timestamp when the previous document unload ended
  unloadEventStart: 1578537857497; // Represents the timestamp when an UNLOAD event is thrown
  unloadEventEnd: 1578537857497; // represents the timestamp when the unload event processing completes
  redirectStart: 0; // The timestamp when the redirect started
  redirectEnd: 0; // The timestamp when the redirect is complete
  fetchStart: 1578537857232; // Prepare the HTTP request to fetch the timestamp of the document
  domainLookupStart: 1578537857232; // Start time stamp for domain queries
  domainLookupEnd: 1578537857232; // The timestamp of the end of the domain query
  connectStart: 1578537857232; // The timestamp when the HTTP request starts being sent to the server
  connectEnd: 1578537857232; // The time stamp when the connection between the browser and the server is established
  secureConnectionStart: 0; // The U timestamp of the handshake for the secure link
  requestStart: 1578537857253; // The timestamp of the HTTP request (or read from the local cache)
  responseStart: 1578537857491; // The timestamp when the server receives (or reads from the local cache) the first byte.
  responseEnd: 1578537857493; // The response is complete
  domLoading: 1578537857504; // The timestamp when the DOM structure starts parsing
  domInteractive: 1578537858118; // The timestamp when the DOM structure finishes parsing and starts loading the embedded resource
  domContentLoadedEventStart: 1578537858118; //DOMContentLoaded Event start timestamp
  domContentLoadedEventEnd: 1578537858118; // The timestamp when all scripts that need to be executed immediately have been executed (regardless of the order of execution)
  domComplete: 1578537858492; // The timestamp when the current document is parsed
  loadEventStart: 1578537858492; // The timestamp when the load event was sent
  loadEventEnd: 1578537858494; // The timestamp when the load event ends
}
Copy the code

1.1 Network connection optimization

It is optimized for redirection, DNS, and TCP connections

  • Avoid redirection
  • DNS lookup optimization: Pages are pre-resolveddns-prefetchAt the same time, put the same type of resources together to reducedomainThe number can also reduce DNS lookups
  • Using CDN (Content Delivery Network)
  • HTTP/1.1, the client can pass Keep-AliveOption to establish a long connection with the server to transfer multiple resources over a single TCP connection.

1.2 Request optimization

Reducing the number of requests the browser sends to the browser and the size of the requested resource is the core idea of request optimization

  • Use file compression and consolidation wisely
    • Make a reasonable balance between the amount of resources loaded and the size of resources by using the browser’s feature of parallel loading
    • On a mobile page, limit the number of resources requested on the first screen to five and the size of each resource after Gzip to 28.5KB, which can significantly improve the first screen time.
  • Compressed images, using Sprite, Base64 inline for small images
  • Component lazy loading
  • To the Cookie diet
    • Static resources are placed in a different domain from the current domain using CDN to avoid cookies when requesting static resources
  • Use CDN to improve browser resource loading capability
    • Resources are distributed across multiple CDNS to maximize the browser’s parallel loading capability
  • Use caching strategies to cache static resources, Ajax responses, and more
    • Make use of Manifest + local storage for persistent caching
    • Other resources that do not require real-time access, such as images and advertising scripts, are stored in IndexDB or WebSQL. After IndexDB, WebSQL has a much larger storage capacity than LocalStorage and can be used to store these resources.
    • Use localForage to persist the cache
    • Library files into the CDN or enable strong caching

1.3 Response Optimization

  • Optimize server processing processes, such as using caching, optimizing database queries, reducing the number of queries, etc
  • Optimize the size of the response resources, for example, enable Gzip compression for the response resources.

1.3.1 Core metrics for page loading

  • TTFB
    • The first byte
  • FP
    • For the first time, only divs and nodes are created, corresponding to the VUE lifecycle
  • FCP
    • The first time there is content to draw, the basic frame of the page, but no data content, corresponding to vUE life cycle Mounted
  • FMP
    • First meaningful draw, with all elements and data content, updated for the VUE lifecycle
  • TTI
    • First interaction time
  • Long Task
    • The task of > = 50 ms
  • SSR&CSR
    • Server-side rendering and client-side rendering
  • Isomorphic javascript
    • TongGouHua

1.4 Optimization of browser first screen rendering

1.4.1 First Screen Time:

The time between the user opening the site and the first screen rendering of the browser. For user experience, the first screen time is an important factor for users to experience a website. Generally, if the first screen time of a website is less than 5 seconds, it is better, less than 10 seconds is acceptable, and more than 10 seconds is unacceptable. If the first screen lasts longer than 10 seconds, the user will choose to refresh the page or leave immediately.

1.4.2 Calculation of first Screen Time:

  • First screen module label

It usually applies to the situation that the content on the first screen does not need to pull data to survive and the page does not consider the loading of resources such as images. We will record the current timestamp in the inline JavaScript code corresponding to the end position of the label on the first screen in the HTML document. As follows:

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>The first screen</title>
    <script type="text/javascript">
      window.pageStartTime = Date.now();
    </script>
    <link rel="stylesheet" href="common.css" />
    <link rel="stylesheet" href="page.css" />
  </head>
  <body>
    <! -- First screen visible module 1 -->
    <div class="module-1"></div>
    <! -- First screen visible module 2 -->
    <div class="module-2"></div>
    <script type="text/javascript">
      window.firstScreen = Date.now();
    </script>
    <! -- The first screen is not visible
    <div class="module-3"></div>
    <! -- First screen not visible module 4 -->
    <div class="module-4"></div>
  </body>
</html>
Copy the code

The first screen time equals firstScreen – performance. Timing. NavigationStart

In fact, the first screen module label method is rarely used in business, most pages need to pull data through the interface to be fully displayed

  • Count the time of the slowest image loading in the first screen:

Generally, the slowest loading of the first screen content is the image resource, so we will take the time of the slowest loading of the first screen as the time of the first screen.

After the DOM tree is built, it will traverse all image tags in the first screen, and listen to all image tags onload event, and finally traverse the maximum load time of image tags, and subtract navigationStart from this maximum to obtain the approximate first screen time.

The first screen pictures of load time is equal to the slowest time order – performance. Timing. NavigationStart

  • Custom first screen content calculation method

It is complicated to calculate the loading time of images in the first screen. Therefore, we usually customize the module content in business to simplify the calculation of the first screen time. As follows:

  • Ignore the loading of resources such as images and only consider the main DOM of the page
  • Consider only the main modules of the first screen, not strictly everything above the first screen line

1.4.3 First-screen Optimization Scheme:

  • Page straight out: skeleton screen or SSR
  • First frame rendering optimized
  • Dynamic resource loading
  • Browser cache
  • Optimize JavaScript script execution time
  • Reduce rearrangement and redraw
  • Hardware acceleration to improve the performance of animation page rendering optimization

1.5 Browser rendering optimization

  • Optimize JavaScript script execution time
  • Reduce rearrangement and redraw
  • Hardware acceleration to improve animation performance

20. How do I calculate how many times a component appears in the viewport? How is IntersectionObserver used? How do YOU know when a DOM node appears in the viewport?

Company: Fast hand

Classification: JavaScript

Check the parsing

First, monitor Scroll

To know whether an element has entered the viewport, that is, whether the user can see it, the traditional implementation method is to listen to the Scroll event, call the getBoundingClientRect() method of the target element, get its coordinates corresponding to the upper left corner of the viewport, and then determine whether it is in the viewport. Then declare a global variable and increment it by one each time it occurs to see how many times it occurs in the viewport. The disadvantage of this method is that it is easy to cause performance problems due to the intensive occurrence of Scroll events and large amount of computation.

Hence the IntersectionObserver API

Second, the IntersectionObserver

2.1 API

var io = new IntersectionObserver(callback, option);
Copy the code

In the above code, IntersectionObserver is the constructor provided natively by the browser and takes two parameters: callback is the callback function when visibility changes and option is the configuration object (this parameter is optional).

The return value of the constructor is an observer instance. The observe method of the instance specifies which DOM node to observe.

// Start observing
io.observe(document.getElementById("example"));

// Stop observing
io.unobserve(element);

// Close the viewer
io.disconnect();
Copy the code

In the code above, the argument to Observe is a DOM node object. Call this method multiple times if you want to observe multiple nodes.

io.observe(elementA);
io.observe(elementB);
Copy the code

2.2 the Callback parameter

When the visibility of the target element changes, the observer’s callback function is called.

Callback typically fires twice. Once the target element has just entered the viewport (becoming visible), and once it has completely left the viewport (becoming invisible).

var io = new IntersectionObserver((entries) = > {
  console.log(entries);
});
Copy the code

The parameters of the callback function (entries) is an array, each member is a IntersectionObserverEntry object. If the visibility of two observed objects changes at the same time, the Entries array will have two members.

IntersectionObserverEntry object provides a target element of information, a total of six attributes.

{
  time: 3893.92.rootBounds: ClientRect {
    bottom: 920.height: 1024.left: 0.right: 1024.top: 0.width: 920
  },
  boundingClientRect: ClientRect {
     // ...
  },
  intersectionRect: ClientRect {
    // ...
  },
  intersectionRatio: 0.54.target: element
}
Copy the code

The meaning of each attribute is as follows.

  • time: The time at which visibility changes, a high-precision timestamp in milliseconds
  • target: The object element being observed is a DOM node object
  • rootBounds: information about the rectangular region of the root element,getBoundingClientRect()Method, if there is no root element (that is, scrolling directly with respect to the viewport)null
  • boundingClientRect: Information about the rectangular region of the target element
  • intersectionRect: Information about the area where the target element intersects with the viewport (or root element)
  • intersectionRatio: Visibility ratio of the target element, i.eintersectionRectAccount forboundingClientRectIs fully visible1Is less than or equal to completely invisible0

2.3 Option object

The second argument to the IntersectionObserver constructor is a configuration object. It can set the following properties.

2.3.1 Threshold Attribute:

The threshold attribute determines when the callback function is triggered. It is an array and each member is a threshold value, which defaults to [0], i.e., intersectionRatio triggers the callback function when it reaches 0.

new IntersectionObserver(
  (entries) = > {
    / *... * /
  },
  {
    threshold: [0.0.25.0.5.0.75.1]});Copy the code

The user can customize the array. For example, [0, 0.25, 0.5, 0.75, 1] means that the callback is triggered when the target element is 0%, 25%, 50%, 75%, 100% visible.

2.3.2 Root attribute and rootMargin attribute:

Many times, the target element will scroll not only with the window, but also inside the container (such as in an iframe window). Scrolling within the container also affects the visibility of the target element.

The IntersectionObserver API supports intra-container rolling. The root attribute specifies the container node on which the target element is located (the root element). Note that the container element must be the ancestor node of the target element.

var opts = {
  root: document.querySelector(".container"),
  rootMargin: "500px 0px"};var observer = new IntersectionObserver(callback, opts);
Copy the code

In addition to the root attribute, there is the rootMargin attribute in the above code. The latter defines the margin of the root element, which is used to expand or reduce the size of the rootBounds rectangle and thus affect the intersectionRect area. It uses CSS definitions such as 10px, 20px, 30px, 40px for top, right, bottom, and left.

This allows the viewer to be triggered whenever the visibility of the target element changes, whether it is window scrolling or container scrolling.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — a speak of wushu line — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Due to the word limit of the nuggets post, the rest of the answers can be viewed by scanning the code.

21. Versions is a list of version numbers of a project. Due to irregular maintenance by several people, a version number processing function is implemented

var versions = ["1.45.0"."1.5"."6"."3.3.3.3.3.3.3"];
// Order from smallest to largest, note that '1.45' is larger than '1.5'
function sortVersion(versions) {
  // TODO
}
/ / = > [' 1.5 ', '1.45.0', '3.3.3.3.3.3', '6']
Copy the code

Company: Top Story

Classification: JavaScript

22. What are microservices, what is the difference between microservices and individual applications, and what are the benefits of using microservices?

Classification: the Node

23. Implement a repeat method

function repeat(func, times, wait) {
  // TODO
}
const repeatFunc = repeat(alert, 4.3000);
RepeatFunc (" hellWorld ") will alert HELLOWorld three times each time
Copy the code

Company: Top Story

Classification: JavaScript

24. Please list the current mainstream JavaScript modular implementation technologies. Tell the difference?

Company: Xuanwu Technology

Classification: JavaScript

25. Please describe the concepts of Scope, Closure and Prototype in JavaScript, and explain the implementation principles of JavaScript encapsulation and inheritance.

Company: Xuanwu Technology

Classification: javascript