1, copy

When you put an object or an array as the value assigned to a variable, is actually to the object or array reference address is assigned to a variable, when the variable changed object or an array of operation, will also affect the original object and array change accordingly, so we think through to copy a copy of the way.

We all know that there are shallow and deep JS copies

Shallow copy:

(1) the Object. The assign

const obj1 = {
    a: 1,
    b: { c: 2 }
};
const obj2 = Object.assign({}, obj1);
Copy the code



(2) ES6 deconstruction

const obj1 = { a: 1, b: { c: 2 } }; const obj2 = { ... obj1 };Copy the code



(3) Key and value assignments traversed once

(4) Arrays and slice


But shallow copy still doesn’t solve the problem of nested objects or arrays, so we need to consider deep copy.

Deep copy:

(1) json.stringify and json.parse

const obj1 = {
    a: 1,
    b: { c: 2 }
};
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.b.c = 3;
console.log(obj1);
console.log(obj2);Copy the code

You’ll notice that Obj1 and Obj2 are already independent of each other.



Is this the perfect way to solve the problem?

In fact, it ignores the property of the object whose value is undefined.

const obj1 = {
    a: 1,
    b: { c: undefined }
};
const obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1);
console.log(obj2);Copy the code



(2) Recursion

function clone(source) {
    var target = {};
    for(var i in source) {
        if (source.hasOwnProperty(i)) {
            if (typeof source[i] === 'object') {
                target[i] = clone(source[i]);
            } else {
                target[i] = source[i]; }}}return target;
}Copy the code

The 👆 method lacks argument verification, is not rigorous in determining whether it is an object, and has no compatible arrays.

Actually, commonly used methods for judging whether the Object is the Object. The prototype. ToString. Call (obj) = = = ‘[Object Object]’

For the perfect solution, check out this:

Github.com/jsmini/type…

In fact, this deep copy method has a problem, is the circular reference and too deep level will cause stack explosion, here is a good article to write, you can see:

Juejin. Cn/post / 684490…

2. Array deduplication

(1) Use objects

Const arr =,2,3,4,2,5,4,6,7,6,8 [1]; const obj = {}; const newArr = []; arr.forEach((item) => {if (!obj[item]) {
        newArr.push(item);
        obj[item] = 1;
    }
});
console.log(newArr);Copy the code



2. Use ES6 Set

Const arr =,2,3,4,2,5,4,6,7,6,8 [1]; const mySet = new Set(arr); console.log(mySet);Copy the code



So now we’ve got the result, but we’re still one step away, this is still a Set, so we have to get it back to an array, how do we do that? Yes, array.from.

const newArr = Array.from(mySet);
console.log(newArr);Copy the code



Of course, there are other methods of array de-duplication, such as traversal of the original array to check whether the new array has an element to be inserted, if it does not, insert, if it does, do not insert, but this will use indexOf, in fact, the new array is traversed, so the performance is not as good as the above two methods.

3. If you were to implement a search box, what would you consider? (The search box here is just like baidu’s search box, search results will be displayed below after input)

This problem should be most people will think of is the input keyword trigger request, then the user will trigger the request every time the input, no doubt is bad for the network, performance, experience, so we should use throttling function.

Simple throttling functions:

function throttle(fn, duration) {
    let flag = true;
    return function() {
        const context = this;
        if (flag) {
            flag = false;
            setTimeout((a)= > {
                fn && fn.apply(context, arguments)
                flag = true; }, duration); }}}Copy the code

Throttling functions can be used in onresize, onScroll, onMousemove, onmouseover and other scenarios.

Speaking of throttling functions, by the way, what’s the difference between the two?

I think the difference lies in the time control. The anti-shake function will only execute once within the set time, but it will recalculate the time if it is triggered the second time.

function debounce(fn, duration) {
    let timer = null;
    return function() {
        const context = this;
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
        timer = setTimeout(() => { fn && fn.apply(context, arguments); timer = null; }, duration); }}Copy the code

Back to the search box, there’s a problem with setting throttling. If the user enters “ABC” for the first time and sends a request, and then enters “def” for another time and sends a request, but the return order of the two requests is not fixed, the search result obtained may not be what the user wants, and the experience will be poor.

So you use XMLHttpRequest abort, and when the result of your last request is not returned, abort it and make the next request.

4, achieve drag effect, drag a thing with the mouse, drag at will, down at will.

First of all, understand that we’re not going to use HTML5 drag, and then draw your own picture and think about how you’re going to use various coordinate distances, and then try to do that in code.

<html>
<head>
    <meta .>
    <title>test</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            position: absolute;
            top: 0px;
            left: 0px;
            background-color: #FF0000;
        }
    </style>
    <script>
        window.onload = function() {
            const box = document.getElementById('box');
            box.addEventListener('mousedown', mouseDown);
            box.addEventListener('mouseup', mouseUp);
            let boxLeft = 0; // The left is used to save the absolute position of the box when the mouse clicks
            let boxTop = 0; // Use to save the absolute position of box when mouse click top
            let initX = 0; // Save the x-coordinate when the mouse clicks on box
            let initY = 0; // Save the Y coordinate when the mouse clicks on box
            let distanceX = 0; // To store the distance moved on the box X axis
            let distanceY = 0; // To store the distance moved on the Y-axis of the box
            
            function mouseDown(e) {
                // Mouse click box triggers
                initX = e.pageX;
                initY = e.pageY;
                boxLeft = e.target.offsetLeft;
                boxTop = e.target.offsetTop;
                // We bind the mouse movement event to the body because it covers the entire page.
                // If you bind a mouse movement event to box, the event will be interrupted when the mouse moves out of the box quickly
                document.body.addEventListener('mousemove', mouseMove);
            }

            function mouseUp() {
                // Triggered when the mouse is released
                document.body.removeEventListener('mousemove' mouseMove);
            }

            function mouseMove(e) {
                // Triggered when the mouse slidesdistanceX = e.pageX - initX; distanceY = e.pageY - initY; box.style.left = boxLeft + distanceX; box.style.top = boxTop + distanceY; }}</script>
</head>
<body>
    <div id="box"></div> 
</body>
</html>Copy the code

5. Add large numbers

Javascript supports a range of numbers (-2^53, 2^53) beyond which accuracy is lost.

If the back end returns two extra-large strings, how do we add them? Because if it is converted to numeric addition, the accuracy of super-large string will be lost when converted to numeric addition, and the result of addition will be necessarily inaccurate. If we add strings directly, that’s just string concatenation, not what we want.

So let’s see, the way you add numbers is you add up each digit, and then you add up to one.

   12345

+ 56789

— — —

   69134

Can we add each digit of a string, analog numbers?

function add(str1, str2) {
    const arr1 = str1.split(' ').reverse();
    const arr2 = str2.split(' ').reverse();
    const res = [];
    let flag = 0;
    while(arr1.length || arr2.length || flag) {
        const num1 = arr1.shift() || 0;
        const num2 = arr2.shift() || 0;
        const sum = Number(num1) + Number(num2) + flag;
        if (sum > 9) {
            flag = 1;
            res.push(sum % 10);
        } else{ flag = 0; res.push(sum); }}return res.reverse().join(' ');
}Copy the code

Implement a simple template engine

Now there is a template string ‘

hello, I am {{name}}, age: {{info.age}}

, work experience: {{info.experience.company}}, work time: {{info.experience.com time}}’,

datadata = {name: 'abc', info: {age: 24, experience: {company: 'abc', time: 'two years'}}} , how to achieve template data replacement?

The key here is the use of the replace method, whose second argument can be a callback.

function compile(tpl, data) {
    const regex = /\{\{([^}]*)\}\}/g;    const string = tpl.trim().replace(regex, function(match, The $1) {
        if (The $1) {
            const arr = The $1.split('. ');
            return getValue(data, arr);
        } else {
            return ' '; }}); console.log(string); }function getValue(data, arr) {
    let attr;
    if (arr.length) {
        attr = arr.shift();
        return getValue(data[attr], arr);
    }
    return data;
}
const tpl = '

Hello, I am {{name}}, age: {{info.age}}

, work experience: {{info.experience.company}}, work time: {{info.experience.com time}}'

; const data = {name: 'abc', info: {age: 24, experience: {company: 'def', time: 'two years'}}}; compile(tpl, data); Copy the code



The role of closures

Closures are used to read variables inside functions. Second, variables declared in a function are always kept in memory and are not automatically cleared after a function is called.

Use scenarios such as traversal indexing, function currification, throttling, and bind.


To be continued ~ ~