2020面试系列-js手写代码
函数节流,防抖
节流
//函数节流 function throttle(handler, wait) { let preTime = 0; return function () { let now = Date.now(); if (now - preTime >= wait) { handler(); preTime = now; } }; } var t = throttle(function () { console.log(11); }, 1000); var oBtn1 = document.getElementById('btn1'); oBtn1.onclick = function(){ t(); }
防抖
//函数防抖 function debounce(handler, wait) { let timer = null; return function () { if(timer){ clearTimeout(timer); } timer = setTimeout( handler,1000 ) }; } var t = debounce(function () { console.log(11); }, 1000); document.onmousemove = function(){ t(); }
实现call,apply,bind
call
Function.prototype.mcall = function (context) { //传参第一个参数转对象,不传参直接去window let ctx = Object(context) || window; let fn = "fn", res = ""; while (ctx.hasOwnProperty(fn)) { // 循环判断并重新赋值 ,防止上下文对象上本来就有同名方法 fn = fn + Math.random(); } //把绑定函数作为上下文对象的方法 ctx[fn] = this; //作为对象方法调用绑定函数,并把参数传入 if (arguments.length > 1) { res = ctx[fn](...[...arguments].slice(1)); } else { res = ctx[fn](); } delete ctx[fn]; //返回函数返回值 return res; };
apply
Function.prototype.mapply = function (context, arr) { let ctx = Object(context) || window; let fn = "fn", res = ""; while (ctx.hasOwnProperty(fn)) { fn = fn + Math.random(); } ctx[fn] = this; if (arr) { res = ctx[fn](...arr); } else { res = ctx[fn](); } delete ctx[fn]; return res; };
bind
Function.prototype.mbind = function (context) { context = context ? Object(context) : window; //保存argumets var mArguments = arguments, self = this; if (arguments.length > 1) { return function () { //借用apply self.apply(context, [...mArguments].slice(1)); }; } else { return function () { self.apply(context); }; } };
实现数组实例方法
push
//push 从后面新增 Array.prototype.push = functon(){ for(var i =0;i<arguments.length;i++){ this[this.length-1] = arguments[i]; } return this.length; }
POP
//pop 从后面删除一个 Array.prototype.pop = function(){ var item = this[this.length-1]; if(this.length>0){ this.length = this.length - 1; } return item; }
shift
//shift 从前面删除一项 Array.prototype.shift = function(){ var item = this[0]; for(var i = 1;i<this.length;i++){ this[i-1] = this[i]; } this.length = this.length-1; return item; }
unshrft
//unshift 从前面增加n项 Array.ptototype.unshift = function(){ var l = arguments.length; //把原数组向后移动 for(var i= 0;i<this.length;i++){ this[i+l] = this[i]; } //赋值 for(var j = 0;j<arguments.length;j++{ this[j] = arguments[j]; } return this.length; }
filter
//fitler Array.prototype.fitler = function(handler){ var newArr = []; for(var i = 0;i<this.length;i++){ if(handler(this[i],i,this)){ newArr[newArr.length] = this[i]; } } return newArr; }
数组去重
//普通去重 function unique(arr) { var newArr = []; arr.forEach((item, index, arr) => { if (newArr[newArr.length] != item) { newArr[newArr.length] = item; } }); return newArr; } //indexOf去重 function unique(arr) { var newArr = []; arr.forEach((item, inddex, arr) => { if (newArr.indexOf(item) == -1) { newArr.length = item; } }); return newArr; } //利用对象属性不能相同 function unique(arr) { var obj = {}, newArr = []; arr.forEach((item, index, arr) => { if (!obj[item]) { obj[arr[i]] = 1; newArr.push(item); } }); return newArr; } //es6去重 function unique(arr) { return Array.from(new Set(arr)); } //扩展运算符 function unique(arr) { return [...new Set(arr)]; }
排序算法
//冒泡排序 //相邻两元素之间两两比较,比较出大值进行赋值互换,再依次与相邻的元素比较,层层递进 //假设升序排序 function bubbleSort(arr) { var l = arr.length; for (var i = 0; i < l; i++) { //比较轮数 for (var j = 0; j < l - i - 1; j++) { //每一轮确定一个最大值,放最右边 var temp = arr[j]; if (arr[j] > arr[j + 1]) { arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } return arr; } //选择排序 //先假设一个值为最大或者最小值 function selectSort(arr){ for(var i = 0;i<arr.length;i++){ var minIndex = i; for(var j = i;j<arr.length;j++){ if(arr[j]>arr[j+1]){ minIndex=j+1; var temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } //快速排序 //找基准,遍历数组,小于基准的放在left,大于基准的放在right,最后递归 function quickSAort(arr){ if(arr.length<=1>)return arr; var temp = arr[0],left=[],right =[]; for(var i = 1;i<arr.length;i++){ if(arr[i]<temp){ left.push(arr[i]) }else{ right.push(arr[i]) } } return [].concat(quickSort(left),temp,quickSort(right)); }
深拷贝
//深拷贝黑科技 JSON.parse(JSON.stringify(obj)); //存在问题:无法拷贝原型上的属性和方法 //递归实现 function deepCopy(obj) { var newobj = obj.constructor === Array ? [] : {}; if (typeof obj !== "object") { return obj; } else { for (var i in obj) { //判断对象的这条属性是否为对象,//若是对象进行嵌套调用,否则直接赋值 newobj[i] = typeof obj[i] === "object" ? deepCopy(obj[i]) : obj[i]; } } return newobj; //返回深度克隆后的对象 }
拉平多维数组
//简便方法 function flatArr(arr) { return arr.join(",").split(","); } //递归实现 function flat(arr) { let arr1 = []; arr.forEach((val) => { if (val instanceof Array) { arr1 = arr1.concat(flat(val)); } else { arr1.push(val); } }); return arr1; }
setTimeout模拟定时器
function mInterval() { //要执行的逻辑 console.log(1); //每次逻辑执行完,才会向队列添加事件 setTimeout(mInterval, 1000); } mInterval();
手写promise
promise
//判断变量是否是函数 function isFunction(variable) { return typeof variable === "function"; } //promise构造函数 function MyPromise(handle) { if (!isFunction(handle)) { throw new Error("必须传入一个函数"); } this.status = "pending"; //状态,默认等待状态 this.value = ""; //值 this.onResolveCallbacks = []; //存放成功回调的数组 this.onRejectCallbacks = []; //存放失败回调的数组 var that = this; try { handle(resolve, reject); } catch (err) { reject(err); //有报错,状态直接变为rejected } function resolve(val) { if (that.status == "pending") { that.status = "resolved"; that.value = val; that.onResolveCallbacks.forEach((fn) => { fn(); }); } } function reject(err) { if (that.status == "pending") { that.status = "rejected"; that.value = err; that.onRejectCallbacks.forEach((fn) => { fn(); }); } } }
promise.then
MyPromise.prototype.then = function (sucFun, faildFun) { //可选参数 //如果没有传,只负责把值往后传 sucFun = isFunction(sucFun) ? sucFun : (value) => value; faildFun = isFunction(faildFun) ? faildFun : (value) => value; var that = this; //先改变了状态 if (this.status === "resolved") { sucFun(this.value); } if (this.status === "rejected") { faildFun(this.value); } //先指定了回调函数,状态还没改变 if (this.status === "pending") { //存住回调函数,在异步操作完成时调用 this.onResolveCallbacks.push(() => { sucFun(this.value); }); this.onRejectCallbacks.push(() => { faildFun(this.value); }); } return this; };
promise.all
Promise.allFun = (arr) => { return new Promise((resolve, reject) => { var resolveArr = [], rejectArr = []; for (var i = 0; i < arr.length; i++) { if (!(arr[i] instanceof Promise)) { arr[i] = Promise.resolve(arr[i]); } arr[i] .then((res) => { resolveArr.push(res); if (resolveArr.length == arr.length) { resolve(resolveArr); } }) .catch((err) => { rejectArr.push(err); reject(rejectArr); }); } }); };
promise.race
myPromise.race = function (arr) { return new Promise(function (resolve, reject) { for (var i in arr) { arr[i].then(resolve, reject); } }); };
实现一个并发请求控制方法
async function sendRequest(list, max = 4) { return new Promise((resolve, reject) => { let index = 0; // let count = 0; //上传成功个数 const start = () => { while (max > 0 && index < list.length) { //剩余位置-1 max--; let chunk = list[index]; index++; request().then((res) => { max++; //释放暂用位置 count++; //上传成功数量+1 if (count == list.length) { resolve("完成了"); } else { start(); } }); } }; start(); }); } function request() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(1); resolve(1); }, 2000); }); } var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]; sendRequest(list, 4) .then((res) => { console.log(res); }) .catch((err) => { console.log("上传失败了"); });
实现new
function new() { //创建空对象 let obj = {}; //获取构造函数 let Constructor = Array.prototype.shift.call(arguments); //绑定原型关系 obj.__proto__ = Constructor.prototype; // 执行构造函数,即绑定 this,并且为这个新对象添加属性 Constructor.apply(newObj, arguments); //返回新对象 return obj; }
Object.create
新创建一个对象,使用传入对象作为新对象的原型对象
Object.create = function (obj) { //创建空构造函数F function F() {} //F的prottotype指向obj F.prtotype = obj; //返回F实例 return new F(); };
输出数据类型
function getType(param){ if(param){ return Object.prototype.toString.call(param).split(' ')[1].split(']')[0]; }else{<br> console.log('参数不能为空')<br> } }
斐波那契数列
//给定位置,输出对应的值 function fib(n){ if(n==1||n==2){ return 1; } return fib(n-1)+fib(n-2) }