算法相關總結

//call apply bind 的實現
//call的實現
//將函數設爲傳入參數的屬性
//指定this到函數並傳入給定參數執行函數
//如果不傳入參數或者參數爲null,默認指向爲 window / global
//刪除參數上的函數
Function.prototype.call = function(content) {
    /** 如果第一個參數傳入的是 null 或者是 undefined, 那麼指向this指向 window/global */
    /** 如果第一個參數傳入的不是null或者是undefined, 那麼必須是一個對象 */

    if (!content) {
        content = typeof window === 'undefined' ? global : window
    }
    content.fn = this //this  指向的是當前的函數(Function的實例)

    let rest = [...arguments].slice(1) //獲取除了this指向對象以外的參數, 空數組slice後返回的仍然是空數組

    let result = content.fn(...rest) //隱式綁定,當前函數的this指向了content.

    delete content.fn
    return result

}

//實現call
// 模擬 call bar.mycall(null);
//實現一個call方法:
Function.prototype.myCall = function(context) {
    //此處沒有考慮context非object情況
    context.fn = this;
    let args = [];
    for (let i = 1, len = arguments.length; i < len; i++) {
        args.push(arguments[i]);
    }
    context.fn(...args);
    let result = context.fn(...args);
    delete context.fn;
    return result;
};
//實現apply
// 模擬 apply
Function.prototype.myapply = function(context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    } else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push("arr[" + i + "]");
        }
        result = eval("context.fn(" + args + ")");
    }

    delete context.fn;
    return result;
};
//實現bind
Function.prototype.mybind = function(context, ...rest) {
        return (...params) => this.call(context, ...rest, ...params);
    }
    // mdn的實現
if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== 'function') {
            // closest thing possible to the ECMAScript 5
            // internal IsCallable function
            throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function() {},
            fBound = function() {
                // this instanceof fBound === true時,說明返回的fBound被當做new的構造函數調用
                return fToBind.apply(this instanceof fBound ?
                    this :
                    oThis,
                    // 獲取調用時(fBound)的傳參.bind 返回的函數入參往往是這麼傳遞的
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        // 維護原型關係
        if (this.prototype) {
            // Function.prototype doesn't have a prototype property
            fNOP.prototype = this.prototype;
        }
        // 下行的代碼使fBound.prototype是fNOP的實例,因此
        // 返回的fBound若作爲new的構造函數,new生成的新對象作爲this傳入fBound,新對象的__proto__就是fNOP的實例
        fBound.prototype = new fNOP();

        return fBound;
    };
}

//先打印a隔兩秒打印b
new Promise(function(resolve) {
    console.log('a')
    resolve()
}).then(
    function() {
        setTimeout(function() {
            console.log('b')
        }, 2000)
    }
)

function test() {
    console.log('a');
    setTimeout(function() {
            console.log('b')
        },
        2000)
}
test();

function test() {
    console.log(1)
    setTimeout(function() { // timer1
        console.log(2)
    }, 1000)
}

test();

//apply  第二個參數必須是數組或者類數組
Function.prototype.apply = function(context, rest) {
        if (!context) {
            //context爲null或者是undefined時,設置默認值
            context = typeof window === 'undefined' ? global : window;
        }
        context.fn = this;
        let result;
        if (rest === undefined || rest === null) {
            //undefined 或者 是 null 不是 Iterator 對象,不能被 ...
            result = context.fn(rest);
        } else if (typeof rest === 'object') {
            result = context.fn(...rest);
        }
        delete context.fn;
        return result;
    }
    //bind()一個函數被 call/apply 的時候,會直接調用,但是 bind 會創建一個新函數。
    //當這個新函數被調用時,bind() 的第一個參數將作爲它運行時的 this,之後的一序列參數將會在傳遞的實參前傳入作爲它的參數。

//字符串操作
//將單詞的首字母大寫
const capitalizeEveryWorld = str => str.replace(/\b[a-z]/g, char => char.toUpperCase())
    //首字母大寫
const capital = ([first, ...rest]) => first.toUpperCase() + rest.join('')
    //字符串翻轉
    //方法一
var arr = str.split('')
var newArr = []
for (let i = 0; i < arr.length; i++) {
    newArr[i] = arr[arr.length - i - 1]
}
var newStr = newArr.join('')
    //方法二
var newStr = ''
for (var i = 0; i < str.length; i++) {
    newStr += str.charAt(str.length - i - 1)
}
//方法三
var newStr = str.split('').reverse().join('')
    //方法四
var arr = str.split('')
var newArr = []
while (arr.length > 0) {
    newArr.push(arr.pop())
}
var newStr = newArr.join('')

//統計字符串出現最多的字母和次數(使用對象)
var str = 'ssssssssssdddfgnghterg'
var n = {}
for (let i = 0; i < str.length; i++) {
    var a = str.charAt(i)
    if (n[a]) {
        n[a]++
    } else {
        n[a] = 1
    }
}
console.log(n)
var max = 0;
var maxchar = null
for (var key in n) {
    if (max < n[key]) {
        max = n[key]
        maxchar = key
    }
}
console.log("最多的字符" + maxchar)
console.log("出現次數" + max)

// 統nums計數組中出現的次數的對象
const nums = [3, 5, 2, 56, 45, 56, 87, 4, 3, 4, 2]
const result = nums.reduce((tally, amt) => {
    tally[amt] ? tally[amt]++ : (tally[amt] = 1)
    return tally
}, {})

console.log(result)

//深拷貝與淺拷貝
//深拷貝
//他無法實現對函數 、RegExp等特殊對象的克隆
//會拋棄對象的constructor,所有的構造函數會指向Object
//對象有循環引用,會報錯
const newObj = JSON.parse(JSON.stringify(oldobj))
    //深拷貝
    /**
     * deep clone
     * @param  {[type]} parent object 需要進行克隆的對象
     * @return {[type]}        深克隆後的對象
     */
const clone = parent => {
    // 判斷類型
    const isType = (obj, type) => {
        if (typeof obj !== "object") return false;
        const typeString = Object.prototype.toString.call(obj);
        let flag;
        switch (type) {
            case "Array":
                flag = typeString === "[object Array]";
                break;
            case "Date":
                flag = typeString === "[object Date]";
                break;
            case "RegExp":
                flag = typeString === "[object RegExp]";
                break;
            default:
                flag = false;
        }
        return flag;
    };

    // 處理正則
    const getRegExp = re => {
        var flags = "";
        if (re.global) flags += "g";
        if (re.ignoreCase) flags += "i";
        if (re.multiline) flags += "m";
        return flags;
    };
    // 維護兩個儲存循環引用的數組
    const parents = [];
    const children = [];

    const _clone = parent => {
        if (parent === null) return null;
        if (typeof parent !== "object") return parent;

        let child, proto;

        if (isType(parent, "Array")) {
            // 對數組做特殊處理
            child = [];
        } else if (isType(parent, "RegExp")) {
            // 對正則對象做特殊處理
            child = new RegExp(parent.source, getRegExp(parent));
            if (parent.lastIndex) child.lastIndex = parent.lastIndex;
        } else if (isType(parent, "Date")) {
            // 對Date對象做特殊處理
            child = new Date(parent.getTime());
        } else {
            // 處理對象原型
            proto = Object.getPrototypeOf(parent);
            // 利用Object.create切斷原型鏈
            child = Object.create(proto);
        }

        // 處理循環引用
        const index = parents.indexOf(parent);

        if (index != -1) {
            // 如果父數組存在本對象,說明之前已經被引用過,直接返回此對象
            return children[index];
        }
        parents.push(parent);
        children.push(child);

        for (let i in parent) {
            // 遞歸
            child[i] = _clone(parent[i]);
        }

        return child;
    };
    return _clone(parent);
};
//實現instanceof
function instance_of(l, r) {
    var o = r.prototype
    l = l._proto_
    while (true) {
        if (l === null) return false
        if (o === l) {
            return true
            l = l._proto_
        }

    }
}
//實現一個簡單的slice
function my_slice(start, end) {
    var array = [];
    start = start ? start : 0;
    end = end ? end : this.length;
    for (var i = start, j = 0; i < end; i++, j++) {
        array[j] = this[i];
    }
    return array;
}
//實現new

// 它創建了一個全新的對象
// 它會被執行[[Prototype]](也就是__proto__)鏈接
// 它使this指向新創建的對象
// 通過new創建的每個對象將最終被[[Prototype]]鏈接到這個函數的prototype對象上
// 如果函數沒有返回對象類型Object(包含Functoin, Array, Date, RegExg, Error),那麼new表達式中的函數調用將返回該對象引用

function mynew() {
    const obj = new Object()
    const parent = [].shift.call(arguments)
    obj._proto_ = parent.prototype
    const ret = parent.apply(obj, arguments)

    return typeof ret === 'object' ? ret : obj
}

function new2(func) {
    // 創建了一個實例對象 o,並且這個對象__proto__指向func這個類的原型對象 
    let o = Object.create(func.prototype);
    // (在構造函數中this指向當前實例)讓這個類作爲普通函數值行 並且裏面this爲實例對象 
    let k = func.call(o);
    // 最後再將實例對象返回 如果你在類中顯示指定返回值k,
    // 注意如果返回的是引用類型則將默認返回的實例對象o替代掉
    return typeof k === 'object' ? k : o;
}

//深拷貝
function deepClone(obj, hash = new WeakMap()) { //遞歸拷貝
    if (obj instanceof RegExp) {
        return new RegExp(obj)

    }
    if (obj instanceof Date) {
        return new Date(obj)
    }
    if (obj === null || typeof obj != 'object') {
        return obj
    }
    if (hash.has(obj)) {
        return hash.get(obj)
    }
    //如果obj爲數組的話,那麼obj.constructor爲[Functon:Array]
    let t = new obj.constructor()
    hash.set(obj, t)
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) { //是否是自身的屬性
            t[key] = deepClone(obj[key], hash)
        }
    }
    return t;
}

//淺拷貝

//函數柯里化(函數柯里化是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受餘下的參數而且返回結果的新函數的技術。)

function curry(fn, args = []) {
    return function() {
        let rest = [...args, ...arguments];
        if (rest.length < fn.length) {
            return curry.call(this, fn, rest);
        } else {
            return fn.apply(this, rest);
        }
    }
}
//test
function sum(a, b, c) {
    return a + b + c;
}
let sumFn = curry(sum);
console.log(sumFn(1)(2)(3)); //6
console.log(sumFn(1)(2, 3)); //6
//函數柯里化

/**
 * 將函數柯里化
 * @param fn    待柯里化的原函數
 * @param len   所需的參數個數,默認爲原函數的形參個數
 */
function curry(fn, len = fn.length) {
    return _curry.call(this, fn, len)
}

/**
 * 中轉函數
 * @param fn    待柯里化的原函數
 * @param len   所需的參數個數
 * @param args  已接收的參數列表
 */
function _curry(fn, len, ...args) {
    return function(...params) {
        let _args = [...args, ...params];
        if (_args.length >= len) {
            return fn.apply(this, _args);
        } else {
            return _curry.call(this, fn, len, ..._args)
        }
    }
}

//函數柯里化-----接收一部分參數,返回一個函數接收剩餘參數,接收足夠參數後,執行原函數。
/**
 * @param  fn           待柯里化的函數
 * @param  length       需要的參數個數,默認爲函數的形參個數
 * @param  holder       佔位符,默認當前柯里化函數
 * @return {Function}   柯里化後的函數
 */
function curry(fn, length = fn.length, holder = curry) {
    return _curry.call(this, fn, length, holder, [], [])
}
/**
 * 中轉函數
 * @param fn            柯里化的原函數
 * @param length        原函數需要的參數個數
 * @param holder        接收的佔位符
 * @param args          已接收的參數列表
 * @param holders       已接收的佔位符位置列表
 * @return {Function}   繼續柯里化的函數 或 最終結果
 */
function _curry(fn, length, holder, args, holders) {
    return function(..._args) {
        //將參數複製一份,避免多次操作同一函數導致參數混亂
        let params = args.slice();
        //將佔位符位置列表複製一份,新增加的佔位符增加至此
        let _holders = holders.slice();
        //循環入參,追加參數 或 替換佔位符
        _args.forEach((arg, i) => {
            //真實參數 之前存在佔位符 將佔位符替換爲真實參數
            if (arg !== holder && holders.length) {
                let index = holders.shift();
                _holders.splice(_holders.indexOf(index), 1);
                params[index] = arg;
            }
            //真實參數 之前不存在佔位符 將參數追加到參數列表中
            else if (arg !== holder && !holders.length) {
                params.push(arg);
            }
            //傳入的是佔位符,之前不存在佔位符 記錄佔位符的位置
            else if (arg === holder && !holders.length) {
                params.push(arg);
                _holders.push(params.length - 1);
            }
            //傳入的是佔位符,之前存在佔位符 刪除原佔位符位置
            else if (arg === holder && holders.length) {
                holders.shift();
            }
        });
        // params 中前 length 條記錄中不包含佔位符,執行函數
        if (params.length >= length && params.slice(0, length).every(i => i !== holder)) {
            return fn.apply(this, params);
        } else {
            return _curry.call(this, fn, length, holder, params, _holders)
        }
    }
}
//reduce函數的實現
Array.prototype._reduce = function(callback, initvalue) {
        let i = 0;
        let result = initvalue
        if (typeof initvalue === 'undefined') {
            result = this[0]
            i++
        }
        for (let i = 0; i < this.length; i++) {
            result = callback(result, this[i])
        }
        return result
    }
    //add函數的應用
function add() {
    //args用來存儲所有的參數
    var _args = Array.prototype.slice.call(arguments)
        //申明函數利用閉包訪問_args
    var adder = function() {
        _args.push(...arguments)
        return adder
    }

    // 利用toString隱式轉換的特性,當最後執行時隱式轉換,並計算最終的值返回
    adder.toString = function() {
        return _args.reduce(function(a, b) {
            return a + b;
        });
    }
    return adder;
}
//插入排序(從後往前比較 直到碰到比當前項 還要小的前一項時 將這一項插入到前一項的後面)
function insertsort(arr) {
    let len = arr.length
    let preindex, current
    for (let i = 1; i < len; i++) {
        preindex = i - 1;
        current = arr[1]
        while (preindex >= 0 && current < arr[preindex]) {
            arr[preindex + 1] = arr[preindex]
            preindex--
        }
        arr[preindex + 1] = current
    }
    return arr
}

//全排列
const permute = function(nums) {
    if (nums.length <= 1) return [nums]

    const permutes = []
    for (let i = 0; i < nums.length; i++) {
        const num = nums[i]
        const others = nums.slice(0, i).concat(nums.slice(i + 1))
        const list = permute(others)
        list.forEach(item => {
            permutes.push([num].concat(item))
        })
    }
    return permutes
};
const arr = [1, 2, 3]
console.log(permute(arr))

//選擇排序
function selectSort(arr) {
    let len = arr.length;
    let temp = null;
    let minIndex = null;
    for (let i = 0; i < len - 1; i++) { // 把當前值的索引作爲最小值的索引一次去比較
        minIndex = i; // 假設當前項索引 爲最小值索引
        for (let j = i + 1; j < len; j++) { // 當前項後面向一次比小
            if (arr[j] < arr[minIndex]) { // 比假設的值還要小 則保留最小值索引
                minIndex = j; // 找到最小值的索引位置
            }
        }
        // 將當前值和比較出的最小值交換位置
        if (i !== minIndex) {
            temp = arr[i]
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
    return arr;
}

//快排
//快速排序
const QuickSort7 = (array) => {
    const sort = (arr, left = 0, right = arr.length - 1) => {
        if (left >= right) {
            return
        }
        let i = left
        let j = right
        const base = arr[j]
        while (i < j) {
            while (i < j && arr[i] <= base) {
                i++
            }
            arr[j] = arr[i]
            while (j > i && arr[j] >= base) {
                j--
            }
            arr[i] = arr[j]
        }
        arr[j] = base
        sort(arr, left, j - 1)
        sort(arr, j + 1, right)
    }
    const newArray = array.concat()
    sort(newArray)
    return newArray
}

const quickSort = (array) => {
        const sort = (arr, left = 0, right = arr.length - 1) => {
            if (left >= right) { //如果左邊的索引大於等於右邊的索引說明整理完畢
                return
            }
            let i = left
            let j = right
            const baseVal = arr[j] // 取無序數組最後一個數爲基準值
            while (i < j) { //把所有比基準值小的數放在左邊大的數放在右邊
                while (i < j && arr[i] <= baseVal) { //找到一個比基準值大的數交換
                    i++
                }
                arr[j] = arr[i] // 將較大的值放在右邊如果沒有比基準值大的數就是將自己賦值給自己(i 等於 j)
                while (j > i && arr[j] >= baseVal) { //找到一個比基準值小的數交換
                    j--
                }
                arr[i] = arr[j] // 將較小的值放在左邊如果沒有找到比基準值小的數就是將自己賦值給自己(i 等於 j)
            }
            arr[j] = baseVal // 將基準值放至中央位置完成一次循環(這時候 j 等於 i )
            sort(arr, left, j - 1) // 將左邊的無序數組重複上面的操作
            sort(arr, j + 1, right) // 將右邊的無序數組重複上面的操作
        }
        const newArr = array.concat() // 爲了保證這個函數是純函數拷貝一次數組
        sort(newArr)
        return newArr
    }
    // jsonp
function foo(data) {
    console.log()
}

function addscriptTags(src) {
    var script = document.createElement('script')
    script.setAttribute("type", "text/javascript")
    script.src = src
    document.body.appendChild(script)
}
window.onload = function() {
    addscriptTags("http://example.com/ip?callback = foo")
}


//實現一個foo函數,返回自身調用次數:
function helper() {
    var count = 0;
    return function() {
        count++;
        console.log("count", count)
    }
}
var foo = helper()
    //發佈訂閱者模式
    //創建一個對象(緩存列表)
    //on方法用來把回調函數fn都加到緩存列表中
    //emit方法取到arguments裏第一個當做key,根據key值去執行對應緩存列表中的函數
    //remove方法可以根據key值取消訂閱
let event = {
    list: {},
    on(key, fn) {
        if (!this.list[key]) {
            this.list[key] = [];
        }
        this.list[key].push(fn);
    },
    emit() {
        let key = [].shift.call(arguments),
            fns = this.list[key];

        if (!fns || fns.length === 0) {
            return false;
        }
        fns.forEach(fn => {
            fn.apply(this, arguments);
        });
    },
    remove(key, fn) {
        // 這回我們加入了取消訂閱的方法
        let fns = this.list[key];
        // 如果緩存列表中沒有函數,返回false
        if (!fns) return false;
        // 如果沒有傳對應函數的話
        // 就會將key值對應緩存列表中的函數都清空掉
        if (!fn) {
            fns && (fns.length = 0);
        } else {
            // 遍歷緩存列表,看看傳入的fn與哪個函數相同
            // 如果相同就直接從緩存列表中刪掉即可
            fns.forEach((cb, i) => {
                if (cb === fn) {
                    fns.splice(i, 1);
                }
            });
        }
    }
};

function cat() {
    console.log('一起喵喵喵');
}

function dog() {
    console.log('一起旺旺旺');
}

event.on('pet', data => {
    console.log('接收數據');
    console.log(data);
});
event.on('pet', cat);
event.on('pet', dog);
// 取消dog方法的訂閱
event.remove('pet', dog);
// 發佈
event.emit('pet', ['二哈', '波斯貓']);
/*
    接收數據
    [ '二哈', '波斯貓' ]
    一起喵喵喵
*/
let crop = {}
crop.list = {}
crop.on = function(key, fn) {
    if (!this.list[key]) {
        this.list[key] = []
    }
    //有了的話直接把函數添加到緩存隊列裏
    this.list[key].push(fn)

}
crop.emit = function() {
    //用shift取出第一個參數---key值
    let key = [].shift.call(arguments)
        //把函數列表取出來放在fns中
    fns = this.list[key]
        //如果緩存隊列沒有函數的話就返回false
    if (!fns || fns.length === 0) {
        return false
    } else {
        fns.forEach(fn => {
            fn.apply(this, arguments)
        })
    }
}

//手寫封裝ajax的處理

//LazyMan的實現
//

//要求任務並行完成,同時並行的任務不能超過兩個。

class Scheduler {
    constructor() {
        this.cur = 0;
        this.prepare = [];
    }
    run() {
        if (this.prepare.length == 0) return;
        const [task, resolve] = this.prepare.shift();
        this.cur += 1;
        task().then(_ => {
            this.cur -= 1
            resolve();
            this.run();
        })
    }
    add(promiseCreator) {
        return new Promise((res, rej) => {
            this.prepare.push([promiseCreator, res]);
            if (this.cur < 2) {
                this.run();
            }
        })
    }
}
const timeout = (time) => new Promise(resolve => {
    console.log("in timeout:", time);
    setTimeout(resolve, time)
});
const scheduler = new Scheduler();
const addTask = (time, order) => {
    scheduler.add(() => timeout(time)).then(() => console.log(order))
};
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
addTask(100, '5')
    // output: 2 3 1 5 4
    // 一開始,1、2兩個任務進入隊列
    // 500ms時,2完成,輸出2,任務3進隊
    // 800ms時,3完成,輸出3,任務4進隊
    // 1000ms時,1完成,輸出1,任務5進隊
    // 1100ms時,5完成,輸出5// 1200ms時,4完成,輸出4

//原生ajax
function ajax(method, url, data, callback, type) {
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
    } else {
        xhr = new ActiveXObject("Microsoft.XMLHttp")
    }
    xhr.onreadystateChange = function() {
        if (xhr.state == 200 && xhr.readyState == 4) {
            if (type == "json") {
                var res = JSON.parse(xhr.responseText);
            } else if (type == "xml") {
                var res = responseXML
            } else {
                var res = xhr.responseText
            }
            callback(res)
        }
    }
    var param = ''
    if (JSON.stringify(data) != '{}') {
        url += '?'
        for (var i in data) {
            param += i + '=' + data[i] + "&"
        }
        param = param.slice(0, param.length - 1)
    }

    if (method == 'get') {
        url = url + param
    }
    //初始化請求
    xhr.open(method, url, true)
    if (method == 'post') {
        xhr.setRequestHeader("content-Type", "application/x-www-fprm-urlencoded")
        xhr.send(param)
    } else {
        xhr.send(null)
    }

}
//promise.all的實現
Promise.all = function(promises) {
        return new Promise((resolve, reject) => {
            let index = 0;
            let result = [];
            if (promises.length === 0) {
                resolve(result);
            } else {
                function processValue(i, data) {
                    result[i] = data;
                    if (++index === promises.length) {
                        resolve(result);
                    }
                }
                for (let i = 0; i < promises.length; i++) {
                    //promises[i] 可能是普通值
                    Promise.resolve(promises[i]).then((data) => {
                        processValue(i, data);
                    }, (err) => {
                        reject(err);
                        return;
                    });
                }
            }
        });
    }
    //防抖
function debounce(fn, time) {
    let timer = null;
    return function() {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, time)
    }
}
// 防抖函數
const debounce = (fn, delay) => {
    let timer = null;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, delay);
    };
};
//節流
function throttle(fn, delay) {
    let flag = true
    return function() {
        if (!flag) return
        flag = false
        setTimeout(() => {
            fn.apply(this, arguments)
            flag = true
        }, delay)
    }
}
//數組去重
//set(轉化爲數組有兩種,拓展運算符,Array.from(new set(myarr)))
function unique(arr) {
    var newArr = []
    for (let i = 0; i < arr.length; i++) {
        if (newArr.indexOf(arr[i]) === -1) {
            newArr.push(arr[i])
        }
    }
    return newArr
}

function unique1(arr) {
    var sortArr = arr.sort()
    var newArr = []
    for (let i = 0; i < arr.length; i++) {
        if ((sortArr[i] !== sortArr[i - 1])) {
            newArr.push(sortArr[i])
        }
    }
    return newArr;
}

function unique2(arr) {
    var newArr = []
    for (let i = 0; i < arr.length; i++) {
        if (newArr.includes(arr[i])) {
            newArr.push(arr[i])
        }
    }
}

function unique4(arr) {
    return Array.from(new set(arr))
}

function unique(arr) {
    var newarr = []
    newarr = arr.filter(function(item) {
        return newarr.includes(item) ? '' : newarr.push(item)
    })
    return newarr
}

function unipue5() {
    const newarr = []
    this.forEach((item) => {
        if (!newarr.includes(item)) {
            newarr.push(item)
        }
    })
    return newarr
}

function unique8() {
    const tmp = new Map()
    const newarr = []
    for (let i = 0; i < arr.length; i++) {
        if (!tmp.has(arr[i])) {
            tmp.set(arr[i], 1)
            newarr.push(arr[i])
        }
    }
}

function unique3(arr) {
    var obj = {}
    var newArr = []
    for (let i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            obj[arr[i]] = 1
            newArr.push(arr[i])
        }
    }
    return newArr
}
//數組扁平化處理
let arr = [
    [1, 2], 3, [
        [
            [4], 5
        ]
    ]
]; // 數組展平
function flatten(arr) {
    return [].concat(
        ...arr.map(x => Array.isArray(x) ? flatten(x) : x)
    )
}

//全排列
const permute = function(nums) {
    if (nums.length <= 1) return [nums]

    const permutes = []
    for (let i = 0; i < nums.length; i++) {
        const num = nums[i]
        const others = nums.slice(0, i).concat(nums.slice(i + 1))
        const list = permute(others)
        list.forEach(item => {
            permutes.push([num].concat(item))
        })
    }
    return permutes
};
const arr = [1, 2, 3]
console.log(permute(arr))


//根據數組某個屬性去重
function unique(arr) {
    const res = new Map()
    return arr.filter(item => {
        !res.has(item.productName) && res.set(item.productName, 1)
    })
}
//promise的finally實現
Promise.prototype.finally = function(callback) {
        const p = this.constructor
        return this.then(
            value => p.resolve(callback()).then(() => value),
            reason => p.resolve(callback()).then(() => { throw reason })
        )
    }
    // computed的實現
    //1.data 屬性初始化 getter setter
    //2. computed 計算屬性初始化,提供的函數將用作屬性 vm.reversedMessage 的 getter
    //3. 當首次獲取 reversedMessage 計算屬性的值時,Dep 開始依賴收集
    //4. 在執行 message getter 方法時,如果 Dep 處於依賴收集狀態,則判定 message 爲 reversedMessage 的依賴,並建立依賴關係
    //5. 當 message 發生變化時,根據依賴關係,觸發 reverseMessage 的重新計算
    //十進制轉化爲其他進制(利用棧)
function divideBy2(decNumber, base = 2) {
    let remStack = new Stack()
    let rem
    let binaryString = ''
    let digits = '0123456789ABCDEF'
    while (decNumber > 0) {
        rem = Math.floor(decNumber % base)
        remStack.push(rem)
        decNumber = Math.floor(decNumber / base)
    }
    while (!remStack.isEmpty()) {
        binaryString += digits[remStack.pop()].toString()
    }
    return binaryString
}

// 將十進制轉換成其他進制
let num = 100345
num.toString(2) // "11000011111111001"
num.toString(8) // "303771"

console.log(divideBy2(num, 2)) // "11000011111111001"
console.log(divideBy2(num, 8)) // "303771"

//push 和pop的實現(Array的push底層實現是依賴於 數組的length屬性的)
Array.prototype.push2 = function(...rest) {
    this.splice(this.length, 0, ...rest)
    return this.length;
}

//簡易promise的實現
class Promise {
    constructor(fn) {
        this.status = 'Pending'
        setTimeout(() => {
            fn((data) => {
                this.resolve(data)
            }, (error) => {
                this.reject(error)
            })
        })
    }

    resolve(data) {
        if (this.status === 'Pending') {
            this.success(data)
            this.status = 'Fulfilled'
        }
    }

    reject(error) {
        if (this.status === 'Pending') {
            this.error(error)
            this.status = 'Rejected'
        }
    }

    then(success, error) {
        this.success = success
        this.error = error
    }
}

let p1 = new Promise((resolve, reject) => {
    // reject('hello error');
    setTimeout(() => {
        resolve('hello promise')
    }, 1000)
})

p1.then((data) => console.log(data), (err) => console.log(err))

//在一個數組中 如a、b兩項, 要保證a和b兩項的差 與 a和b兩項索引的差 的相加後的結果max 是數組中其他兩項max 中的最大值 找出符合條件兩項a, b的值 (不可以排序 或改變數組位置)
// 思路:其實也就是找出數組中當前的每一項與自身索引相加後的和的最大值以及與索引相加後的最小值的和 找出符合條件的兩項即可 如 let result = (maxItem-minItem) + (maxIndex-minIndex) 等價於 (maxItem+maxIndex) - (minItem+minIndex)

// let arr = [1, 2, 3, 4, 5, 6]; // 最簡單的測試數組 最小項1 最大項6
// 很顯然這個數組中最大值6與索引相加(6+5)是當中最大值11 1與索引相加(1+0)爲當中的最小值1(6 + 5)-(1+0)= 10

// 假設法
let arr = [2, 10, 9, 1, 8, 3, 4];
let minItem = arr[0]; // 假設第一項與自身索引的和是最小值 索引爲0因此省略
let maxItem = arr[0]; // 假設第一項與自身索引的和是最大值 索引爲0因此省略
let min = minItem; // 最小項
let max = maxItem; // 最大項
let minIndex = 0; // 最小項索引
let maxIndex = 0; // 最大項索引
for (let i = 1; i < arr.length; i++) {
    let cur = arr[i] + i; // 當前項和自身索引的和
    cur < minItem ? (minItem = cur, min = arr[i], minIndex = i) : null;
    cur > maxItem ? (maxItem = cur, max = arr[i], maxIndex = i) : null;
}
console.log(maxItem, minItem); // 最大項與索引的和 最小項與索引的和
console.log(max, min); // 最大項 最小項
console.log(maxIndex, minIndex); // 最大項的索引 最小項的索引

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章