千家信息网

Js实现Bind的使用方法

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,这篇文章给大家介绍Js实现Bind的使用方法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。最近在帮女朋友复习 JS 相关的基础知识,遇到不会的问题,她就会来问我。这不是很简单?三
千家信息网最后更新 2025年01月16日Js实现Bind的使用方法

这篇文章给大家介绍Js实现Bind的使用方法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

最近在帮女朋友复习 JS 相关的基础知识,遇到不会的问题,她就会来问我。

这不是很简单?三下五除二,分分钟解决。

function bind(fn, obj, ...arr) {  return fn.apply(obj, arr) }

于是我就将这段代码发了过去

这时候立马被女朋友进行了一连串的灵魂拷问。

这个时候,我马老师就坐不住了,我不服气,我就去复习了一下 bind,发现太久不写基础代码,还是会需要一点时间复习,这一次我得写一个有深度的 bind,深得马老师的真传,给他分成了五层速记法。

第一层 - 绑定在原型上的方法

这一层非常的简单,得益于 JS 原型链的特性。由于 function xxx 的原型链 指向的是 Function.prototype , 因此我们在调用 xxx.bind 的时候,调用的是 Function.prototype 上的方法。

Function.prototype._bind = function() {}

这样,我们就可以在一个构造函数上直接调用我们的bind方法啦~例如像这样。

funciton myfun(){} myfun._bind();

想要详细理解这方面的可以看这张图和这篇文章(https://github.com/mqyqingfeng/blog/issues/2)

第二层 - 改变 this 的指向

这可以说是 bind 最核心的特性了,就是改变 this 的指向,并且返回一个函数。而改变 this , 我们可以通过已知的 apply 和 call 来实现,这里我们就暂且使用 apply 来进行模拟。首先通过 self 来保存当前 this,也就是传入的函数。因为我们知道 this 具有 隐式绑定的规则(摘自 《你不知道的JavaScript(上)》2.2.2 ),

function foo() {console.log(this.a)} var obj = {a: 2, foo}; obj.foo(); // 2

通过以上特性,我们就可以来写我们的 _bind 函数。

Function.prototype._bind = function(thisObj) {  const self = this;  return function () {     self.apply(thisObj);   } } var obj = {a:1} function myname() {console.log(this.a)} myname._bind(obj)(); // 1

可能很多朋友都止步于此了,因为在一般的面试中,特别是一些校招面试中,可能你只需要知道前面两个就差不多了。但是想要在面试中惊艳所有人,仍然是不够的,接下来我们继续我们的探索与研究。

第三层 - 支持柯里化

函数柯里化是一个老生常谈的话题,在这里再复习一下。

function fn(x) {  return function (y) {   return x + y;  } } var fn1 = fn(1); fn1(2) // 3

不难发现,柯里化使用了闭包,当我们执行 fn1 的时候,函数内使用了外层函数的 x, 从而形成了闭包。

而我们的 bind 函数也是类似,我们通过获取当前外部函数的 arguments ,并且去除了绑定的对象,保存成变量 args,最后 return 的方法,再一次获取当前函数的 arguments, 最终用 finalArgs 进行了一次合并。

Function.prototype._bind = function(thisObj) {  const self = this;   const args = [...arguments].slice(1)  return function () {     const finalArgs = [...args, ...arguments]     self.apply(thisObj, finalArgs);   } }

通过以上代码,让我们 bind 方法,越来越健壮了。

var obj = { i: 1} function myFun(a, b, c) {   console.log(this.i + a + b + c); } var myFun1 = myFun._bind(obj, 1, 2); myFun1(3); // 7

一般到了这层,可以说非常棒了,但是再坚持一下下,就变成了完美的答卷。

第四层 - 考虑 new 的调用

要知道,我们的方法,通过 bind 绑定之后,依然是可以通过 new 来进行实例化的, new 的优先级会高于 bind(摘自 《你不知道的JavaScript(上)》2.3 优先级)。

这一点我们通过原生 bind 和我们第四层的 _bind 来进行验证对比。

// 原生 var obj = { i: 1} function myFun(a, b, c) {   // 此处用new方法,this指向的是当前函数 myFun    console.log(this.i + a + b + c); } var myFun1 = myFun.bind(obj, 1, 2); new myFun1(3); // NAN  // 第四层的 bind var obj = { i: 1} function myFun(a, b, c) {   console.log(this.i + a + b + c); } var myFun1 = myFun._bind(obj, 1, 2); new myFun1(3); // 7

注意,这里使用的是 bind方法

因此我们需要在 bind 内部,对 new 的进行处理。而 new.target 属性,正好是用来检测构造方法是否是通过 new 运算符来被调用的。

接下来我们还需要自己实现一个 new ,

而根据 MDN,new 关键字会进行如下的操作:

1.创建一个空的简单JavaScript对象(即{});

2.链接该对象(设置该对象的constructor)到另一个对象 ;

3.将步骤1新创建的对象作为this的上下文 ;

4.如果该函数没有返回对象,则返回this。

Function.prototype._bind = function(thisObj) {  const self = this;   const args = [...arguments].slice(1);  return function () {     const finalArgs = [...args, ...arguments];   // new.target 用来检测是否是被 new 调用     if(new.target !== undefined) {       // this 指向的为构造函数本身       var result = self.apply(this, finalArgs);       // 判断改函数是否返回对象       if(result instanceof Object) {         return reuslt;       }       // 没有返回对象就返回 this       return this;     } else {       // 如果不是 new 就原来的逻辑       return self.apply(thisArg, finalArgs);     }   } }

看到这里,你的造诣已经如火纯情了,但是最后还有一个小细节。

第五层 - 保留函数原型

以上的方法在大部分的场景下都没有什么问题了,但是,当我们的构造函数有 prototype 属性的时候,就出问题啦。因此我们需要给 prototype 补上,还有就是调用对象必须为函数。

Function.prototype._bind = function (thisObj) {   // 判断是否为函数调用   if (typeof target !== 'function' || Object.prototype.toString.call(target) !== '[object Function]') {     throw new TypeError(this + ' must be a function');   }   const self = this;   const args = [...arguments].slice(1);   var bound = function () {     var finalArgs = [...args, ...arguments];     // new.target 用来检测是否是被 new 调用     if (new.target !== undefined) {       // 说明是用new来调用的       var result = self.apply(this, finalArgs);       if (result instanceof Object) {         return result;       }       return this;     } else {       return self.apply(thisArg, finalArgs);     }   };   if (self.prototype) {     // 为什么使用了 Object.create? 因为我们要防止,bound.prototype 的修改而导致self.prototype 被修改。不要写成 bound.prototype = self.prototype; 这样可能会导致原函数的原型被修改。     bound.prototype = Object.create(self.prototype);     bound.prototype.constructor = self;   }   return bound; };

关于Js实现Bind的使用方法就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

函数 方法 对象 原型 指向 时候 复习 代码 特性 问题 柯里 检测 使用方法 接下来 优先级 内容 可以通过 基础 女朋友 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 湖北正规网络技术代理商 网络安全等保2.0内容 bv310系统升级服务器地址 互联网时代的科技作品 软件开发遵循的规则 防城港网络安全审计 东莞云闪修网络技术有限公司 服务器内存条安装普通主板吗 计算机网络技术移动通信 网络安全问题频道 hcna网络技术学习指南京东 河南大数据软件开发价钱是多少 软件开发项目后勤工作有哪些 联通公司网络技术员 c读取文件中的数据库 网络安全专网龙头 医院网络安全平台 数据库事件执行的顺序 神魔大陆为什么总是断开服务器 培训开发人员的软件开发手册 .db数据库文件怎么打开 加密中转服务器 双路服务器主板内存条怎么插 存储和服务器基本原理指的是哪些 数据库系统教程何玉洁主编 jsp服务器页面渗透 延津网络安全宣传周 软件开发 联系单范本 物联网网络技术实习 mysql数据库管理软件有
0