Vue-related high-frequency interview questions

The difference between mwvm and mvc

Both MVVM and MVC are common software architectural patterns, they are somewhat similar, but there are some differences.

MVC (Model-View-Controller) is a software architecture pattern that divides applications into three main components: Model (Model), View (View) and Controller (Controller). Among them, the model is the core component of the application, representing the data and business logic of the application; the view is the user interface of the application, representing the appearance of the data; the controller is responsible for processing user input and data flow, passing user requests to the model and updating view. MVC divides the application into different concerns, making the application easier to develop, test and maintain.

MVVM (Model-View-ViewModel) is a software architecture pattern based on MVC, and its core is ViewModel. ViewModel is an intermediate layer for displaying data and interacting with users, which connects the view and the model. Unlike MVC, the ViewModel in MVVM is responsible for converting model data into the format required by the view, as well as receiving and processing user input. This makes the view less coupled to the model and easier to develop and maintain.

Therefore, the difference between MVVM and MVC is that MVVM has an additional ViewModel layer, which is used to convert model data into the format required by the view and pass user input to the model. This results in less coupling between the view and the model, and makes the application easier to develop and maintain.

In vue, the understanding of responsive data

In Vue, responsive data means that when the data in the Vue instance changes, Vue will automatically detect and notify the relevant components to re-render the view.

The core of Vue's implementation of responsive data is to define a property's getter and setter through the Object.defineProperty() method. In Vue, each component instance has its own reactive data object, called the data object. When the property in data is accessed, Vue will track this property through the getter and add the component instance to a list of subscribers. When this property is modified, Vue will update this property through the setter and notify the component instances in the subscriber list to re-render.

Using responsive data allows Vue to implement two-way binding between data and views. When data changes, the view will be automatically updated, and vice versa. At the same time, using responsive data can also make it easier for developers to manage the data state, because there is no need to manually perform DOM operations, but let Vue automatically manage view updates. However, it should be noted that since Vue's data hijacking mechanism is implemented through the Object.defineProperty() method, it is necessary to use some special methods provided by Vue (such as push(), splice(), etc.) to change the array. Trigger a reactive update.

Compared with vue3 and vue2, what changes have been made in responsive data

1. Use Proxy instead of Object.defineProperty()

In Vue 3, the implementation of responsive data uses the Proxy object instead of the Object.defineProperty() method. Compared with Object.defineProperty(), the Proxy object has more powerful and flexible functions. It can directly proxy the entire object instead of just the properties in it, and supports dynamic property addition and deletion.

2. Support monitoring of nested properties

In Vue 3, nested properties in objects and arrays can also be monitored and updated responsively. This makes it easier for Vue 3 to manage complex data structures and enable responsive updates to data of any depth.

3. Improved responsive update of arrays

In Vue 3, the responsive update of arrays has been optimized and improved, using a mechanism similar to React to avoid unnecessary re-rendering. At the same time, Vue 3 also provides some new APIs (such as toRefs(), reactive(), etc.) to handle the responsive update of arrays more conveniently.

4. Improved the performance of initialization

In Vue 3, the performance during initialization is optimized, and lazy initialization is used to avoid unnecessary performance consumption. This means that reactive data is only initialized when the component actually needs to use it, rather than immediately upon component creation. This allows Vue 3 to handle large and complex components more efficiently.

To sum up, Vue 3 has made many major improvements in responsive data. These improvements make Vue 3 more flexible, efficient and easy to use, and can better deal with complex data structures and large-scale applications. (In vue2, Options API is the main way to write component code, while vue3 is Composition API, but in Vue 3, Options API is still available)

In vue, the process of template compilation (how to convert from template to real Dom)

In Vue, the process of template compilation mainly includes the following steps:

1. Parse the template

Vue's template compiler parses the template string into an Abstract Syntax Tree (AST), which recognizes various grammatical structures in the template, such as tags, attributes, directives, and more.

2. Generate rendering function

According to the parsed AST, Vue's template compiler will generate the corresponding rendering function. A render function is a function that returns a virtual DOM that describes how to render a component into the final HTML.

3. Optimize the rendering function

After generating the rendering function, Vue will perform some optimizations on the rendering function to improve rendering performance. These optimizations include static node promotion, event listener caching, and more.

4. Create virtual DOM

When a component needs to be rendered, Vue will call the rendering function to generate a virtual DOM (Virtual DOM), which is a JavaScript object that describes the real DOM.

5. Update the virtual DOM

When the data in the component changes, Vue will call the rendering function again to generate a new virtual DOM. Vue will calculate the parts that need to be updated by comparing the difference between the old and new virtual DOM, and then update these parts to the real DOM.

6. Render the real DOM

Finally, Vue will render the updated virtual DOM into real DOM and insert it into the document.

To sum up, the process of Vue's template compilation can be simply summarized as: parsing templates, generating rendering functions, optimizing rendering functions, creating virtual DOM, updating virtual DOM, and rendering real DOM.

In vue, the usage scenarios and advantages and disadvantages of Mixin

Mixins are a way in Vue to share logic between components. It allows us to reuse the same code snippet in multiple components, thus improving code reusability and maintainability.

Mixin usage scenarios:

  1. Multiple components have similar functional logic, but do not want to repeat the code.
  2. I want to reuse the functional logic of another component in one component.

Advantages of mixins:

  1. Improve code reusability: Mixin allows us to reuse the same code fragments in multiple components, reducing the writing of repeated code.
  2. Improve maintainability: Mixin can separate component logic, reduce code coupling, and improve code maintainability.
  3. Improve development efficiency: Mixin allows us to quickly implement component logic and save development time.

Disadvantages of mixins:

  1. Naming conflict: If the same property or method is defined in multiple Mixins, it will cause a naming conflict and cause a program error.
  2. Code complexity: If too many Mixins are used, the code will become complex and difficult to maintain.
  3. Difficult state management: Since the state in a mixin may be used by multiple components, state management can become difficult.

To sum up, Mixin can improve the reusability and maintainability of code, but you need to pay attention to issues such as naming conflicts, code complexity, and state management. When using Mixin, you should choose Mixin reasonably to avoid abuse and excessive dependence.

In vue, why does Data have to be a function

In Vue components, if the Data option is a pure object, it will cause the data of the object to be shared among all component instances. This means that if one component modifies the object's properties, all other components using that object's properties will also be modified, leading to unpredictable behavior in the program.

To prevent this from happening, Vue enforces that the Data option must be a function that returns an object. Each component instance will call this function and return its own data object, so that each component instance will have an independent data object, thereby avoiding the problem of data sharing.

Simply put, Data must be a function, so that every time a new component instance is created, a new data object will be created for the instance, thus avoiding the problem of data sharing. If Data is an object, then all component instances will share the same data object, resulting in data conflicts.

In vue, how is NextTick implemented, what are macro/micro tasks and the types of macro/micro tasks, and the execution order of macro/micro tasks

nextTick()The method in Vue is the method used to execute the callback function after the DOM update is completed. In Vue's responsive update process, sometimes it is necessary to perform some operations after the DOM update is completed, such as obtaining the position information of the DOM element, etc. At this point, you can use nextTick()the method to delay the execution of these operations to ensure that they are not executed until the DOM update is complete.

nextTick()The implementation principle is to use the browser's macro/micro task mechanism. Macrotasks and microtasks are two ways of executing code asynchronously in JavaScript.

Macro tasks include:

  • setTimeout and setInterval
  • I/O operations
  • DOM rendering

Microtasks include:

  • Promise.then 和 Promise.catch
  • MutationObserver
  • Object.observer
  • process.nextTick (Node.js)

After a macrotask is executed, it will check whether there are microtasks to be executed, and if so, execute all tasks in the microtask queue until the microtask queue is empty, and then execute the next macrotask. So you can use this mechanism to put the callback function in the microtask queue to ensure that it is executed after the DOM update is completed.

Specifically, the implementation of nextTick()the method can be divided into the following steps:

  1. Put the callback function into an array.
  2. Determine whether there is already an asynchronous task being executed, if not, create an asynchronous task and execute all the callback functions in the array.
  3. If there is already an asynchronous task executing, the callback function is only added to the array waiting to be executed.

Generally speaking, nextTick()the implementation of the method is to use the browser's asynchronous task mechanism, add the callback function to the microtask queue, and execute the callback function after the DOM update is completed.

It should be noted that in Vue 3, nextTick()the implementation of the method has changed, and a new asynchronous execution mechanism-scheduler is adopted. But the basic principle is the same, they all use the browser's macro/micro task mechanism to implement asynchronous task execution.

How Vue.set is implemented

Vue.set is a global method provided by Vue.js for adding properties to responsive objects and triggering view updates.

In Vue.js, the properties of the responsive object are turned into getters and setters through the Object.defineProperty() method. When the property is accessed or modified, a responsive update will be triggered.

However, when a new property is added to an already created object, Vue.js does not handle this new property reactively. At this point, you can use the Vue.set() method to manually turn the new property into a responsive property and trigger a view update.

The implementation principle of the Vue.set() method is to set the getter and setter for the new property by calling the defineReactive() method to achieve responsive processing. In this process, you also need to use JavaScript's Object.defineProperty() method to add getters and setters for new properties to achieve responsive updates.

The following is a pseudocode implementation of the Vue.set() method:

function set(target, key, value) {
  if (Array.isArray(target) && typeof key === 'number') {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, value)
    return value
  }

  if (key in target && !(key in Object.prototype)) {
    target[key] = value
    return value
  }

  const ob = target.__ob__
  if (!ob) {
    target[key] = value
    return value
  }

  defineReactive(ob.value, key, value)
  ob.dep.notify()
  return value
}

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      return val
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
      // 触发更新
    }
  })
}

Among them, the set() method receives three parameters, which are target object target, property name key and property value value. First, if the target object is an array and the attribute name is a number, call the splice() method of the array to change the array and return the new attribute value.

If the attribute name already exists in the target object, it is assigned directly. If the attribute name does not exist, the ob object of the target object is obtained , and if the ob object does not exist, the value is assigned directly. Otherwise, call the defineReactive() method to make the property reactive and trigger an update.

The defineReactive() method receives three parameters, which are the target object obj, attribute name key and attribute value val. Reactive updates are achieved by setting getters and setters for properties through the Object.defineProperty() method. When the property value is modified, the setter method is triggered, which triggers a reactive update.

Understanding of virtual Dom (display of any form of DOM), how to represent virtual DOM with pure js

Virtual DOM (Virtual DOM) is one of the core concepts of front-end frameworks such as React and Vue. It is a lightweight JavaScript object used to describe the real DOM structure. Through the operation of the virtual DOM, the update of the real DOM can be minimized, thereby improving front-end performance and user experience.

The virtual DOM consists of a tree structure represented as JavaScript objects (or JSON). Each node represents a DOM element, including the element's tag name, attributes, events, and other information, as well as the element's child elements (if any).

Here is a simple virtual DOM example:

{
  tag: 'div',
  attrs: {
    class: 'wrapper'
  },
  children: [
    {
      tag: 'h1',
      attrs: {},
      children: 'Hello World!'
    },
    {
      tag: 'p',
      attrs: {},
      children: 'This is a paragraph.'
    }
  ]
}

In this example, the root node is a div element with a class attribute of wrapper, and the two child nodes are an h1 element and a p element.

In Vue.js, the virtual DOM is represented by a class called VNode. The constructor of VNode is as follows:

class VNode {
  constructor(tag, data, children, text, elm) {
    this.tag = tag          // 标签名
    this.data = data        // 属性值
    this.children = children  // 子节点
    this.text = text        // 文本内容
    this.elm = elm          // 对应的真实 DOM 节点
  }
}

In this constructor, tag represents the tag name, data represents the attribute value, children represents the child node, text represents the text content, and elm represents the corresponding real DOM node.

For pure JavaScript code, the virtual DOM can be represented by an object, similar to the example above. For example, you can define a function called h that creates a virtual DOM:

function h(tag, props, ...children) {
  return {
    tag,
    props,
    children
  }
}

const vnode = h('div', { class: 'wrapper' },
  h('h1', {}, 'Hello World!'),
  h('p', {}, 'This is a paragraph.')
)

This function receives three parameters, which are the tag name, attributes and child nodes, and returns a JavaScript object representing a virtual DOM node. Through this function, you can easily create a virtual DOM without directly manipulating the DOM, thereby improving the maintainability and readability of the code.

Principle of Diff algorithm

In the front-end framework, how to efficiently update the virtual DOM is an important issue. When data changes, the entire virtual DOM usually needs to be re-rendered, which consumes a lot of computing resources and affects application performance. In order to solve this problem, the front-end framework introduces the Diff algorithm (also known as the Virtual DOM Diff algorithm), which is used to find the changed parts in the virtual DOM, thereby minimizing the update of the real DOM.

The principle of the Diff algorithm is based on the following two assumptions:

  1. Two different nodes have different labels, and their content and attributes are also different.
  2. The same components generate the same DOM structure, and different components generate different DOM structures.

According to these two assumptions, the implementation process of the Diff algorithm can be summarized as the following steps:

  1. First, compare the new virtual DOM tree with the old virtual DOM tree to find out what changed.
  2. If a node existed in the old virtual DOM but not in the new virtual DOM, it means that the node was deleted and needs to be removed from the real DOM.
  3. If a node exists in the new virtual DOM but does not exist in the old virtual DOM, it means that this node is new and needs to be added to the real DOM.
  4. If a node exists in both the new virtual DOM and the old virtual DOM, it is necessary to further compare their attributes and child nodes to determine whether the node needs to be updated.
  5. For nodes at the same level, the Diff algorithm will use some heuristic algorithms to reduce the number of comparisons as much as possible.

Diff algorithm can greatly improve the update performance of virtual DOM, but there are some problems. For example, in some cases, the Diff algorithm may not be able to accurately determine which nodes have changed, resulting in invalid DOM updates. In addition, due to the high complexity of the comparison algorithm, the implementation of the Diff algorithm is also relatively complex and requires a large amount of computing resources. Therefore, the front-end framework usually combines other technologies, such as asynchronous update and batch update, to further improve the performance of the application.

understanding of components

In front-end development, a component (Component) refers to a reusable, independent, code block with specific functions, which is used to build a user interface. The design and use of components can help developers improve code reusability and maintainability, reduce code coupling and repetition, thereby accelerating application development and iteration.

Components usually consist of three parts:

  1. Template (Template): Used to define the appearance and layout of components, usually written in HTML and CSS languages.
  2. Data (Data): Used to store the internal state and properties of components, usually managed using JavaScript objects.
  3. Behavior: Used to define the interaction and logic of a component, usually implemented using JavaScript methods and events.

Key features of the component include:

  1. Reusability: Components can be reused in different pages and applications, reducing code duplication and development time.
  2. Independence: Components have independent functions and styles, and have no coupling relationship with other parts of the application, thereby improving the maintainability and testability of the code.
  3. Scalability: Components can be expanded and customized according to application requirements, so as to adapt to different business scenarios and user needs.
  4. Composability: Components can be combined into more complex components, resulting in richer and more diverse user interfaces.

In front-end development, common components include buttons, forms, lists, navigation bars, dialog boxes, etc. Component-based development has become an important trend in modern front-end development. Various frameworks and libraries (such as React, Vue, Angular, etc.) provide rich component libraries and component-based development tools to help developers more easily and efficiently build complex User Interface.

In vue, the rendering\update process of components

  1. Template compilation: After the template of the Vue component is compiled, it will be converted into a render function or render function.
  2. Instantiate component: Create a Vue component instance, which is a component option in the options object in new Vue(options).
  3. Rendering: Execute the render function of the component or the rendering function converted from the template, and convert the virtual DOM into a real DOM.
  4. Mount: Mount the real DOM rendered by the component into the page.
  5. Update: When the data in the component changes, Vue will re-execute the rendering function, generate a new virtual DOM, and update the page by comparing the difference between the old and new virtual DOM.

In the update process, Vue will compare the difference between the old and new virtual DOM through the Diff algorithm, and then reuse the existing DOM elements as much as possible to reduce unnecessary DOM operations and improve the performance of page updates. During the update process, if subcomponents need to be updated, the subcomponent update process will be executed recursively.

Finally, when the component is destroyed from the page, the beforeDestroy and destroyed life cycle hook functions of the component will be triggered to perform some cleaning tasks, such as clearing timers, unbinding events, etc.

In vue, the difference between ordinary slots and scoped slots

In Vue, a slot is a mechanism for distributing the content of a component to a specified location inside the component. There are two types of slots in Vue, normal slots and scoped slots.

Ordinary slot is the most basic form of slot, it is to reserve a position in the component, so that the parent component can insert any content into it. In the parent component, fill the slot by including the child element in the component tag. <slot>The element is used in the component to define the position of the slot, as shown below

<template>
  <div>
    <h1>我是子组件</h1>
    <slot></slot>
  </div>
</template>

In the parent component, any content can be inserted into this slot:

<template>
  <div>
    <h2>我是父组件</h2>
    <Child>
      <p>我是插入到子组件中的内容</p>
    </Child>
  </div>
</template>

Scoped slots are a mechanism by which data can be passed to a slot. By defining a named slot in the child component, the parent component can affect the rendering result of the child component by passing data into the slot. Subcomponents can declare the parameters of the slot through slot-scopethe attribute , and the parent component can pass data to the slot through an object with specific parameters when using the slot.

Here's an example using scoped slots:

<!-- 子组件 -->
<template>
  <div>
    <h1>我是子组件</h1>
    <slot name="content" v-bind:user="user"></slot>
  </div>
</template>

<!-- 父组件 -->
<template>
  <div>
    <h2>我是父组件</h2>
    <Child>
      <template slot="content" v-slot:default="slotProps">
        <p>欢迎你,{
   
   { slotProps.user.name }}</p>
      </template>
    </Child>
  </div>
</template>

In the above example, the slot in the child component defines a userparameter , and the parent component v-slot:default="slotProps"declares the slot parameter through when using the slot, and passes a userobject . In the content of the slot, the parameters passed in can be accessed slotPropsthrough .

In general, normal slots are for when you need to insert arbitrary content, while scoped slots are for when you need to pass data.

In vue, the scenarios and principles used by Keep-alive

<keep-alive>It is a built-in component of Vue, which can cache component instances to avoid repeated rendering. <keep-alive>Dynamic components can be wrapped and it will cache inactive component instances instead of destroying them. When the component is activated again, it will be retrieved from the cache and reuse the previous instance instead of creating a new instance.

<keep-alive>There are two main scenarios for using :

  1. Some components need to be re-rendered every time they are switched, but the content of these components remains unchanged. In order to improve performance, you can use <keep-alive>to .
  2. Some components need to re-acquire data every time they switch. If they are not cached, they will re-request data every time they switch, which will cause unnecessary network requests and server pressure. At this time, you can use <keep-alive>to cache, and the cached data can be used directly when the component is activated, avoiding repeated requests for data.

<keep-alive>The principle is to use a cache object cacheto store component instances. Every time a dynamic component is switched, it will first go to the cache to find out whether there is a corresponding instance. If there is, the instance in the cache will be used directly. If not, a new instance will be created. and cache it. When the component is switched, the instance in the cache will not be destroyed, but will be cached. When the component is activated again, the instance will be taken out of the cache and reused.

It should be noted that when the component using <keep-alive>the cache is activated, the and hookcreated functions will not be triggered, but the and hook functions will be triggered. Therefore, special attention should be paid to the use of lifecycle hook functions when caching components.mountedactivateddeactivated

What are the two modes of Vue-router, and what are the differences?

Vue Router supports two modes: hash mode and history mode.

  • Hash mode: Use the hash of the URL (that is, the content after # in the URL in the address bar) to simulate a complete URL, so the page will not request data from the server, which is suitable for single-page applications.
  • History mode: Use the HTML5 history API to change the URL without reloading the page. It can support operations such as forward and backward more naturally, and requires the support of the server.

In the hash mode, the change of the route will not trigger the browser to request the server, but the hash of the URL has changed, so the page corresponding to the current route can still be displayed normally after the page is refreshed. In the history mode, the change of the route will trigger the browser to request the corresponding resources from the server. If the server does not configure the corresponding routing rules, it will return a 404 error. Therefore, when using the history mode, you need to configure the routing rules of the server to support page refresh and access when the routing changes.

Understanding of Vuex

Vuex is a state management library officially provided by Vue.js, which is used to centrally manage shared state in Vue.js applications. Vuex can help us better organize and manage the state of the application in large single-page applications, making the code more structured and easier to maintain.

In Vuex, we can store the application's shared state in a global Store object. This Store object contains multiple modules, and each module has its own state, mutation, action, and getter. In the component, we can use the auxiliary functions mapState, mapMutations, mapActions and mapGetters provided by Vuex to simplify the code for accessing the state in the Store in the component.

The core concepts of Vuex include:

  • State: It is the state in the application, which can be considered as a container for storing data.
  • Mutation: used to modify the state in State, it must be a synchronous function.
  • Action: Similar to Mutation, it is also used to modify the state in State, but it can contain asynchronous operations, and Mutation can be submitted in Action.
  • Getter: Used to calculate the state in the Store and return the calculation result.

In short, Vuex can help us better manage the state of the application, avoiding confusion and duplication of code when passing data between components. It makes state changes traceable, maintainable, and shared across the application. (vue3 launches pinia)

What happens when npm run xx

When using the npm run xx command in a project, npm will run the specified script command according to the configuration in the "scripts" section of the package.json file in the project.

Specifically, the npm run command will find the corresponding executable file in the system environment variable PATH, then execute the executable file, and pass the parameters defined in the script in package.json to the executable file. This allows custom scripts defined in the package.json file to be executed.

When executing this custom script, npm will set the root directory of the project as the current working directory, and add some additional environment variables to the environment variables of the process, such as including the installation path of the current project, etc.

Usually, the npm run xx command is used to execute some predefined script commands, such as building applications, starting local servers, running tests, etc. These script commands can be easily run in the project, thus improving the development efficiency.

js related interview questions

In js, the basic data type, the difference between symbol type and ordinary type, what is the packaging type

In JavaScript, basic data types include Undefined, Null, Boolean, Number, BigInt, Symbol, and String. The Symbol type is a new data type in ES6. It is a unique, immutable data type used to create unique property names for objects. Unlike the basic data types, the value of the Symbol type is unique, and each Symbol value is unique.

The difference between basic data types and Symbol types and ordinary types is that basic data types and Symbol types are primitive values, and their values ​​cannot be changed. Ordinary types are objects, which can contain multiple properties and methods. When we use basic data types or Symbol types, JavaScript will automatically encapsulate them into corresponding packaging types, that is, objects. These wrapper types provide many useful methods, such as methods for operating on strings, numbers, etc.

Wrapper type refers to the object automatically created by JavaScript, which is used to encapsulate the value of basic data type and Symbol type. For example, when we use the string method, JavaScript will automatically create a String object, which contains the operation method on the string. When we're done, this object is destroyed, leaving only the original string value. Similarly, when we use the number method, JavaScript will automatically create a Number object, which contains the operation method on the number.

It should be noted that since the wrapper type is a temporarily created object, when comparing the underlying data type and the Symbol type, the identity operator (=) instead of the equality operator () to avoid the effects of type conversion.

In js, the method of type verification is different from

  1. typeof operator: It can be used to check the type of a value and returns a string representing the type of the value. For example, typeof 123 returns "number" and typeof "hello" returns "string". Note that typeof null returns "object", which is a legacy issue.
  2. instanceof operator: Can be used to check whether an object is an instance of a certain class. For example, x instanceof Array can check whether x is an instance of the Array class. It should be noted that instanceof checks the prototype chain of the object, so the instanceof operator cannot be used for basic data types and Symbol types.
  3. Object.prototype.toString method: It can return the type string of an object. For example, Object.prototype.toString.call(“hello”) returns "[object String]" and Object.prototype.toString.call(123) returns "[object Number]". This method can be used to check basic data types and Symbol types.
  4. typeof and instanceof can be used to check the type of a value, and the Object.prototype.toString method can be used to check the type of an object.

It should be noted that JavaScript is a dynamically typed language, and the type of variables can change at runtime, so type checking is very important. In development, type checking should be used as much as possible to reduce errors.

In js, how to solve the floating point precision problem

In JavaScript, floating-point numbers have precision issues. This is because JavaScript uses the IEEE 754 standard to represent numbers, and this standard uses binary to represent decimals, resulting in some decimals that cannot be represented precisely. For example, 0.1 is an infinitely recurring decimal in binary, so it cannot be represented precisely, and something like 0.10000000000000001 may appear.

In order to solve the problem of floating-point precision, the following methods can be used:

  1. Calculations using integers: convert the decimal to an integer, perform the calculation, and convert the result back to a decimal. For example, multiplying a decimal by a multiple and then dividing by that multiple yields the corresponding result.
  2. Use the toFixed method: This method rounds a number to the specified number of decimal places and returns a string representing the number. For example, (0.1 + 0.2).toFixed(1) returns "0.3". It should be noted that toFixed returns a string, which needs to be converted to a number using parseFloat.
  3. Use third-party libraries: Some third-party libraries, such as Big.js and Decimal.js, provide higher-precision calculation methods that can solve floating-point precision problems.

It should be noted that when performing floating-point calculations, you should try to avoid directly comparing whether two floating-point numbers are equal, because due to precision issues, two seemingly equal floating-point numbers may not be equal. Some tolerance value should be used to judge whether two floating point numbers are equal, such as Math.abs(a - b) < 0.00001.

what happens with new a function

When using newthe operator to create an instance of a function, JavaScript performs the following steps:

  1. Creates a new object whose prototype is the constructor's prototypeproperty .
  2. thisSet the keyword to the newly created object.
  3. Execute the constructor while passing parameters to the constructor.
  4. If the constructor returns an object, that object will be returned as the result of newthe operator . Otherwise, the object created in step 1 will be returned.

During this process, keywords newmainly do the following two things:

  1. A new object is created, and the prototype of this object is pointed to prototypethe property .
  2. Point thisthe keyword to this new object, so that the object can be accessed inside the constructor, and the properties and methods inside the constructor are bound to this new object.

It should be noted that when using newthe operator to create an instance of a function, JavaScript will automatically execute the constructor of the function, so the instance can be initialized inside the constructor and attributes and methods can be added to the instance. At the same time, you need to pay attention not to return the basic data type directly inside the constructor, otherwise newthe operator will not be able to return an object.

The difference between arrow function and ordinary function

Arrow functions and ordinary functions have the following differences in syntax and usage:

  1. Arrow functions are defined using =>the symbol , and ordinary functions functionare defined using the keyword.
  2. Arrow functions do not have their own this, thisand inherit their values ​​from the parent scope this. However, thisthe value is determined by the method of calling. If it is called through an object, then thispoints to the object. If it callis applycalled through or , then thispoints to the first parameter passed. If it is called directly, then thispoints to the global object (in in strict mode undefined).
  3. Arrow functions cannot use argumentsobjects , and can use rest parameters ...instead. Ordinary functions can use argumentsthe object to get all passed parameters.
  4. Arrow functions cannot be instanced using newthe operator , because arrow functions have no own thisand no prototypeproperties . Ordinary functions can use newthe operator to create instances.
  5. Arrow functions cannot be used as constructors because arrow functions have no propertiesthis of their own. prototypeOrdinary functions can be used as constructors.
  6. returnThe statement of an arrow function automatically returns the value of the expression without using returnthe keyword. Ordinary functions need to use returnthe keyword to return a value. (In fact, returnthe statement can be used to return the value of the expression, but in the case of only one expression, returnthe keyword can be omitted and the value of the expression will be returned automatically.)

It should be noted that the usage of arrow functions and ordinary functions is different, and should be selected according to the actual situation. Arrow functions are usually used to simplify code and reduce the amount of code, while ordinary functions are more flexible and suitable for complex logic processing.

How to modify the point of this, the difference between call, apply, and bind

In JavaScript, we can use call, apply, bindto modify the pointer thisin .

These three methods can temporarily modify the pointer thisin :

  • callBoth method and applymethod call the function immediately, the first parameter is thisthe pointer inside the function, the following parameters are the parameters of the function (can be multiple), and applythe parameter of the method is an array.
  • bindThe method returns a new function, the new function thispoints to the first parameter passed in, and the subsequent parameters will be used as parameters of the new function. Note that bindthe method does not call the function immediately, but returns a new function that needs to be called manually.

Here is an example using callthe , apply, bindmethods:

const person = {
  name: 'John',
  greet: function(greeting) {
    console.log(`${greeting}, ${this.name}!`);
  }
};

person.greet('Hello'); // 输出:Hello, John!

const anotherPerson = {
  name: 'Alice'
};

// 使用 call 方法调用 person.greet(),this 指向 anotherPerson
person.greet.call(anotherPerson, 'Hi'); // 输出:Hi, Alice!

// 使用 apply 方法调用 person.greet(),this 指向 anotherPerson
person.greet.apply(anotherPerson, ['Hey']); // 输出:Hey, Alice!

// 使用 bind 方法创建一个新函数 newGreet,this 指向 anotherPerson
const newGreet = person.greet.bind(anotherPerson);
newGreet('Good morning'); // 输出:Good morning, Alice!

callThe main difference between , , and the three lies in the method of passing parameters and the method of calling the function, and applythe method will immediately call the function and pass the parameters, while the method will not call the function immediately, but return a new function.bindcallapplybind

In general, using these three methods can flexibly modify the pointer thisin , which needs to be selected according to the specific scenario.

Difference between deep and shallow copy

In JavaScript, when we want to copy an object, we may use two different copy methods: shallow copy and deep copy. Their differences are as follows:

  1. shallow copy:

Shallow copy will create a new object, but this new object will only copy one layer of properties of the original object, if a property of the original object is a reference type, then this property in the new object still points to the reference in the original object, so the Modifications to this property in the new object will affect the original object. For example:

const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

shallowCopy.b.c = 3;

console.log(obj); // { a: 1, b: { c: 3 } }
console.log(shallowCopy); // { a: 1, b: { c: 3 } }

In the above code, we use Object.assignthe method to create a shallow copy object shallowCopy, and then shallowCopymodify b.cthe value of the attribute in the original object. It is found that the value of the attribute objin b.chas also been modified, indicating that the shallow copy only copies one layer of attributes.

  1. Deep copy:

Deep copy will recursively copy all the attributes of the object, including the reference type attributes in the original object, until all the attributes are of basic data types. Therefore, a deep copy will create a brand new object, and modifying the properties in the new object will not affect the original object. For example:

const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));

deepCopy.b.c = 3;

console.log(obj); // { a: 1, b: { c: 2 } }
console.log(deepCopy); // { a: 1, b: { c: 3 } }

In the above code, we use to JSON.parse(JSON.stringify(obj))perform a deep copy, modify the value of the attributedeepCopy in the original object, and find that the value of the attribute in the original object has not been modified, indicating that the deep copy has created a brand new object.b.cobjb.c

It should be noted that there are some restrictions on JSON.parse(JSON.stringify(obj))using deep copy, such as the inability to copy functions, circular references, etc., so in actual use, you need to choose the appropriate deep copy method according to the specific situation. (can be done recursively)

In general, shallow copy only copies one layer of attributes, and deep copy recursively copies all attributes to create a brand new object. The two copy methods are suitable for different scenarios. You need to choose the appropriate copy method according to the specific situation.

Guess you like

Origin blog.csdn.net/lFFFFFFl/article/details/129244677