5个常见的前端手写功能:New、call apply bind、防抖和节流、instanceof、ajax

实现New

  • 首先创建一个新的空对象
  • 设置原型,将对象的原型设置为函数的prototype对象
  • 让函数的this指向这个对象,执行构造函数的代码
  • 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象
function myNew(constructor, ...args) {// 如果不是一个函数,就报错if (typeof constructor !== "function") {throw "myNew function the first param must be a function";}// 基于原型链 创建一个新对象,继承构造函数constructor的原型对象上的属性let newObj = Object.create(constructor.prototype);// 将newObj作为this,执行 constructor ,传入参数let res = constructor.apply(newObj, args);// 判断函数的执行结果是否是对象,typeof null 也是'object'所以要排除nulllet isObject = typeof res === "newObject" && res !== null;// 判断函数的执行结果是否是函数let isFunction = typeof res === "function";// 如果函数的执行结果是一个对象或函数, 则返回执行的结果, 否则, 返回新创建的对象return isObject || isFunction ? res : newObj;
}// 用法
function Person(name, age) {this.name = name;this.age = age;// 如果构造函数内部,return 一个引用类型的对象,则整个构造函数失效,而是返回这个引用类型的对象
}
Person.prototype.say = function() {console.log(this.age);
};
let p1 = myNew(Person, "poety", 18);
console.log(p1.name);	//poety
console.log(p1);	//Person {name: 'poety', age: 18}
p1.say();	//18

测试结果:

image.png

call、apply、bind

实现call

思路:接受传入的context上下文,如果不传默认为window,将被调用的方法设置为上下文的属性,使用上下文对象来调用这个方法,删除新增属性,返回结果。

//写在函数的原型上
Function.prototype.myCall = function (context) {// 如果要调用的方法不是一个函数,则报错if (typeof this !== "function") {throw new Error("Type error");}// 判断 context 是否传入,如果没有传就设置为 windowcontext = context || window;// 获取参数,[...arguments]把类数组转为数组let args = [...arguments].slice(1);let result = null;// 将被调用的方法设置为context的属性,this即为要调用的方法context.fn = this;// 执行要被调用的方法result = context.fn(...args);// 删除手动增加的属性方法delete context.fn;// 将执行结果返回return result;
};//测试
function f(a, b) {console.log(a + b);console.log(this.name);
}
let obj = {name: 1,
};
f.myCall(obj, 1, 2); // 3,1

测试结果:

image.png

实现apply

思路:除了传参方式是数组,其它与call没区别

Function.prototype.myApply = function (context) {if (typeof this !== "function") {throw new Error("Type error");}let result = null;context = context || window;// 与上面代码相比,我们使用 Symbol 来保证属性唯一,也就是保证不会重写用户自己原来定义在 context 中的同名属性const fnSymbol = Symbol();context[fnSymbol] = this;// 执行要被调用的方法,处理参数和 call 有区别,判断是否传了参数数组if (arguments[1]) {//传了参数数组result = context[fnSymbol](...arguments[1]);} else {//没传参数数组result = context[fnSymbol]();}delete context[fnSymbol];return result;
};//测试
function f(a, b) {console.log(a, b);console.log(this.name);
}
let obj = {name: "张三",
};
f.myApply(obj, [1, 2]); //1 2,张三

测试结果:

image.png

实现bind

思路:bind返回的是一个函数,需要判断函数作为构造函数的情况,当作为构造函数时,this指向实例,不会被任何方式改变this,所以要忽略传入的context上下文。

bind可以分开传递参数,所以需要将参数拼接。如果绑定的是构造函数,还需要继承构造函数原型上的属性和方法,保证不丢失。

Function.prototype.myBind = function (context) {// 判断调用对象是否为函数if (typeof this !== "function") {throw new Error("Type error");}// 获取参数const args = [...arguments].slice(1);const fn = this; // 保存this的值,代表调用bind的函数//返回一个函数,此函数可以被作为构造函数调用,也可以作为普通函数调用const Fn = function () {// 根据调用方式,传入不同绑定值// 当作为构造函数时,this 指向实例,不会被任何方式改变 this,要忽略传入的context上下文return fn.apply(this instanceof Fn ? this : context,// bind可以分开传递参数(如f.bind(obj, 1)(2)),所以需要将参数拼接,这里使用apply,参数拼接成一个数组args.concat(...arguments)//当前的这个 arguments 是指 Fn 的参数,也可以用剩余参数的方式);};//对于构造函数,要保证原函数的原型对象上的属性不能丢失Fn.prototype = Object.create(fn.prototype);return Fn;
};// 1.先测试作为构造函数调用
function Person(name, age) {console.log(name);console.log(age);console.log(this); //构造函数this指向实例对象
}
// 构造函数原型的方法
Person.prototype.say = function () {console.log("say");
};
var obj = {name: "cc",age: 18,
};
var bindFun = Person.myBind(obj, "cxx");
var a = new bindFun(10);
// cxx
// 10
// Person {}
a.say(); // say// 2.再测试作为普通函数调用
function normalFun(name, age) {console.log(name);console.log(age);console.log(this); // 普通函数this指向绑定bind的第一个参数 也就是例子中的obj
}
var obj = {name: "aa",age: 18,
};
var bindNormalFun = normalFun.myBind(obj, "cc");
bindNormalFun(12);
// cc
// 12
// { name: 'aa', age: 18 }

测试结果:

image.png

防抖和节流

防抖

防抖是指在事件被触发n秒后在执行回调,如果在这n秒内时间又被触发,则重新计时。

可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。

//fn是需要防抖的函数,delay是等待时间
function debounce(fn, delay = 500) {let timer = null;// 这里返回的函数是每次用户实际调用的防抖函数return function(...args) {	//...args是es6的剩余参数语法,将多余的参数放入数组,用来代替arguments对象// 如果已经设定过定时器了就清空上一次的定时器if(timer) {clearTimeout(timer);	}// 开始一个新的定时器,延迟执行用户传入的方法;注:定时器的返回值是一个数值,作为定时器的编号,可以传入clearTimeout来取消定时器timer = setTimeout(() => {  //这里必须是箭头函数,不然this指向window,要让this就指向fn的调用者fn.apply(this, args);   }, delay)	}
}

节流

节流就是一定时间内执行一次事件,即使重复触发,也只有一次生效。

可以使用在监听滚动scroll事件上,通过事件节流来降低事件调用的频率。

定时器版本
throttle(fn, delay = 500) {let timer = null;return function(...args) {// 当前有任务了,直接返回if(timer) {return;}timer = setTimeout(() => {fn.apply(this, args);//执行完后,需重置定时器,不然timer一直有值,无法开启下一个定时器timer = null;	}, delay)}
}
时间戳版本
// 节流
function throttle(fn, delay = 500) {let prev = Date.now();// 上一次执行该函数的时间return function(...args) {let now = Date.now();//返回从UTC到当前时间的毫秒数// 如果差值大于等于设置的等待时间就执行函数if (now - prev >= delay) {fn.apply(this, args);prev = Date.now();}};
}

实现instanceof

instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

myInstanceof(instance, constructor) {//如果不是对象,或者是null,直接返回falseif (typeof instance !== "object" || instance === null) {return false;}// 获取对象的原型let proto = Object.getPrototypeOf(instance);// 获取构造函数的 prototype 对象let prototype = constructor.prototype;// 判断构造函数的 prototype对象是否在对象的原型链上while (true) {// 到达原型链终点null,说明没找到if (!proto) {return false;}if (proto === prototype) {return true;}// 如果没有找到,就继续从其原型上找proto = Object.getPrototypeOf(proto);}
}//测试
let Fn = function () { }
let p1 = new Fn()
console.log(myInstanceof(p1, Fn));//true
console.log(myInstanceof([], Fn));//false
console.log(myInstanceof([], Array)) // true
console.log(myInstanceof(function(){}, Function)) // true

测试结果:

image.png

实现Ajax

创建一个XMLHttpRequest对象
在这个对象上使用open方法创建一个HTTP请求(参数为请求方法、请求地址、是否异步和用户的认证信息)
通过send方法来向服务器发起请求(post请求可以入参作为发送的数据体)
监听请求成功后的状态变化:根据状态码进行相应的出来。onreadystatechange设置监听函数,当对象的readyState变为4的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是200则为成功,404或500为失败。

function ajax(url) {//1.创建XMLHttpRequest对象const xhr = new XMLHttpRequest();//2.使用open方法创建一个GET请求xhr.open('GET',url);//xhr.open('GET',url,true);//true代表异步,已完成事务的通知可供事件监听器使用;如果为false,send() 方法直到收到答复前不会返回//3.发送请求xhr.send(); //4.监听请求成功后的状态变化(readyState改变时触发):根据状态码(0~5)进行相应的处理xhr.onreadystatechange = function () {//readyState为4代表服务器返回的数据接收完成if (xhr.readyState == 4) { //请求的状态为200或304代表成功if(xhr.status == 200 || xhr.status == 304) {//this.response代表返回的数据handle(this.response);} else {//this.statusText代表返回的文本信息console.error(this.statusText);}}};
}

使用Promise封装Ajax:

function ajax(url) {return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest()xhr.open('get', url)xhr.send()  xhr.onreadystatechange = () => {if (xhr.readyState == 4) {if (xhr.status == 200 || xhr.status == 304) {resolve(this.response)} else {reject(new Error(this.statusText));}}}})
}
//使用
let url = '/data.json'
ajax(url).then(res => console.log(res)).catch(reason => console.log(reason))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/822802.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站创建的流程是什么

网站的创建过程包括几个主要的步骤,其中涉及到一系列的决策和实践操作。下面我将详细介绍网站创建的流程,帮助读者了解如何创建一个成功的网站。 第一步:确定网站目标和功能 在创建网站之前,你需要明确自己网站的目标和功能。是用…

【剪映专业版】07素材导入与界面认识

视频课程:B站有知公开课【剪映电脑版教程】 点击开始创作后生成新的草稿 单击更改草稿名称 导入数量没有限制 根据选中素材创建文件夹:选中素材,单击右键 智能镜头分割:选中素材,单击右键,用于不同场景…

【Git】安装 Git

文章目录 1. CentOS 下安装2. Ubuntu 下安装 Git 是开放源代码的代码托管工具,最早是在 Linux 下开发的。开始也只能应用于 Linux 平台,后面慢慢的被移植到 Windows 下。现在,Git 可以在 Linux、Unix、Mac 和 Windows 这几大平台上正常运行了…

力扣2923、2924.找到冠军I、II---(简单题、中等题、Java、拓扑排序)

目录 一、找到冠军I 思路描述: 代码: 二、找到冠军II 思路描述: 代码: 一、找到冠军I 一场比赛中共有 n 支队伍,按从 0 到 n - 1 编号。 给你一个下标从 0 开始、大小为 n * n 的二维布尔矩阵 grid 。对于满足…

终于看到一个不在 Backbone上研究 ReNet的了!直接优化小目标检测性能,不卷ImageNet-1K数据集!

终于看到一个不在 Backbone上研究 ResNet的了!直接优化小目标检测性能,不卷ImageNet-1K数据集! 前言 传统的基于深度学习的目标检测网络在数据预处理阶段常通过调整图像大小以达到特征图中的统一尺寸和尺度。调整大小的目的是为了便于模型传播…

吴恩达llama课程笔记:第六课code llama编程

羊驼Llama是当前最流行的开源大模型,其卓越的性能和广泛的应用领域使其成为业界瞩目的焦点。Meta公司基于llama2发布了code llama,用于代码生成,补全等,Code Llama拥有7B、13B和34B三种版本。 吴恩达教授推出了全新的Llama课程&a…

OceanBase 4.3 列存存储格式和列存索引存储格式

以 t1 表和索引为例子,下面两张图说明了存储层如何存储数据。 create table t1 (id1 int, id2 int, name varchar(10), salary int, primary key(id1, id2)) with column group (each column);create index idx (name) storing(salary) with column group(each co…

基于GIS、python机器学习技术的地质灾害风险评价与信息化建库应用

结合项目实践案例和科研论文成果进行讲解。入门篇,ArcGIS软件的快速入门与GIS数据源的获取与理解;方法篇,致灾因子提取方法、灾害危险性因子分析指标体系的建立方法和灾害危险性评价模型构建方法;拓展篇,GIS在灾害重建…

vue elmentui 可编辑table 实现

废话不多说上图: 1.可编辑input 2.可编辑下来框 3.点击chechbox 4.可编辑radio 其实后面两种可以直接显示值 需要修改直接改就行 保持风格统一所以就做了点击之后出现修改功能 上代码,不要哔哔 哈哈 粗暴 真得是曲不离口 拳不离手, 几天…

【力扣】45. 跳跃游戏 II

Problem: 45. 跳跃游戏 II 文章目录 问题思路复杂度Code 问题 思路 核心思路,例如nums[i]5,那么最远能跳五步; //那么在这接下来1-5范围内,哪个能让我跳的最远,这个最远指的是 -------------------------------------…

代码随想录图论

1. 所有可能的路径 class Solution:def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:def dfs(graph, result, path, root): #result 返回结果, path记录路径, root记录遍历到了第几个节点if root len(graph) - 1: #如果遍历到最后…

如何让多人同时扫码看图?图片转二维码的制作方法

现在经常会发现需要通过扫描二维码的方式来获取图片信息,这种方式可以让很多人能够同时获取图片信息,有利于提升传播的效率和用户体验。那么如何使用图片二维码生成器来在线制作二维码呢?其实步骤很简单,只需要在电脑3步就可以轻松…

Solana 上创建自己的 SLPToken:简明指南

Solana 定义 Solana 是由 Solana Labs 创建的区块链平台,旨在提供高吞吐量和低延迟的去中心化应用(DApps)开发环境。它采用一系列创新技术,如 PoH(Proof of History)共识机制和 Tower BFT(BFT …

大模型预测结果导入到Doccano,人工修正预测不准的数据

背景 使用大语言模型做实体识别的实验时,发现大模型关于实体的边界预测一直不准。 主要原因在于当时找了很多同学标注数据,由于不同组同学关于实体的边界没有统一,故导致数据集中实体边界也没统一。 (找太多人标,会有…

HalconLen2-示例程序分析

dev_update_window(off) dev_open_window(0, 0, 512, 512, black, WindowHandle) //打开窗口 stop() //程序中断 *dev_close_window() //关闭窗口 read_image (Bond, die/die_03) //读取图片 dev_display(Bond) //显示图片 set_display_font(WindowHandle, 16, mono, true, fal…

#陶晶驰串口屏使用

1.陶晶驰串口屏输入要连接的wifi信息实现 (1)选择文本控件 (2)给文本控件配置输入键盘,id代表用户名,password代表wifi密码(注意wifi的频段需要为2.4GHz) (3&#xff0…

【结构型模式】适配器模式

一、适配器模式概述 适配器模式的定义-意图:将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。(对象结构模式->对象适配器/类结构模式->类适配器) 适配器模式包含三个角色:目标(Target)角色、适配者(Adapt…

打破常规,重新定义PMP备考之路

今天我想和大家聊聊一个我们都不陌生的话题——PMP备考。你是不是也在备考的苦海中挣扎,或是听说过各种“速成”的神话?🤔 最近读到一篇文章(来着圣略PMP培训讲师老杨),让我对PMP备考有了新的认识。原来&a…

常见的地图绘制方法,这个包全包了~~

在上一篇介绍完Bokeh精美可视化作品之后,有小伙伴咨询我能不能稍系统的介绍下如何在地图上添加如柱形图等其他元素的付方法? 这就让我想到一个优秀的地图绘制可视化包-R-cartography,虽然之前也有简单介绍过,本期就具体分享下该包…

Python QP 求解器

系列文章目录 前言 该 Python 库提供一站式 solve_qp 函数,用于求解凸二次规划: 向量不等式逐个坐标应用。函数返回后端 QP 求解器找到的初等解 ,如果求解失败/问题不可行,则返回 None。所有求解器都要求问题是凸的,这…