前端常用手寫程式碼

田小菜發表於2019-05-21

個人去面試時。有時會遇到一些手寫程式碼題。
花了點時間來總結一下,希望對大家有所幫助。

1,call的模擬實現

Function.prototype.myCall = function(context, ...rest){
    context = context || window;
    let fn = this;
    context.fn = fn;
    context.fn(...rest);
    delete context.fn;
}
// 簡單測試
let obj = {
    name: '彭彭彭'
};
function test(){
    console.log('arguments=',arguments); // Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log('this=',this); // {name: "彭彭彭", fn: ƒ}
}
test.myCall(obj,1,2);
複製程式碼

call的作用:

  1. 改變呼叫方法的this指向,使函式的this和傳入的context的作用域保持一致,常用來封裝一些方法或者做一些原始碼框架比較常用。
  2. 檢測型別,Object.prototype.toString.call(type)。call配合toString可以用來判斷變數型別。

2,apply的模擬實現

Function.prototype.myCall = function(context, ...rest){
    context = context || window;
    let fn = this;
    context.fn = fn;
    context.fn(rest); // 與call傳參不一致。其他是一樣的。就不詳述了
    delete context.fn;
}
複製程式碼

3,bind的模擬實現

Function.prototype.myBind = function(context, ...oldArg){
    let cont = context || window;
    let fn = this;
    let emptyFn = function() {};
    // 比call,apply多一個閉包而已。同時改變this的指向,延緩函式執行。
    function newFn(...newArg){
        var arg = [...oldArg, ...newArg];
        return fn.apply(cont, arg);
    }
    // 繼承老函式的原型方法
    newFn.prototype = fn.prototype ? fn.prototype : emptyFn.prototype;
    // 同時保持新函式原型的constructor不變
    newFn.prototype.constructor = newFn;
    return newFn;
}
複製程式碼

4,reduce的模擬實現

Array.prototype.myReduce = function(fn, initValue){
    if(!this.length){
        if(initValue) {
            return initValue;
        } else {
            throw('error');
        }
    } else {
        let startValue = initValue ? initValue : this[0];
        let startIndex = initValue ? 1 : 0;
        for(let i = 0; i < this.length; i++){
            startValue = fn(startValue, this[startIndex]);
        }
        return startValue;
    }
}
複製程式碼

5,deepCopy深拷貝的模擬實現

    function checkType (type) {
        return Object.prototype.toString.call(type).slice(8, -1);
    }
    function deepCopy(obj) {
        let type = checkType(obj);
        let newObj = null;
        if (type === 'Object') {
            newObj = {};
        } else if(type === 'Array' ) {
            newObj = [];
        } else {
            return obj;
        }
        for(let key in obj) {
            let value = obj[key];
            let valueType = checkType(value);
            if (valueType === 'Array' || valueType === 'Object') {
                arguments.callee(value);// 遞迴呼叫
            } else {
                if (!newObj.hasOwnProperty(value)) {
                    newObj[key] = value;
                }
            }
            
        }
        return newObj; 
        
    }
    
   
複製程式碼

6,debounce防抖的模擬實現

Function.prototype.myDebounce = function(cb, wait) {
    let timer = null;
    return function (...rest) {
        if (timer) {
            // 如果上次的定時器還存在,則清除。重新等待時間
            clearTimeour(timer);
        }
        timer = setTimeout(() => {// 使用箭頭函式,確保this還能定義在當前執行環境
            // 裡邊的閉包的this必須保持和callback保持一致。確保使用ok
            cb.apply(this, rest);
        }, wait)
    }
}
    
複製程式碼

7,throttle防抖的模擬實現

Function.prototype.myThrottle = function(cb, wait) {
    let flag = false;
    return function(...rest) {
        if (flag) {
            return;
        }
        flag = true;// 在wait時間範圍內。。通過flag不讓執行cb;
        setTimeout(() => {
            cb.apply(this, rest);
            flag = false;
        }, wait)
    }
}

複製程式碼

8,兩個無限大值想加的實現

// 如: 12341234123 + 32323423342
function infinite(a, b) {
    let num = 0;
    let str = '';
    let aArr = a.split('');
    let bArr = b.split('');
    while(aArr.length || bArr.length || ) {
        num += (~~aArr.pop()) + (~~b.Arr.pop());// 取個位相加
        str = num + ''; 
        num = num > 9; // true 轉換為 1,我們借用 Js 的型別轉換,完成了邏輯上的逢10進1操作。false時就不用進1
    }
    return str;
}
    
複製程式碼

9,獲取cookie引數的實現

function getCookie(key) {
    let arr;
	let reg = new RegExp("(^| )" + key + "=([^;]*)(;|$)");
	if (arr = document.cookie.match(reg)) {
		return unescape(arr[2]);
	} else {
		return null;
	}
}

// 寫入COOKIES
function $setCookie(name, value, expires, path, domain, secure) {
    var exp = new Date();
    expires = arguments[2] || null;
    path = arguments[3] || '/';
    domain = arguments[4] || null;
    secure = arguments[5] || false;
    expires ? exp.setMinutes(exp.getMinutes() + parseInt(expires)) : '';
    document.cookie = name + '=' + escape(value) + (expires ? ';expires=' + exp.toGMTString() : '') + (path ? ';path=' + path : '') + (domain ? ';domain=' + domain : '') + (secure ? ';secure' : '');
}

// 刪除cookie
function $delCookie(name, path, domain, secure) {
    var value = $getCookie(name);
    if (value != null) {
        var exp = new Date();
        exp.setMinutes(exp.getMinutes() - 1000);
        path = path || '/';
        document.cookie = name + '=;expires=' + exp.toGMTString() + (path ? ';path=' + path : '') + (domain ? ';domain=' + domain : '') + (secure ? ';secure' : '');
    }
}
    
複製程式碼

10,獲取url引數的實現

    function $getQuery(name, url) {
        var u = url || window.location.search;
        var reg = new RegExp('(^|&)' + name + '=([^&#]*)(&|#|$)');
        var r = u.substr(u.indexOf('?') + 1).match(reg);
        return r != null ? r[2] : '';
    }
複製程式碼

11,氣泡排序

// 從小到大
const sort = arr => {
    let res = []
    arr.forEach((v, i) => {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                [arr[i],arr[j]] = [arr[j],arr[i]]
            }
        }
    })
    return arr
}


複製程式碼

12,菲薄拉契數列

function Fibonacci (n) {
  if ( n <= 1 ) {return 1};
  return Fibonacci(n - 1) + Fibonacci(n - 2);
}
複製程式碼

13,組合繼承

Function Father(name){
  this.name  = name;
  this.num = ['12'];
}
father.prototype.father = function(){
  console.log(this.name);
}

function Child(age,name){
  Father.call(this,name);//繼承屬性
  this.age = age;
}
Child.prototype = new Father();//繼承方法
Child.prototype.constructor = Child;
Child.prototype.sayage = function(){
  console.log(this.age);
}

var c1 = new Child(16,"小花");
c1.sayage();//16
c1.sayname();//小花
c1.num.push(13);
console.log(c1.num)//12,13

var c2 = new Child(18,"小明");
c2.sayage();//18
c2.sayname();//小明
console.log(c2.num)//12
複製程式碼

13,時間戳獲取日期時間格式

 function $addZero(v, size) {
    for (var i = 0, len = size - (v + '').length; i < len; i++) {
        v = '0' + v;
    }
    return v + '';
}
function $formatDate(date, formatStr) {
    var arrWeek = ['日', '一', '二', '三', '四', '五', '六'];
    var str = formatStr
        .replace(/yyyy|YYYY/, date.getFullYear())
        .replace(/yy|YY/, $addZero(date.getFullYear() % 100, 2))
        .replace(/mm|MM/, $addZero(date.getMonth() + 1, 2))
        .replace(/m|M/g, date.getMonth() + 1)
        .replace(/dd|DD/, $addZero(date.getDate(), 2))
        .replace(/d|D/g, date.getDate())
        .replace(/hh|HH/, $addZero(date.getHours(), 2))
        .replace(/h|H/g, date.getHours())
        .replace(/ii|II/, $addZero(date.getMinutes(), 2))
        .replace(/i|I/g, date.getMinutes())
        .replace(/ss|SS/, $addZero(date.getSeconds(), 2))
        .replace(/s|S/g, date.getSeconds())
        .replace(/w/g, date.getDay())
        .replace(/W/g, arrWeek[date.getDay()]);

    return str;
}
    
複製程式碼

14,獲取每三位分隔符333132123 =>333,132,123

    
複製程式碼

15,獲取1-100的質數

  
複製程式碼

16,判斷型別

function typeIs(target) {
    return Object.prototype.toString.apply(target).match(/\[object\s(\w+)\]/)[1].toLowerCase();
}
複製程式碼

17,把html標記轉為實體編碼

/**
 * 把html標記轉為實體編碼
 * @param html
 * @returns {string}
 */
function $encodeHtml(html) {
    if (typeof html !== 'string') {
        return '';
    }
    var _ele = document.createElement('div');
    if (document.innerText) {
        _ele.innerText = html;
    } else {
        _ele.textContent = html;
    }
    return _ele.innerHTML;
}
複製程式碼

18, 獲取伺服器當前時間

    function xhrMaker() {
        var xhr;
        try { // Firefox, Opera 8.0+, Safari
            xhr = new XMLHttpRequest();
        } catch (e) { // Internet Explorer
            try {
                xhr = new window.ActiveXObject('Msxml2.XMLHTTP');
            } catch (e) {
                try {
                    xhr = new window.ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {
                    xhr = null;
                }
            }
        }
        return xhr;
    }
    // 獲取伺服器當前時間
    function $getServerTime(url) {
        var sysTime = document.getElementById('SYSTIME');
        if (sysTime) {
            var ts = sysTime.value.substring(0, 19).split('-');
            var dObj = new Date(ts[0], parseInt(ts[1], 10) - 1, ts[2], ts[3], ts[4], ts[5]);
            return dObj;
        }
        var xhr = xhrMaker();
        url = url || ('//' + window.location.hostname + '/favicon.ico?t=' + Math.random());
        try {
            xhr.open('HEAD', url, false);
            xhr.send();
        } catch (e) {
            return new Date();
        }
        return new Date(xhr.getResponseHeader('Date'));
    }
複製程式碼
  • 持續更新中......
  • 歡迎點贊關注
  • 歡迎批評指正

相關文章