preface

Handwriting is essential in the front end of the interview process, because handwriting is the most impressive test of your knowledge of a certain principle. Here are some of the handwritten questions I encountered during the interview review process. I will realize the idea to write out with you to share, and the realization is just a reference, interested can click on the reference answer, there is a question please correct.

Principle of implementation

Implement a new operator

First we need to understand what the new operator does

  • The new operator returns an object.
  • Object that points to the prototype of the constructor
  • If the constructor has a return, we need to check the return, if it is an object, then return the newly created object, if it is not an object
Refer to the answer
function myNew(fn, ... args) {
    let obj = Object.create(fn.prototype);
    let res = fn.apply(obj, args);
    return res instanceof Object ? res : obj;
}
Copy the code

Implement an instanceof operator

The first thing we need to know is that Instanceof is judged by the prototype chain

Refer to the answer
The instanceof operator works by judging the prototype chain, so as long as you compare _proto_ on the left to prototype on the rightCopy the code
function myInstance(left, right) {
    Return false if left is a base type
    if(typeofleft ! = ='object' || left === null) return false;
    let proto = Object.getPrototypeOf(left);
    while(true) {
        if(proto === null) return false;
        if(proto === right.prototype) return true;
        proto = Object.getPrototypeOf(proto); }}Copy the code

Implement an Apply

The following aspects should be paid attention to in implementing Apply:

1. Do not take the first parameter because the first parameter is the context.

2. Methods assigned to objects need to be deleted without affecting the original object.

3. Use undefined to point the context to the window object

Refer to the answer
Function.prototype.myApply = function(context, [...args]) {
    // Check if the context is empty, if it is empty, it points to the window object
    context = context || window;
    context.fn = this; context.fn(... args);delete context.fn;
}
Copy the code

Implementing a Call

Call’s implementation is similar to apply’s, but the level of parameter handling is slightly different.

Refer to the answer
Function.prototype.myCall = function(context) {
    // Check if the context is empty, if it is empty, it points to the window object
    context = context || window;
    let args = [...arguments].slice(1);
    context.fn = this;
    context.fn(args);
    delete context.fn;
}
Copy the code

Implement a bind

The implementation of bind needs to be aware of the currization of the function.

Refer to the answer
Function.prototype.myBind = function(context) {
    const self = this;
    let args = [...arguments].slice(1);
    return function() {
        // Consider the curryization of the function
        let newArgs = [...arguments];
        this.apply(context, newArgs.concat(args))
    }
}
Copy the code

Fulfill a promise

The realization of promise is necessary to focus on, I divide a few steps to see:

1. Deal with the synchronization logic first, such as the state value changes, will not change, and which attribute values, etc.

2. Reprocess the asynchronous logic in the form of callbacks and stored lists.

3. Redeal with the logic of chain call, chain call is more complex, pay more attention to the object of Thenable.

4. Other ways to deal with promises.

Finally, HERE I recommend an article to you, write very good! Promise the article

Refer to the answer
class Promise(exector) {
    constructor() {
        this.value = undefined;
        this.reason = ' ';
        this.state = 'pending';
        this.onResolveList = [];
        this.onRejectList = [];
        const resolve = (value) = > {
            if(this.state === 'fulfilled') {
                this.value = value
                this.state = 'fulfilled';
                this.onResolveList.forEach((fn) = >{ fn(); })}};const reject = (reason) = > {
            if(this.state === 'rejected') {
                this.reason = reason
                this.state = 'rejected';
                this.onRejectList.forEach((fn) = >{ fn(); }}})try {
            exector(resolve, reject);
        } catch(err) {
            reject(err)
        }
    }
    then(onFulfilled, onRejected) {
        const promise2 = new Promise((reslove, reject) = > {
            if(this.state === 'fulfilled') {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, reslove, reject);
            }
            if(this.state === 'rejected') {
                onRejected(this.reason);
                resolvePromise(promise2, x, reslove, reject);
            }
            if(this.state === 'pending') {
                onResolveList.push((a)= > {
                    let x = onFulfilled(this.value);
                    resolvePromise(promise2, x, reslove, reject);
                });
                onRejectList.push((a)= > {
                    let x = onRejected(this.reason); resolvePromise(promise2, x, reslove, reject); }); }});return  promise2;
    }
    race(promises) {
        return new Promise((resolve, reject) = > {
            for(let i = 0; i < promises.length; i++) {
                promises[i].then(resolve, reject);
            }
        })
    }
    all(promises) {
        let arr = [];
        let i = 0;
        function processData(index, data) {
            arr[index] = data;
            i++;
            if(i === promises.length) { resolve(data); }}return new Promise((resolve, reject) = > {
            for(let i = 0; i < promises.length; i++) {
                promises[i].then((val) = > {
                    processData(i, val);
                }, reject)
            }
        })
    }
    resolve(val) {
        return new Promise((resovle, reject) = > {
            resovle(val);
        })
    }
    reject(val) {
        return new Promise((resovle, reject) = >{ reject(val); }}})// Loop references, thenable objects, promise objects
resolvePromise(promise2, x, reslove, reject) {
    if(promise2 === x) {
        reject('Circular reference');
        return;
    }
    // Prevent multiple calls
    let called;
    // Check the type of the value of x, if not an object or function, return resolve
    if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
        // Then errors can also enter a catch
        try {
            if(called) return;
            let then = x.then; 
            if(typeof then === 'function') {
                then.call(x, (y) => {
                    if(called) return;
                    called = true;
                    resolvePromise(promise2, y ,reslove, reject)
                }, (err) => {
                    if(called) return;
                    reject(err);
                    called = true; })}else{ resolve(x); }}catch(err) {
            if(called) return;
            reject(err);
            called = true; }}else{ resolve(x); }}Copy the code

Implement a parasitic composite inheritance

The main concern for parasitic combinatorial inheritance is the orientation of the constructor child. And the inherited drawback: super assembly calls twice.

Refer to the answer
function Super() {}
function Sub() {
    Super.call(this)
}
Sub.prototype = new Super();
Sub.constructor = Sub;
Copy the code

Business problem realization

How to implement an anti – shake function

The understanding of anti-shake is best based on the memory of service scenarios: Anti-shake is generally used in the input box scenario. So there are two aspects to the implementation:

1. When the event is triggered again within a certain period of time, the timer should be reset.

2. Reset the timer after the execution.

Refer to the answer
function debounce(cb, delay, ... args) {
    let time = null;
    return function() {
        if(time) {
            clearTimeout(time);
        }
        time = setTimeout((a)= > {
            cb.apply(this. args); clearTimeout(time); }, delay); }}Copy the code

How to implement a throttling function

For throttling functions, you also need to remember them in context. Generally used in rolling events, will only be triggered once in a certain period of time. There are also two points to note at the implementation level:

1. Use a lock variable to ensure that it fires only once in a certain period of time.

2. After the execution, unlock the lock

Refer to the answer
function tr(fn, time, ... args) {
    let lock = false;
    return  function() {
        if(lock) return;
        lock = true;
        setTimeout((a)= > {
            fn.apply(this. args); lock =false;
        }, time)
    }
}
Copy the code

Realize a line and hump conversion

This is a test of the regular and replace methods.

Refer to the answer
function camelize(str) {
    return (str + ' ').replace(/-\D/g.function(match) {
        return match.charAt(1).toUpperCase()
    })
}
Copy the code
function hyphenate(str) {
    return (str + ' ').replace(/[A-Z]/g.function(match) {
        return The '-'+ match.toLowerCase(); })}Copy the code

Implement a sleep function

Sleep can be implemented in many ways, promise, async/await, etc. Here are some of the most common ones.

Refer to the answer
function sleep(time) {
    return new Promise((resolve, reject) = > {
        setTimeout((a)= > {
            resolve(true);
        }, time)
    })
}
Copy the code

Implement a Currie function

To implement currification is to call multiple arguments with different lengths. The advantage is that you can observe an intermediate procedure, or intermediate variable, when you call a parameter. Add (1)(2)(3

Refer to the answer

function curry(fn) {
    const finalLen = fn.length
    let args = [].slice.call(this.1)
    return function currying () {
    args = args.concat(Array.from(arguments))
    const len = args.length
    return len >= fn.length ? fn.apply(this, args) : currying
    }
}

Copy the code

Implementing an Ajax

Implementing an Ajax is essentially a matter of using the XMLHttpRequest object and its API methods. Here, I suggest that it be packaged in the form of promise as far as possible for easy use.

Refer to the answer
function ajax({url, methods, body, headers}) {
    return new Promise((resolve, reject) = > {
        let request = new XMLHttpRequest();
        request.open(url, methods);
        for(let key in headers) {
            let value = headers[key]
            request.setRequestHeader(key, value);
        }
        request.onreadystatechange = (a)= > {
            if(request.readyState === 4) {
                if(request.status >= '200' && request.status < 300) {
                    resolve(request.responeText);
                } else {
                    reject(request)
                }
            }
        }
        request.send(body)
    })
}
Copy the code

Implement a deep copy

Deep copy is a common method of serialization and deserialization, but there are two drawbacks to this method:

Values of the type undefined, NULL, and symbol are deleted

2. An error occurs when a circular reference is encountered.

We need to keep a close eye on circular references when implementing deep copy.

In the following methods, I mainly solve the problem of circular references in the form of arrays. So why have two arrays?

Basically an array maintains references to old objects, and an array maintains references to new objects.

Refer to the answer
function deepClone(obj) {
    const parents = [];
    const children = [];
    function helper(obj) {
        if(obj === null) return null;
        if(typeofobj ! = ='object') return obj;
        let child, proto;
        if(Array.isArray(obj)) {
            child = [];
        } else {
            proto = Object.getPrototypeOf(obj);
            child = Object.create(proto);
        }
        // Handle circular references
        let index = parents.indexOf(obj)
        if(index === - 1) {
            parents.push(obj);
            children.push(child)
        } else {
            return children[index];
        }
        // for in iteration
        for(let i inobj) { child[i] = helper(obj[i]); }}}Copy the code

push

In the current epidemic situation, only entering large companies, graduates can have a good guarantee. Small companies will be forced to recruit passively if they are unable to survive, lay off workers or become permanent employees.

The writer works for Alibaba Retail Link. If you want to tweet in, you can email [email protected]. Massive HC!! You can also add the q group: 912253914. Edit your resume in your spare time.