前端招聘之路-手写

前端面试会这些手写,大多数的公司没什么问题,理解一遍,跟着写一遍,再默写几遍

手写promise

function myPromise(executor){
	this.status='pending';
	this.value=null;
	this.reason=null;
	this.onFulfilledCallbacks=[];
	this.onRejectedCallbacks=[];
	function resolve(value){
		if(this.status=='pending'){
			this.status='fulfilled';
			this.value=value;
			this.onFulfilledCallbacks.forEach(item=>{item(value)});
		}
	}
	function reject(reason){
		if(this.status=='pending'){
			this.status='rejected';
			this.reason=reason;
			this.onRejectedCallbacks.forEach(item=>{item(reason)});
		}
	}
	executor&&executor(resolve,reject);
}
myPromise.prototype.then(onFulfilled,onRejected){
	onFulfilled= typeof onFulfilled=='function'?onFulfilled:data=>data;
	onRejected=typeof onRejected=='function'?onRejected:err=>throw err;
	if(this.status=='fulfilled'){
		resolve(this.value);
	}
	if(this.status=='rejected'){
		reject(this.reason);
	}
	if(this.status=='pending'){
		this.onFulfilledCallbacks.push(onFulfilled);
		this.onRejectedCallbacks.push(onRejected);
	}
}
function promiseAll(promises){//给每个请求增加自己的catch,避免promiseall.catch提前跳出
	return new Promise(resolve,reject){
		if(!Array.isArray(Array.from(promises))) throw TypeError('error');
		let counter=0,Interator=0,result=[];
		for(let i of promises){
			interator++;
			Promise.resolve(i).then(value=>{
				counter++;
				results.push(value);
				if(counter==Interator){
					resolve(results);
				}
			},err=>return reject(err))
		}
	}
}
function promiseRace(promises) {  
    return new Promise((resolve,reject) => {
		if(!Array.isArray(Array.from(promises))) throw TypeError('error');
        for (const p of promises) {
            Promise.resolve(p)
            .then((res) => {
                resolve(res)
            })
            .catch(e => {
                reject(e)
            })
        }
    })
}

手写repeat

function myrepeat(fn,times,timeout){
	return function(content){
		let count=0;
		let timer=setInterval({
			count++;
			fn(content);
			if(count==times) clearInterval(timer);
		},timeout)
	}
}
let repeat1=myrepeat(console.log,4,2000);
repeat1('1')

for+定时器 三种写法

//var改let for每次循环是新块作用域
for (let i=1; i<=5; i++) {
	setTimeout(function(){
		console.log(i);
	}, 1000);
}
//匿名函数
for(var i=0;i<n;i++){
	(function(j){
		setTimeout(function(){
		console.log(j);}
		,1000);
	})(i)
}
//第三个参数
for(var i=0;i<n;i++){
	setTimeout(function(j){
	console.log(j);}
	,1000,i);
}

给ul下的li绑定onclick并输出,事件没有触发

var oli = document.getElementsByTagName("li");
    for(var i=0; i<oli.length; i++){
        (function(j){
            oli[j].onclick = function () {
            alert(j);
        };
        })(i)
		}
//js事件委托
 var ul = document.querySelector("ul");
    ulItem.onclick = function (e) {
        e = e || window.event; //这一行及下一行是为兼容IE8及以下版本
        var target = e.target || e.srcElement;
        if (target.tagName.toLowerCase() === "li") {
            var li = this.querySelectorAll("li");
            index = Array.prototype.indexOf.call(li, target);
            alert(target.innerHTML + index);
        }
    }

防抖 每次执行重新计时,场景:逐字联想

function debounce(fn,wait){
	let timer;
	return function(args){
		clearInterval(timeout);
		timer=setTimeout(()=>{
			fn(args);
		},wait)
	}
}

节流 固定时间内只能执行一次,场景:提交表单

function throttle(fn,wait){
	let timer;
	return function(args){
		if(!timer){
			timer=setTimeout(()=>{
				timer=null;
				fn(args);
			},wait)
		}
	}
}

深拷贝

function deepclone(source){
	if(typeof source!=='object') return source;
	var obj=Array.isArray(source)?[]:{};
	for(let i in source){
		obj[i] = typeof source[i] == "object" ? deepclone(source[i]) : source[i];
	}
	return obj;
}

call 多个参数

Function.prototype.mycall=function(context){
	if(typeof this!='function'){
		throw new Error('error');
	}
	context=context||window;
	context.fn=this;
	var args=[...arguments].slice(1)
	return context.fn(...args)	
}

apply 两个参数,第二个参数是数组

Function.prototype.myapply=function(context){
	if(typeof this!='function'){
		throw new Error('error');
	}
	context=context||window;
	context.fn=this;
	var args=arguments[1]
	return context.fn(...args)	
}

bind 返回一个新的函数,必须调用才能执行

Function.prototype.mybind = function (context) {
    if(typeof this!='function'){
    	throw new Error('error');
    }
	context = context || window;
    let args = [...arguments].slice(1);
    context.fn = this;
    return function () {
        context.fn(...args)
    }
}

new

Function.prototype.myNew = function () {
  let obj = Object.create(this.prototype)//基于原型创建一个新对象
  let result = this.call(obj, ...arguments)//继承属性,获取函数执行的结果
  return result instance of Object ? result : obj//返回一个对象就返回,不是返回新创建的对象
}

闭包实现单例

function singletone(fn){
	let result;
	return function(){
		result||(result=fn.apply(this,arguments))
	}
}

lodash

// 处理 path, path有三种形式:'a[0].b.c'、'a.0.b.c' 和 ['a','0','b','c'],需要统一处理成数组,便于后续使用
function basePath(path) {
    if (Array.isArray(path)) return path // 若是数组,则直接返回
    return path.replace(/\[/g, '.').replace(/\]/g, '').split('.')// 若有 '[',']',则替换成将 '[' 替换成 '.',去掉 ']'
}
//lodash.get
function get(object, path, defaultValue) {
    if (typeof object !== 'object') return defaultValue// 判断 object 是否是数组或者对象,否则直接返回默认值 defaultValue
    return basePath(path).reduce((o, k) => (o || {})[k], object) || defaultValue// 沿着路径寻找到对应的值,未找到则返回默认值 defaultValue
}
//lodash.set
function set(object, path, value) {
    if (typeof object !== 'object') return object;
    basePath(path).reduce((o, k, i, _) => {
        if (i === _.length - 1) { // 若遍历结束直接赋值
            o[k] = value
            return null
        } else if (k in o) { // 若存在对应路径,则返回找到的对象,进行下一次遍历
            return o[k]
        } else { // 若不存在对应路径,则创建对应对象,若下一路径是数字,新对象赋值为空数组,否则赋值为空对象
            o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {}
            return o[k]
        }
    }, object)
    return object;
}

eventbus

class EventEmitter {
        constructor() {
                this.events = {};
        }
		//触发,传递参数
        emit(event, ...args) {
            const cbs = this.events[event];
            if (!cbs) {// 因为下方off会将this.events[event]重新赋值为null,所以需要判断一下
                console.log('没有当前事件');
                return this;
            }
            cbs.forEach((cb) => {//遍历执行所有回调
                cb(...args)
            });
            return this;
        }
        //监听,执行回调
        on(event, cb) {
            if (!this.events[event]) {//如果events里面没有事件监听,那么就初始化为一个数组,一个事件可能有多个监听
                this.events[event] = [];
            }
            this.events[event].push(cb);
            return this;
        }
        //移除监听回调
        off(event, cb) {
            const func = (...args) => {//注册一个方法,只执行一次,执行完成后直接注销掉
                this.off(event, func);//先把事件监听移除掉,再去执行cb
                cb(...args);
            };
            this.on(event, func);
            return this;
        }
        // 只监听一次,执行回调
        once(event, cb) {
            if (!cb) {//没有cb,就移除所有监听,有就去除这个回调
                this.events[event] = null;
            } else {
                this.events[event] = this.events[event].filter(
                    (it) => it !== cb
                );
            }
            return this;
        }
    }

数组扁平化

Array.prototype.flat=function(){
				let result=[];
				for(let item of this){
					if(Array.isArray(item)){
						result=result.concat(item.flat())
					}else result.push(item);
				}
				return result;
			}
Array.prototype.flat=function(){
				let result=this;
				while (result.some(item=>Array.isArray(item))){
					result=[].concat(...result)
				}
				return result
			}		

Promise实现间隔打印

async function timer() {
        for (let i = 1; i < 4; i++) {
            console.log('ww', await _promise(i))
        }
    }
    function _promise(interval) {
        return new Promise((resolve, reject) => {
            setTimeout(() => { resolve(interval) }, 1000)
        })
    }
timer()
async function timer(n) {//传参版
        for (let i = 1; i < n; i++) {
            console.log('ww', await _promise(i, i * 1000))
        }
    }
    function _promise(num, interval) {
        return new Promise((resolve, reject) => {
            setTimeout(() => { resolve(num) }, interval)
        })
    }
timer(4)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值