当前位置: 首页 > news >正文

JavaScript手写题

一、防抖

function debounce(fn, delay=200) {let timeout = null;  // 定时器控制return function(...args) {if (timeout) {  // 定时器存在,表示某个动作之前触发过了clearTimeout(timeout);  // 清除定时器timeout = null;} else {// 对第一次输入立即执行fn.apply(this, args);}timeout = setTimeout(()=>{fn.apply(this, args);  // this指向function}, delay)}
}

二、节流

function throttle(fn, time) {let pre = 0;let timeout = null;return function (...args) {const now = Date.now();// 如果时间超过了时间间隔,立即执行函数if (now - pre > time) {pre = now;fn.apply(this, args);} else {// 如果时间没有超过时间间隔,取消后续的定时器任务if (timeout) {clearTimeout(timeout);timeout = null;}// 最后一次事件的触发timeout = setTimeout(() => {pre = now;fn.apply(this, args);}, time);}};
}

三、instanceOf

判断数据类型的方法:typeof、 instanceOf、 Object.prototype.tostring.call()

作用:运算符,可以判断一个对象的类型

原理:原型和原型链

function myInstanceOf(obj, constructor) {
// obj=实例对象,constructor=实例对象的构造函数let proto = obj.__proto__;while (true) {  // 遍历原型链if (proto === null) {  return false;}if (proto === constructor.prototype) {return true;}proto = proto.__proto__;}
}

四、call

思路:1、判断是否是函数调用,若非函数调用抛异常;2、通过新对象(context)来调用函数:给context创建一个fn设置为需要调用的函数,结束调用完之后删除fn

// 初级写法
Function.prototype.myCall = function (ctx, ...args) {// ctx=上下文// 将方法挂载到传入的上下文ctxctx.fn = this;// 将挂载以后的方法调用ctx.fn(...args);// 将添加的属性删除delete ctx.fn;
};// 完整写法
Function.prototype.myCall = function (obj) {// obj是this的指向,后面还可以有多个参数即函数本身的参数var obj = obj || window;obj.p = this; // 为形参定义一个方法p,并把this给这个函数var newArguments = []; // 函数参数本身是没有this的,需要把所有参数另外保存起来,并且不保留第一个this参数,使参数回归到正常的序号// 获取函数的参数需要用到arguments对象for (var i = 1; i < arguments.length; i++) {newArguments.push("arguments[" + i + "]"); // 用字符串拼接参数}var result = eval("obj.p(" + newArguments + ")"); // 用eval可以执行到引号里的参数delete obj.p; // 要将p方法删除掉,因为不能改写对象return result;
};

 五、apply

思路:思路:1、判断是否是函数调用,若非函数调用抛异常;2、通过新对象(context)来调用函数:给context创建一个fn设置为需要调用的函数,结束调用完之后删除fn

Function.prototype.myApply = function (obj, arr) {var obj = obj || window;obj.p = this;if (!arr) {// 如果执行myApply的时候没有输入参数arr,那么就直接执行方法p,不用考虑参数问题obj.p();} else {// 有传入参数arr,执行就跟call一样了var newArguments = [];for (var i = 1; i < arguments.length; i++) {newArguments.push("arguments[" + i + "]");}var result = eval("obj.p(" + newArguments + ")");}delete obj.p;return result;
};

六、bind 

思路:1、判断是否是函数调用,若非函数调用抛异常;2、返回函数:判断函数的调用方式,是否是被new出来的,new出来的话返回空对象,但是实例的__proto__指向_thisprototype;3、函数柯里化Array.prototype.slice.call()

Function.prototype.myBind = function (obj) {if (typeof this !== "function") {throw new TypeError("wrong");}var that = this;var arr = Array.prototype.slice.call(arguments, 1);var o = function () {};newf = function () {var arr2 = Array.prototype.slice.call(arguments);var arr = arr.concat(arr2);if (this instanceof o) {that.apply(this, arrSum);} else {that.apply(obj, arrSum);}};o.prototype = that.prototype;newf.prototype = new o();return newf;
};

七、对象深拷贝

    // 简易版  function deepClone(o) {let obj = {}for (var i in o) {// if(o.hasOwnProperty(i)){if (typeof o[i] === "object") {obj[i] = deepClone(o[i])} else {obj[i] = o[i]}// }}return obj}

八、手写new

new发生的事:

  • 创建一个新对象
  • 使新对象的__proto__指向原函数的prototype
  • 改变this指向(指向新的obj)并执行该函数,执行结果保存起来作为result
  • 判断执行函数的结果是不是null或Undefined,如果是则返回之前的新对象,如果不是则返回result
    // 手写一个newfunction myNew(fn, ...args) {// 创建一个空对象let obj = {}// 使空对象的隐式原型指向原函数的显式原型obj.__proto__ = fn.prototype// this指向objlet result = fn.apply(obj, args)// 返回return result instanceof Object ? result : obj}

手写一个发布订阅

手写数组转树

function transTree(data) {let result = []let map = {}if (!Array.isArray(data)) {//验证data是不是数组类型return []}data.forEach(item => {//建立每个数组元素id和该对象的关系map[item.id] = item //这里可以理解为浅拷贝,共享引用})data.forEach(item => {let parent = map[item.parentId] //找到data中每一项item的爸爸if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面(parent.children || (parent.children = [])).push(item)} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中result.push(item) //item是对象的引用}})return result //数组里的对象和data是共享的
}
console.log(JSON.stringify(transTree(data)))

实现一个 Scheduler 类,完成对Promise的并发处理,最多同时执行2个任务

http://www.lryc.cn/news/23157.html

相关文章:

  • 为什么图标的宽度总是8的倍数?
  • 常用的xpath
  • 【035】基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文
  • 【Spark分布式内存计算框架——Spark Streaming】7. Kafka集成方式
  • 如何引入elementUI
  • vue3+rust个人博客建站日记4-Vditor搞定MarkDown
  • KDZD-JC软化击穿试验仪
  • 【数据结构】单链表的C语言实现--万字详解介绍
  • 电子科技大学软件工程期末复习笔记(七):测试策略
  • 逆向-还原代码之除法 (Interl 64)
  • Python WebDriver自动化测试
  • 2023年微信小程序获取手机号授权登录注册详细教程,包含服务端教程
  • YOLOv8模型学习笔记
  • Java SE知识点1
  • 华为OD机试模拟题 用 C++ 实现 - 端口合并(2023.Q1)
  • C++ Primer Plus 第6版 读书笔记(3) 第3章 处理数据
  • ArrayList源码解读
  • python实战应用讲解-【语法高级篇】时间与日期(附python示例代码)
  • D. Moscow Gorillas(双指针 + 区间分析)
  • 华为OD机试题,用 Java 解【相同数字的积木游戏 1】问题
  • Python实现GWO智能灰狼优化算法优化BP神经网络分类模型(BP神经网络分类算法)项目实战
  • 无线蓝牙耳机哪个牌子好?2023质量好的无线蓝牙耳机推荐
  • Qt之QTableView自定义排序/过滤(QSortFilterProxyModel实现,含源码+注释)
  • 电商(强一致性系统)的场景设计
  • 算法与数据结构(一)
  • 【Python】元组如何创建?
  • qt操作文件以及字符串转换
  • 数组中只出现一次的两个数字(异或法思路)
  • python支持的操作系统有哪些
  • S3C2440开发环境搭建