手写一下JS面试题GO!GO!GO!- day1

151 阅读3分钟

1: Array方法

Array.prototype.forEach

image.png

接受两个参数callback, this(ctx)

    Array.prototype.myForEach = function (callBack) {
        var content = arguments[1] || window;
        var _arr = this;
        var len = _arr.length;
        for (var i = 0 ; i < len; i++) {
            callBack.apply(content, [_arr[i], i, _arr]);
        }
    }

Array.prototype.map

image.png

    Array.prototype.myMap = function (callBack) {
        var content = arguments[1] || window;
        var _arr = this;
        var _len = _arr.length;
        var _newArr = [];
        for (var i = 0 ; i < _len; i++) {
            
            _newArr.push(callBack.apply(content, [_arr[i], i, _arr]));
        }
        return _newArr;
    }

备注: 这里简单的实现一下,其实是需要深拷贝一下每一项的结果。

Array.prototype.filter

image.png

    Array.prototype.myFilter = function (callBack) {
        var _arr = this;
        var args = arguments[1] || window;
        var _len = _arr.length;
        var newArr = [];
        for (var i = 0 ; i < _len; i++) {
            if (callBack.apply(args, [_arr[i], i, _arr])) {
                newArr.push(_arr[i])
            }
        }
        return newArr;
        
    }

Array.prototype.every

image.png

    Array.prototype.myEvery = function (callBack) {
        var _arr = this;
        var args = arguments[1] || window;
        var _len = _arr.length;
        var result = true;
        for (var i = 0 ; i < _len ; i++) {
            if (!callBack.apply(args, [_arr[i], i, _arr])) {
                result = false;
                break;
            }
        }
        return result;
    }

Array.prototype.some

image.png

    Array.prototype.mySome = function (callBack) {
        var _arr = this;
        var args = arguments[1] || window;
        var _len = _arr.length;
        var result = false;
        for (var i = 0 ; i < _len ; i++) {
            if (callBack.apply(args, [_arr[i], i, _arr])) {
                result = true;
                break;
            }
        }
        return result;
    }

Array.prototype.reduce

image.png

    Array.prototype.myReduce = function (callBack, initialvalue) {
        var _arr = this;
        var _len = _arr.length;
        for (var i = 0; i < _len; i++) {
            initialvalue = callBack(initialvalue, _arr[i], i, _arr);
        }
        return initialvalue;
    }

数组扁平化

  1. reduce + ...
    Array.prototype.flatArray1 = function (arr) {
        if (!arr.length) return;
        return arr.reduce((prev, item) => {
            Array.isArray(item) ? [...prev, ...flatArray1(item)] : [...prev, item]
        }, [])
    }
  1. reduce + concat
    Array.prototype.flatArray2 = function (arr) {
        if (!arr.length) return;
        return arr.reduce((prev, item) => {
            prev.concat(Array.isArray(item) ? flatArray2(item) : item)
        }, [])
    }

数组去重

  1. reduce + includes
    function unique (arr) {
         if (!arr.length) return;
         let newArr = [];
         return arr.reduce((prev, item) => {
             return newArr.includes(item) ? newArr: newArr.push(item);
         }, 0)
    }
  1. forEach + indexOf
    function unique2(arr) {
        let newArr = [];
        arr.forEach(item => {
            newArr.indexOf(item) === -1 ? newArr.push(item) : newArr;
        })
    }
  1. new Set + ...
     function unique3(arr) {
         return [...new Set(arr)];
     }
  1. new Set + Array.from
    function unique4(arr) {
        return Array.from(new Set(arr));
    }
  1. 利用对象键的唯一性
    function unique5(arr) {
        let newArr = [];
        let obj = {};
        for (let i = 0 ; i < arr.length ; i++) {
            if (!obj[arr[i]]) {
                newArr.push(arr[i]);
                obj[arr[i]] = 1;
            }
            else {
                obj[arr[i]]++;
            }
        }
        return newArr;
    }

2: Function

Function.prototype.call

image.png

    Function.prototype.myCall = function (ctx) {
        var args = [...arguments].slice(1);
        ctx = ctx || window;
        var name = Symbol();
        ctx[name] = this;
        var result = ctx[name](...args);
        delete ctx[name];
        return result;
    }

Function.prototype.apply

image.png

   Function.prototype.myApply = function (ctx, array) {
        ctx = ctx || window;
        var name = Symbol();
        ctx[name] = this;
        var result = ctx[name](...array);
        delete ctx[name];
        return result;
   }

Function.prototype.bind

    Function.prototype.myBind = function (ctx) {
        ctx = ctx || window;
        var args = [...arguments].slice(1);
        var func = this;
        var FNOP = {};
        var returnFunc = function () {
            var newArgs = [...args, ...arguments];
            return func.apply(this instanceof returnFunc ? this : ctx, ...newArgs);
        }
        FNOP.prototype = func.prototype;
        returnFunc.prototype = new fNOP();
        return returnFunc;
    }

实现 add(1)(2)(3) = add(1, 2, 3) = add(1,2)(3) = 6

使用currying函数,return一个新函数

    const sum = (a, b, c) => a + b + c;
    function currying(fn, args) {
        var len = fn.length;
        args = args || [];
        return function () {
            var newArgs = [...args, ...arguments];
            if (newArgs.length < len) {
                return currying(fn, newArgs);
            }
            else {
                return fn.call(this, ...newArgs);
            }
        }
    }

实现 add(1)(2)(3)() = add(1, 2, 3)() = add(1,2)(3)() = 6

同上

    const sum = (a, b, c) => a + b + c;
    function currying(fn, args) {
        var len = fn.length;
        args = args || [];
        return function () {
            var newArgs = [...args, ...arguments];
            if (newArgs.length < len) {
                return currying.call(this, fn, newArgs);
            }
            else {
                return fn.bind(this, ...newArgs);
            }
        }
    }

实现一个add函数

    题目描述:
        实现一个add函数:
            add(1)(2)(3)() = 6 
            add(1)(2)(3, 4)() = 10
    function add() {
        var now_args = [...arguments];
        var fn = function () {
            var args2 = [...arguments];
            if (args2.length) return fn.toString();
            now_args = [...now_args, ...args2];
            return fn;
        }
        fn.toString = function () {
            return now_args.reduce((prev, next) => prev + next)
        }
        return fn;
    }

3. Promise

实现一个简单的Promise

    let p1 = new MyPromise((resolve, reject) => {
        resolve(1);
    });
     p1.then(data => console.log(data))
   
    
    class MyPromise {
        constructor(executor) {
            this.initValue();
            this.initResolve();
            this.initReject();
            try {
                executor(this.resolve, this.reject);
            }
            catch (e) {
                this.reject(e);
            }
        }
        
        initValue() {
            this.promiseState = 'pending';
            this.promiseResult = null;
            this.onFulfilledCallBacks = [];
            this.onRejectedCallBacks = [];
        }
        
        initResolve() {
            this.resolve = this.resolve.bind(this);
        }
        
        initReject() {
            this.reject = this.reject.bind(this);
        }
        
        resolve(value) {
            if (this.promiseState != 'pending') return; 
            this.promiseState = 'fulfilled';
            this.promiseResult = value;
            this.onFulfilledCallBacks.forEach(fn => fn());
        }
        
        reject(reason) {
            if (this.promiseState != 'pending') return; 
            this.promiseState = 'rejected';
            this.promiseResult = reason;
            this.onRejectedCallBacks.forEach(fn => fn());
        }
        
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
            onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
            var thenPromise = new MyPromise((resolve, reject) => {
                var rp = (cb) => {
                    // 这里的cb就是回调onFulfilled or 回调onRejected
                    try {
                        var x = cb(this.promiseResult);
                        if (x === thenPromise) return;   // 不能返回自身
                        if (x instanceof MyPromise) {
                            x.then(resolve, reject); // 如果是promise 抛出结果
                        }
                        else {
                            resolve(x);   // 普通值,走resolve
                        }
                    }
                    catch (e) {
                        reject(e);
                    }
                }
                if (this.promiseState === 'pending') {
                    // 在pending状态下: 分别存入fulfilled和rejected对应的数组
                    // 主要是为了处理executor中是异步的情况
                    this.onFulfilledCallBacks.push(() => {rp(onFulfilled)});
                    this.onRejectedCallBacks.push(() => {rp(onRejected)});
                }
                if (this.promiseState === 'fulfilled') {
                    // 执行onFulfilled
                    rp(onFulfilled);
                }
                if (this.promiseState === 'rejected') {
                    // 执行onRejected
                    rp(onRejected);
                }
            })
            return thenPromise;
        }
    }

实现Promise.race

    static race(promiseArray) {
        return new Promise((resolve, reject) => {
            if (!Array.isArray(promiseArray)) {
                reject('no array');
            }
            promiseArray.forEach(promise => {
                if (promise instanceof MyPromise) {
                    promise.then(data => {
                        resolve(data);
                    }, err => {
                        reject(err);
                    })
                }
                else {
                    resolve(promise);
                }
            })
        })
    }

实现Promise.all

    static all(promiseArray) {
        const result = [];
        const count = 0;
        return new Promise((resolve, reject) => {
            const addPromsie = (promise, index) => {
                result[index] = promise;
                count++;
                if (count === promiseArray.length) resolve(result);
            }
            
            promiseArray.forEach((promise, index) => {
                if (promise instanceof MyPromise) {
                    promise.then(data => addPromsie(data, index), err => reject(err));
                }
                else {
                    addPromsie(promise, index);
                }
            })
        })
    }

4: Object

1: Object.entries

image.png

    Object.prototype.my_entries = function (obj) {
        if (obj === null || obj === undefined) {
            throw new Error('Cannot convert undefined or null to object');
        }
        let new_arr = [];
        for (let key in obj) {
            obj.hasOwnProperty(key) && new_arr.push([key, obj[key]]);
        }
        return new_arr;
    }

测试用例:

    let example1 = null;
    let example2 = ['a', 'b', 'c'];
    let example3 = { name: 'yhq', age: 24 };
    
    Object.my_entries(example1);
    Object.my_entries(example2);
    Object.my_entries(example3);

2: Object.values

image.png

    Object.prototype.my_values = function (obj) {
        if (obj === null || obj === undefined) {
             throw new Error('Cannot convert undefined or null to object');
        }
         let new_arr = [];
         for (let key in obj) {
             obj.hasOwnProperty(key) && new_arr.push(obj[key]);
         }
         return new_arr;
    }

测试用例

    let example1 = null;
    let example2 = ['a', 'b', 'c'];
    let example3 = { name: 'yhq', age: 24 };
    
    Object.my_values(example1);
    Object.my_values(example2);
    Object.my_values(example3);

3. Object.keys

image.png

     Object.prototype.my_keys = function (obj) {
        if (obj === null || obj === undefined) {
             throw new Error('Cannot convert undefined or null to object');
        }
         let new_arr = [];
         for (let key in obj) {
             obj.hasOwnProperty(key) && new_arr.push(key);
         }
         return new_arr;
    }

测试用例

    let example1 = null;
    let example2 = ['a', 'b', 'c'];
    let example3 = { name: 'yhq', age: 24 };
    
    Object.my_keys(example1);
    Object.my_keys(example2);
    Object.my_keys(example3);

5: 数据结构

1: 链表 --> singleList

简单的介绍一下js中的链表结构,跟正常的C和C++里面是不一样的。

    const singleList = {
        data: 1,
        next: {
            data: 2,
            next: {
                data: 3,
                next: {
                    data: 4,
                    next: null
                }
            }
        }
    }
  1. 链表的创建,增加, 删除,修改
    // 生成链表节点
    class Node {
        constructor(data) {
            this.data = data;
            this.next = null;
        }
    }
    
    class SingleLinkList {
        constructor() {
            this.head = null;
            this.length = 0;
        }
        // 添加
        add(data) {
            let node = new Node(data);
            if (this.head === null) {
                this.head = node;
            }
            else {
                let current = this.head;
                while (current.next) {
                    current = current.next;
                }
                current.next = node;
            }
            this.length++;
        }
        // 获取
        get(data) {
            let current = this.head;
            while (current) {
                if (current.data === data) {
                    return current;
                }
                current = current.next;
            }
        }
        // 插入
        insert(data, target) {
            let node = new Node(data);
            let current = this.head;
            while(current.next) {
                if (current.data === target) {
                    node.next = current.next;
                    current.next = node;
                    this.length++;
                    break;
                }
                current = current.next;
            }
        }
        // 删除
        remove(data) {
            let current = this.head;
            let prev = null;
            while (current) {
                if (current.data === data) {
                    if (prev === null) {
                        // 删除的是头节点
                        this.head = current.next;
                    }
                    else {
                        prev.next = current.next;
                    }
                    return true;
                }
                prev = current;
                current = current.next;
            }
        }
    }
   
  1. 链表是否为环链表
    function hasCycle(linkList) {
        let headNode = linkList.head;
        let slower = headNode;
        let faster = headNode;
        while(slower.next) {
            if (!faster.next || !faster.next.next) {
                return false;
            }
            if (faster === slower) {
                retunr true;
            }
            slower = slower.next; 
            faster = faster.next.next;
        }
    }

6: 其他

1: 常见的js优化

  1. 防抖
    function deboundce(fn, delay) {
        var timer = null;
        return function () {
            if (timer) clearTimeout(timer);
            var args = [...arguments];
            var self = this;
            timer = setTimeout(() => {
                fn.apply(self, ...args);
            }, delay);
        }
    }
  1. 节流
    function throttle(fn, delay) {
        var tag = true;
        return function () {
            if (!tag) return;
            tag = false;
            var args = [...arguments];
            var self = this;
            setTimeout(() => {
                fn.apply(self, ...args);
                tag = true;
            }, delay)
        }
    }
  1. 响应的超时处理
    题目描述:
        如何控制一个接口请求,在给定时间time内可以响应走成功,否则抛出异常
        测试: time = 3s, 接口返回时间是4s, 走错误。
        测试: time = 3s, 接口返回时间是2s, 走成功。
    function getIterator(timer) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                // 用setTimeout模拟一下接口请求
                resolve('get data')
            }, timer)
        })
    }
    
    function sleep(delay) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('error');
            }, delay)
        })
    }
    
    function timeOut(sleep, delay) {
        return new Promise.all([getIterator(4), sleep(delay)]);
    }