前端常用手写代码

个人去面试时。有时会遇到一些手写代码题。
花了点时间来总结一下,希望对大家有所帮助。

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'));
    }
复制代码
  • 持续更新中......
  • 欢迎点赞关注
  • 欢迎批评指正

转载于:https://juejin.im/post/5ce3e672e51d4577583ddc1f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值