实现 bind call apply 方法

this 是什么?

this是指包含它的函数作为方法被调用时所属的对象。这句话理解起来感觉还是很拗口的,但是如果你把它拆分开来变成这三句话后就好理解一点了。

  1. 包含它的函数
  2. 作为方法被调用时
  3. 所属的对象

改变 this 指向的函数

bindcallapply

  • 共同点
  • 目标函数被调用时,改变 this 的指向为指定的值
  • 三个方法都是函数的方法,挂载在 Funtion.prototype 上
  • 不同点
  • 目标函数调用 call 和 apply 后会直接被执行。
  • 目标函数调用 bind 后,不会立即执行,而是返回一个新的函数,调用新函数才会执行目标函数。

回顾 call apply bind 的使用

var btn = document.querySelector(".btn");
var name = "windows";
var obj = {name: "Linux",num: 0,updateNum: function(){this.num++;console.log(this.num) // 1,2,3,4}
}function fn(){console.log(this.name);
};btn.addEventListener("click", obj.updateNum.bind(obj))fn();           // windows
fn.call(obj);   // Linux
fn.apply(obj)
fn(null);       // windows

回顾call与apply的参数使用

let name = "wanna";let age = 20;let obj = {name: "hurt",objAge: this.age,objFn: function(a, b){console.log(this.name + "年龄" + this.age, "性别:" + a + "兴趣爱好" + b);}};let user = {name: "hico",age: 18};obj.objFn.call(user, "男", "篮球");             // hico年龄18 性别:男 兴趣爱好篮球obj.objFn.apply(user, ["男","足球"]);           // hico年龄18 性别:男 兴趣爱好足球obj.objFn.bind(user, "男", "排球")();           // hico年龄18 性别:男 兴趣爱好排球obj.objFn.bind(user, ["男", "乒乓球"])(null);   // hico年龄18 性别:男 乒乓球 兴趣爱好null

不同的是 bind 必须调用它才会执行

实现 call

思路

  1. call是可以被所有方法调用的,所以毫无疑问的定义在 Function的原型上
  2. 绑定函数被调用时只传入第二个参数及之后的参数
  3. 如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。
Function.prototype.MyCall = function(){const ctx = arguments[0] || window;// 被调用的方法定义在 ctx.fn 绑定 thisctx.fn = this;// 获取实参const arg = [...arguments].slice(1); // 以对象调用的形式调用 fn ,此时的 this 指向 ctx,也就是传入的需要绑定 this 指向const res = arguments.length > 1 ? ctx.fn(...arg) : ctx.fn();// 删除方法,防止对传入的对象造成污染delete ctx.fn;return res;
};

实现 apply

apply实现的思路与call基本相同,我们只需要对参数进行不同处理即可

Function.prototype.MyApply = function(){const ctx = arguments[0] || window;// 被调用的方法定义在 ctx.fn 绑定 thisctx.fn = this;// 以对象调用的形式调用 fn ,此时的 this 指向 ctx,也就是传入的需要绑定 this 指向const res = arguments[1] ? ctx.fn(...arguments[1]) : ctx.fn();// 删除方法,防止对传入的对象造成污染delete ctx.fn;return res;
};

实现 bind

思路

  1. call是可以被所有方法调用的,所以毫无疑问的定义在 Function的原型上
  2. 绑定函数被调用时只传入第二个参数及之后的参数
  3. 如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。
  4. 调用执行,不调用绑定 this 指向
Function.prototype.MYBind = function(context){// 深拷贝 防止污染const ctx = JSON.parse(JSON.stringify(context)) || window;// 被调用的方法定义在 ctx.fn 绑定 thisctx.fn = this;// 获取实参const args = [...arguments].slice(1);// 返回一个绑定函数,等待调用return function () {// 合并实参const allArgs = args.concat([...arguments]);// 以对象调用的形式调用 fn ,此时的 this 指向 ctx,也就是传入的需要绑定 this 指向return allArgs.length ? ctx.fn(...allArgs) : ctx.fn();}};

什么是节流?怎么实现节流函数

我们举例一个简单的 demo ,假设我们在页面用到了滚轮事件

window.addEventListener("scroll",()=>console.log("1"))

我现在打算从页面滚动一次

于是我们会发现

轻轻的一滚动执行了 16 次打印,这个函数的默认执行频率太高了,但是实际上我们并不需要如果高频的执行,毕竟浏览器的性能是有限的,不应该在这里浪费,接下来我们来看看如何优化这种场景。

如果在限定时间段内,不断触发滚动事件。好比我们假设上了一趟公共厕所,发现水龙头的水大量的喷出,于是我们下意识的拧紧关闭水龙头,却拧不紧,即使拧不紧也要节约一下用水,让水龙头的水量变小,节约用水,人人有责嘛,好了,废话不多说,直接上代码

let getLog = () => console.log("滚动");
window.addEventListener("scroll", throttle(getLog, 300));
// 节流
function throttle(fn, interval=300){let timer = 0;return function(...arg) {let _this = this;if(timer)return;fn.call(_this, ...arg);timer = setTimeout(function(){timer = 0;},interval);};
};

也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却)

开始从顶部滚动,这下狠一点,滚到底部看看效果。

于是我们发现

滚到底部居然只打印了11次,坑比我们上面的滚动一次打印 15 次,大大节省了性能的消耗。

什么是防抖?怎么实现防抖函数

举例一个简单的 demo,现在我打算窗口大小发生改变时打印日志

let getLog = () => console.log("防抖");
window.addEventListener("scroll",getLog)

我打算从左边拉动到右边

小小改变窗口大小就发生了这样的事

其实实际上我们并不需要如果高频的执行,毕竟浏览器的性能是有限的,不应该在这里浪费,我们来整理一下思路。

在第一次触发事件后,不应该立即执行函数,而是给出一个期限值比如 500ms 。

  1. 如果 500ms 内没有再次触发滚动,那么就执行函数。
  2. 如果 500ms 内再次触发滚动事件,那么当前的计时取消,重新开始计时。

效果:短时间内大量触发同一事件,只会执行最后一次

实现:既然前面都提到了计时了,那实现的关键就在于 setTimeOut 这个函数了。

let getLog = () => console.log("防抖");window.addEventListener("resize", debounce(getLog));// fn 要防抖的函数 interval 间隔时间
function debounce(fn, interval=500){let timer = 0;return function(...arg) {let _this = this;clearTimeout(timer);timer = setTimeout(function(){fn.call(_this, ...arg);},interval);}
}

现在我打算窗口从右边拖到到左边。

天呐,控制台居然只输出了一次日志,不管我怎么拉动,当我停下来的时候就执行了最后一次

这下我们明白了。防抖的含义就是让某个时间期限内,事件处理函数只执行一次,大大节省了性能的消耗。

windows 改变文件大小 函数_手写 bind call apply 方法 与 实现节流防抖函数相关推荐

  1. 原生js已载入就执行函数_手写CommonJS 中的 require函数

    前言 来自于圣松大佬的文章<手写CommonJS 中的 require函数> 什么是 CommonJS ? node.js 的应用采用的commonjs模块规范. 每一个文件就是一个模块, ...

  2. 手写 call、apply 及 bind 函数

    之前在bind和apply以及call函数使用中详解总结过bind和apply以及call函数的使用,下面手写一下三个函数. 一.首先call函数 Function.prototype.MyCall ...

  3. 【bind()函数】JavaScript手写bind()及详解-超详细~~~

    这两天学习了手写call.apply.bind,手写bind思考了很久才实现了MDN的示例的结果,所以记录下来~ 因为是第一篇文章,所以可能存在一些错误,希望各位大佬批评指正,不吝赐教. 也欢迎不懂的 ...

  4. 全网最详细手写bind

    手写bind 在写代码前,一定要分析这个api或者关键字实现了什么,拥有什么功能,如果对其原理认识不到时,也不能达到一比一还原 bind bind执行返回的是一个新的函数 这个函数可以被new关键字执 ...

  5. 手写一个promise用法_手写一个 Promise

    1 js 的基本数据类型? 2 JavaScript 有几种类型的值? 3 什么是堆?什么是栈?它们之间有什么区别和联系? 4 内部属性 [Class] 是什么? 5 介绍 js 有哪些内置对象? 6 ...

  6. 苹果键盘怎么手写_手写笔的魅力

    请点击文末右下角"",移步官网获取更好阅读体验! 欢迎加入Augix官方QQ群:595698697. 喜讯!Augix已开通微博,请搜索关注:Augix频道. B站视频更新频道也已 ...

  7. python画cpk图_TensorFlow MNIST手写数据集的实现方法

    MNIST数据集介绍 MNIST数据集中包含了各种各样的手写数字图片,数据集的官网是:http://yann.lecun.com/exdb/mnist/index.html,我们可以从这里下载数据集. ...

  8. [js] 手写一个trim()的方法

    [js] 手写一个trim()的方法 function trim(str) { if (str[0] === ' ' && str[str.length - 1] === ' ') { ...

  9. js拆字_分图程序 _制作个人字体_手写字制作ttf字体方法

    js拆字_分图程序 _制作个人字体_手写字制作ttf字体方法 前言 FontForgeBuilds制作ttf FontForgeBuilds制作个人字体 Adobe_Fireworks_CS5批量转换 ...

最新文章

  1. spring 组件基于注解的注册方式
  2. 使用文本用户界面(NMTUI)进行网络配置
  3. 远程办公还将持续,智办事助力企业团队协作难点“破冰”
  4. VC++使用Soap ToolKit3.0调用WebService接口
  5. 阿里云centos7安装和卸载图形化操作界面
  6. Yahoo Mail,慢功出细活〔转载〕
  7. C和指针之Eratosthenes-埃拉托斯特尼筛方法找质数
  8. 坑爹的日志无法按天切割问题
  9. 在ASP.NET MVC中实现Select多选
  10. 【机器学习】 关联规则Apriori和mlxtend——推荐算法
  11. 性能提升一倍,云原生网关支持 TLS 硬件加速
  12. html判断ie6,jquery如何判断是否是ie?
  13. Hivesql-高级进阶技巧
  14. python 多帧 超分辨_利用python-opencv生成视频帧数控制,和常见错误总结
  15. java抓取网页数据_Golang丨Java丨Python爬虫实战—Boss直聘网站数据抓取
  16. 最大最小距离聚类算法c语言,聚类算法-最大最小距离算法(实例+代码)
  17. NCL中绘制中国任意省份的精确地图
  18. 基于扩张卷积神经网络的图像超分辨率
  19. 计算机网络(四)—— 网络层(1、2):网络层概述、网络层提供的两种服务
  20. hypermedia_Hypermedia REST API简介

热门文章

  1. 迁移上云方法论-6R
  2. ubuntu挂载windows下的文件目录的步骤
  3. 重游HBase核心知识点总结
  4. Spark _03RDD_Transformations_Action_使用scalajavaAPI
  5. 数据结构与算法(一):排序算法之 - 快速排序(详细步骤图解,附代码)
  6. 【Python】import pandas时,报错 pandas Missing required dependencies ['numpy'] 原因分析
  7. 《FlaskWeb开发:基于Python的Web应用开发实战》笔记
  8. jar包冲突常用的解决方法
  9. java动态代理原理及解析
  10. google怎么做(3.搜索结果重排序)