The problem the forerunner

  • Talk about Webworkers [HTML]
  • Understanding the Box Model [CSS]
  • What’s the difference between using Translate and Position to position elements? “CSS”
  • The operator|,||,&and&&The difference between? [js operator]
  • = =,= = =andObject.is()The difference between? [js operator]
  • What are JavaScript wrapper types? 【 JS data type 】
  • JavaScript implicit conversion logic? 【 JS data type 】
  • What are the filters in the Vue instance? How to use it? 【 Vue 】
  • How does Vue save the current page state? 【 Vue 】
  • Event Modifiers and their Functions in Vue
  • handwrittennewOperator [handwritten code]
  • handwrittenPromiseObject [handwritten code]
  • Output result [Promise]
  • 22. The KTH last node in the linked list
  • Reverse linked list [algorithm]

Knowledge comb

Said the webworks

Web workers provide an easy way for Web content to run scripts in background threads. Threads can execute tasks without interfering with the user interface, that is, Web workers are executed asynchronously in the background and do not occupy main resources, because workers have their own threads.

You can run any code you like in the worker thread, with some exceptions. For example, in worker, DOM nodes cannot be operated directly, nor can window method and attributes be used. However, you can use a lot of stuff underneath the Window object, including WebSockets, IndexedDB, and Data storage mechanisms like the FireFox OS proprietary Data Store API. View Functions and classes available to workers for details.

Data transfer between workers and the main thread takes place through a messaging mechanism where each sends its own Message using the postMessage() method and responds to the Message using the onMessage event handler (which is contained in the data attribute of the Message event). In this process, data is not shared but copied.

As long as running in the same parent page, workers can generate new workers in turn. And you can always return NULL using the responseXML and channel properties of XMLHttpRequestest.

The data transferred between the main page and the worker is copied rather than shared. Objects passed to the worker need to be serialized, and then deserialized at the other end. Pages and worker** do not share the same instance, and the end result is that a copy of the data is generated at the end of each communication. ** Most browsers use structured copy to implement this feature.

Reference:

  • webworkes – MDN

Understanding of box models

All HTML elements can be thought of as boxes, and in CSS the term box model is used for design and layout. CSS box model is essentially a box that encapsulates the surrounding HTML elements. It consists of four parts: margin, border, padding, and content.

In addition to the standard box model, there are also some weird box models, such as THE IE box model, the difference is that the width and height Settings are different. The standard and model width and height only apply to the content area, while the weird box model will include three parts except the margins as the width and height values.

What’s the difference between using Translate and Position to position elements?

Translate is a property of Transform. Changing properties such as transform or opacity does not trigger browser reflow, because Translate does not change the document layout of elements, but creates a layer using the GPU for rendering. Positioning itself changes the document layout of an element and takes it out of the document stream, causing backflow and redrawing, and unlike Translate, which uses the GPU for hardware acceleration, translating is better than Position for animation effects.

The operator|,||,&and&&The difference between?

First | and & either as an operator in js, can also be used as a logical operators. When as A logical operators, | and | | presentation logic or, & and presentation logic and &&, but | | and has the character of short-circuit &&, namely A | | B as long as A true won’t judge B, and direct returns true, by the same token, A && B expression when A false will directly returns false, There is no need to determine the value of the B expression.

= =,= = =andObject.is()The difference between?

When == performs data comparison, it will first convert to the same data type and then compare, which is js implicit data type conversion.

And === is congruent comparison, comparison will be directly compared without data conversion, but also more rigorous.

Object. Is is not different from ===, and does not perform type conversion when comparing data, but Object. For example, object. is(0, -0) returns false and object. is(NaN, NaN) returns true, while congruence comparison does the opposite.

What is a wrapper type in JavaScript?

In JavaScript, primitive types have no properties and methods, but to facilitate manipulation of values of primitive types, JavaScript implicitly converts values of primitive types to objects in the background when an attribute or method of primitive types is called, for example:

const a = "abc";
a.length; / / 3
a.toUpperCase(); // "ABC"
Copy the code

These properties and methods are all in strings, so ordinary data types have the same functions and features as objects.

Implicit conversion logic in js

When some calculation or comparison operator is encountered, JS triggers an implicit conversion that converts the data to the same data type for further operation. Such as +, -, *, / and the ==, >, and < operators.

For basic data types, undefined and NULL can be converted to strings, numbers, or booleans: “undefined” and “null”, 0, false, respectively. Strings, numbers, and booleans can also be converted relative to each other, depending on the logic of the two data types.

For reference types, toPrimitive is implicitly converted to the primitive data type when the operation is performed. There is an implicit method in the JS object: [symbol.toprimitive].

We can define this function when we define an object, for example:

var obj = {
  [Symbol.toPrimitive](hint) {
    if (hint == "number") {
      return 10;
    }
    if (hint == "string") {
      return "hello";
    }
    return true; }};console.log(+obj2);     // 10 -- hint parameter value is "number"
console.log(`${obj2}`); // "hello" -- hint parameter value is "string"
console.log(obj2 + ""); // "true" -- hint parameter value is "default"
Copy the code

The HINT type is automatically recognized when an operation is performed on the object and the corresponding base data type value is returned.

If this function is not defined, the following principles are followed:

  • hintfornumberIs called firstvalueOf(), no value to call againtoString()Function.
  • hintforstringIn turn, the object’stoString(), no value to call againvalueOf()Function.

By default, hints are of type number, except for the Date object, which by default is string.

What is the role of a filter in a Vue instance? How to use it?

Filters are, as the name suggests, used to filter data. When we present data, we might want it to be filtered before it’s displayed, or we might want it to be displayed after we’ve done some special operation, so of course when we present an array of numbers we only show integers, when we present people’s names we show them with uppercase letters.

In fact, filters, like methods and computed, are a way to change raw data.

<input v-on:keyup="items | filteredItems(10)">
Copy the code

In fact, this filter can be replaced with a calculated property with the same effect:

computed: {
  filteredItems: function (size) {
    return this.items.slice(0, size)
  }
}
Copy the code

See filter – Vue for more details

How do I save the current state of a page in Vue

Since you want to maintain the state of the page, that is, maintain the state of the component, so that it will not be updated by the page and change, that is, when the page is restored, the state before the component can be restored.

There are two ways to keep a component in state:

  • Components will be uninstalled
  • Components are not unloaded

If a component is to be uninstalled, its data needs to be cached. Generally, there are two methods:

  • Store state data in LocalStorage or SessionStorage

    Just pass the state of the current component through json.stringify () in LocalStorage/SessionStorage during the component’s life cycle when it is about to be destroyed Just store it. One thing to watch out for here is when the component updates its state.

    For example, when switching from component B to component A, component A needs to update its status. However, if you jump to COMPONENT B from another component, you actually want component B to re-render, that is, do not read information from the Storage. Therefore, you need to add A flag attribute to the status of the Storage to control whether component A reads the status of the Storage.

    Advantages: Good compatibility, no additional libraries or tools required.

    Disadvantages: Data storage needs to be copied. If there are special objects in the data, related data may be lost. Reading flags is not easy to control, and it may not be necessary to read the component’s cache state when the page is opened directly.

  • Routing by value

    Prop-to of the React-Router Link component can be used to transfer parameters between routes.

    The state parameter is needed here. In the B component, you can get the state value by using history.location.state and save it. When component A is returned, state is carried again to achieve the effect of maintaining the routing state.

    Advantages: Simple and fast, do not need to control the flag.

    Disadvantages: If a component can jump to more than one component, the same processing logic must be written to each jump component.

Things are easier if the component is not unloaded. In general, there are also two options:

  • The toggle component is rendered in full screen as a child component, and the page state is normally stored in the parent component.

  • In Vue, the keep-alive component can also be used to cache pages. When a component is switched in keep-alive, the lifecycle hook functions of the component that are activated and deactivated are executed. The state of the component wrapped in keep-alive is preserved.

    <keep-alive>
    	<router-view v-if="$route.meta.keepAlive"></router-view>
    </kepp-alive>
    Copy the code

Common event modifiers in Vue and what they do

Calling event.preventDefault() or event.stopPropagation() in the event handler is a very common requirement. While this could easily be done in a method, it’s better if the method has pure data logic instead of dealing with DOM event details.

Here are some event modifiers provided by Vue:

  • .stop: Prevents the event from bubblingevent.stopPropagation()
  • .prevent: Cancel the preset behavior, equivalent toevent.preventDefault()
  • .capture: Enable event capture (as opposed to bubbling, capture events from the outside in)
  • .self: Only the current element can start, i.e. child elements cannot fire
  • .once: The event is executed only once
  • .passiveAnd:.preventDoes the opposite, that is, does not block the default behavior,.passiveModifiers, in particular, can improve performance on mobile. This is equivalent to setting the third property of addEventListenerpassive.
<! -- Prevent the click event from propagating -->
<a v-on:click.stop="doThis"></a>

<! Submit events no longer reload the page -->
<form v-on:submit.prevent="onSubmit"></form>

<! -- modifiers can be concatenated -->
<a v-on:click.stop.prevent="doThat"></a>

<! -- only modifiers -->
<form v-on:submit.prevent></form>

<! Add event listener with event capture mode
<! Events triggered by an inner element are processed here before they are processed by the inner element.
<div v-on:click.capture="doThis">.</div>

<! Trigger handler only if event.target is the current element itself -->
<! -- that is, events are not triggered from internal elements -->
<div v-on:click.self="doThat">.</div>

<! -- The default behavior of the scroll event (i.e. the scroll behavior) will be triggered immediately -->
<! Instead of waiting for 'onScroll' to finish -->
<! -- This includes' event.preventdefault () '-->
<div v-on:scroll.passive="onScroll">.</div>
Copy the code

The handwritten new operator

The new operator creates an instance of a user-defined object type or of a built-in object with a constructor.

The new keyword does the following:

  1. Create an empty simple JavaScript object (i.e{});
  2. Of the objectconstructorTo link the object to the constructorprototypeObject;
  3. Take the object created in Step 1 as the objectthisContext;
  4. Returns if the function does not return an objectthis.
function objectFactory(constructor, args) {
    // Check whether the argument is a function
    if (typeof constructor! = ="function") {
        console.error("type error");
        return;
    }
    // 1. Create an object and set its prototype to the constructor's prototype
    const newObject = Object.create(constructor.prototype);
    // 2. Point this to the new object and initialize the function
    const result = constructor.apply(newObject, args);
    return result && (typeof result === "object" || typeof result === "function")? result : newObject; }Copy the code

Reference:

  • new – MDN

Write a Promise

For an introduction to promises, see promise-mDN.

The Promise object is used to represent the final completion (or failure) of an asynchronous operation and its resulting value. There are three states:

  • Padding: TBD. Initial state: indicates neither success nor failure.
  • This is a big pity. The status of a successful callback. The callback function is a microtask.
  • -Blair: No, I have rejected. Status of a failed callback. The callback function is a microtask.

Promises are designed to solve the problem of callback hell, which is the Promise. Then function implementation, so the basic Promise should have the following properties and functions:

  • State: indicates the status of the callback
  • Data: return value of successful callback
  • Err: return value of callback failure
  • Then: Calls the chained function after the status update

The details involved are:

  • How to switch the callback state; When switching
  • How is a successful callback triggered
  • How is a failure callback triggered
  • How is the execution of microtasks simulated
// Three states of Promise
const PromiseState = {
    PENDING: 'pending'.FULFILLED: 'fulfilled'.REJECTED: 'rejected'
}

function MyPromise(executor) {
    const THIS = this;
    // Initialize the constructor
    _defineProperty(THIS, 'state', PromiseState.PENDING); / / state
    _defineProperty(THIS, 'date'.undefined); // Successful results
    _defineProperty(THIS, 'error'.undefined); // Successful results
    _defineProperty(THIS, 'then', thenFun); // then
    _defineProperty(THIS, 'fulfilledCalls'[]);// Successful callback
    _defineProperty(THIS, 'rejectedCalls'[]);// Failed callback
    // Execute the macro task
    try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }

    /** * Successful callback *@param {*} value 
     */
    function resolve(value) {
        updateState(PromiseState.FULFILLED, value);
    }

    /** * Failed callback *@param {*} err 
     */
    function reject(err) {
        updateState(PromiseState.REJECTED, err);
    }

    /** * Update status *@param {*} State of the state *@param {*} Res Processing result */
    function updateState(state, res) {
        if(THIS.state === PromiseState.PENDING) {
            THIS.state = state;
            if(THIS.state === PromiseState.FULFILLED) {
                THIS.data = res;
                setTimeout(() = > {
                    THIS.fulfilledCalls.forEach(fun= > {
                        fun.call(THIS, THIS.data);
                    });
                    THIS.fulfilledCalls.length= 0;
                    THIS.rejectedCalls.length= 0;
                }, 0);
            } else if(THIS.state === PromiseState.REJECTED) {
                THIS.error = res;
                setTimeout(() = > {
                    THIS.rejectedCalls.forEach(fun= > {
                        fun.call(THIS, THIS.error);
                    });
                    THIS.rejectedCalls.length= 0;
                    THIS.fulfilledCalls.length= 0; }); }; }}/** ** chain call *@param {Function} onFulfilled 
     * @param {Function} onRejected 
     */
    function thenFun(onFulfilled, onRejected) {
        if(THIS.state === PromiseState.FULFILLED) {
            setTimeout(() = > {
                onFulfilled && onFulfilled.call(THIS, THIS.data);
            }, 0);
        } else if(THIS.state === PromiseState.REJECTED) {
            setTimeout(() = > {
                onRejected && onRejected.call(THIS, THIS.error);
            }, 0);
        } else {
            onFulfilled && THIS.fulfilledCalls.push(onFulfilled);
            onRejected && THIS.rejectedCalls.push(onRejected);
        }
        returnTHIS; }}function _defineProperty(obj, key, value) {
    if (key in obj) {
        // Normally, assigning an Object directly is the same as using Object.defineProperty,
        // However, if the property itself exists on the object or its prototype chain, the cut property can be configured.
        // You can update property configurations such as Enumerable and Writable
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true.configurable: true.writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}

/ / test
const p = new MyPromise((resolve, reject) = > {
    console.log('Promise runing... ');
    setTimeout(() = > {
        console.log('fulfilled! ');
        resolve('1');
    }, 100);
});
p.then((data) = > {
    console.log('2', data);
})
p.then((data) = > {
    console.log('3', data);
});
console.log('4')
Copy the code

Note: The promise. then implementation is problematic. In full form, the Promise. Then callback is returned as a new Promise, and if the callback does not return a value, a padding-state Promise is returned. Here we’re just returning the current Promise is incomplete. The full promise.then writing will be given in a subsequent article.

In addition, if the argument to promise.then is not a function, the current Promise is returned directly.

To sum up:

  • Status switch: in fact, is triggered by the user, of course, only the user knows when the success, when the failure, that is, the user manually callresolveorrejectThe function can be updatedPromiseState, andPromiseOnce the status is updated, it cannot be updated.
  • Simulation of microtasks: usingsetTimeoutTo simulate
  • thenMultiple calls to: whenthenWhen the function is called multiple times, perhaps without the Promise state changing, we need to call the functionThe cacheGet up and wait until the state changes before calling. One more detail is that we empty the callback function cache after the call is done. This is to free up memory. Since the state switch is only performed once, there is no need to keep the cache in case memory cannot be reclaimed.

The output

const promise = new Promise((resolve, reject) = > {
  console.log(1);
  setTimeout(() = > {
    console.log("timerStart");
    resolve("success");
    console.log("timerEnd");
  }, 0);
  console.log(2);
});
promise.then((res) = > {
  console.log(res);
});
console.log(4);
Copy the code

Output result:

1
2
4
timerStart
timerEnd
success
Copy the code
Promise.resolve().then(() = > {
  console.log('promise1');
  const timer2 = setTimeout(() = > {
    console.log('timer2')},0)});const timer1 = setTimeout(() = > {
  console.log('timer1')
  Promise.resolve().then(() = > {
    console.log('promise2')})},0)
console.log('start');
Copy the code

Output result:

  • Promise.resolve() returns onefulfilledThe state of thePromise, the subsequent code is microtask, join the microtask queue
  • Timer1 is a macro task and joins the macro task queue
  • Print start. The first macro task ends
  • The promise1 macro task is printed. The timer2 macro task enters the macro task queue, and the microtask ends
  • The second macro task starts, the callback in Timer1 is executed, the print timer1 is printed, and the micro task is queued
  • Start microtask, print Promise2
  • Start the macro task and print Timer2
start
promise1
timer1
promise2
timer2
Copy the code

The key here is the distinction between macro and microtasks, and the alternate execution logic between macro and microtasks: after the execution of the macro task, the executable microtasks are executed, and then the macro tasks in the macro task queue are continued, and so on. And we often say that the asynchronous operation, that is, will not block the main thread, reason is asynchronous operations will be temporarily on the task queue (may be a macro task, can also be micro task queue), when the end of round of macro task execution will begin to queue in the next round of task execution, micro task execution will start again after the macro in the queue task execution, to continuously alternating execution.

In the ES6 specification, macro tasks are initiated by the host (browser, Node), while microtasks are initiated by JavaScript itself. Therefore, the code in script, setTimeout/setInterval, postMessage and other asynchronous operations are macro tasks, while promise. then, Promise.nextTick, and asynchronous calls in Proxy are all initiated by JS itself, so they are microtasks.

22. The k last node in the linked list

Input a linked list, output the last KTH node of the list. In order to conform to the convention of most people, this case counts from 1, i.e. the last node of the list is the last node from the last. For example, a linked list has six nodes, starting with the head node, whose values are 1, 2, 3, 4, 5, and 6. The third from last node of the list is the node with the value 4. Example: Given a linked list: 1->2->3->4->5, and k = 2. Return to list 4->5.Copy the code

The structure of the linked list is:

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; *} * /
Copy the code

If we want to return the child chain of the penultimate KTH node, we need to know the position of the penultimate KTH node. Once we know this position, we can traverse from this node to the end of the list.

The double-pointer method can be used. Since the relative length of the target sub-chain is fixed, the head and tail Pointers are maintained when we traverse the number group. When the tail pointer traverses to the end, the position of the penultimate KTH node is also known.

/ * * *@param {ListNode} head
 * @param {number} k
 * @return {ListNode}* /
var getKthFromEnd = function(head, k) {
    let left = head, right = head;
    let next = head.next;
    let len = 0;
    while(right) {
        if(len === k) {
            left = left.next;
        } else {
            len++;
        }
        right = right.next;
    }
    return left;
};
Copy the code

Reverse a linked list

Given the head node of a single linked list, reverse the list and return the reversed list. Input: head = [1,2,3,4,5] output: [5,4,3,2,1]Copy the code

It’s a very simple problem. Keep pointing to the previous node as you traverse.

/ * * *@param {ListNode} head
 * @return {ListNode}* /
var reverseList = function(head) {
    let pre = null;
    let cur = head;
    let next = null;
    while(cur) {
        next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
};
Copy the code