【build your own xxx】实现你自己的bind函数
今天来实现JavaScript的bind函数。
首先看MDN的bind函数描述:
从上面可以看出来,var A = B.bind(this)函数其实干了这几件事情:
- 返回一个函数,且这个函数后面运行时的this就是bind(this)传入的this
- 接收参数,这些参数(如果有的话)作为bind()的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面
- 使用new操作bind函数返回的函数时,之前传入的this会被忽略,也就是说new的优先级高于bind
第一步
首先实现第一步:
Function.prototype.Zbind = function (othis) {var originFunc = this;return function () {originFunc.apply(othis);}
}var obj = {}function createAgumon() {this.name = "agumon";
}
var createAgumonBind = createAgumon.Zbind(obj);
createAgumonBind();
obj;// {name: "agumon"}
第二步
第二步考虑传参的问题,首先看看原生的bind函数是如何传参的:
var obj = {}
function createAgumon(gender, age) {this.name = "agumon";this.gender = gender;this.age = age;
}
var createAgumonBind = createAgumon.bind(obj, 'female');
createAgumonBind(22);
可以看出来在bind函数中能先传部分参数,运行bind返回的函数时可以再传入部分参数。
自己实现:
Function.prototype.Zbind = function (othis) {var originFunc = this;var partArgs = [].slice.call(arguments, 1);var func = function() {};var boundFunc = function () {var finalArgs = partArgs.concat([].slice.call(arguments));return originFunc.apply(othis, finalArgs);}return boundFunc;
}var obj = {}function createAgumon(gender, age) {this.name = "agumon";this.gender = gender;this.age = age;
}var createAgumonBind = createAgumon.Zbind(obj, 'female');
createAgumonBind(22);
obj;// {name: "agumon", gender: "female", age: 22}
第三步
使用new来调用bind返回的函数时,会忽略bind传入的this
new操作和普通的函数调用有哪些区别?
粗略的来讲,例如new F()这样的调用,有以下几个步骤:
- 新建一个对象,var o = new Object()
- 设置原型链,o.__proto__ = F.prototype
- 把F函数体内的this绑定为o,并且执行F函数的代码
- 判断F的返回类型:
如果是值类型,则返回o
如果是引用类型,则返回该引用类型对象
开始实现:
Function.prototype.Zbind = function (othis) {var originFunc = this;var partArgs = [].slice.call(arguments, 1);var func = function() {};var boundFunc = function () {var finalArgs = partArgs.concat([].slice.call(arguments));return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);}return boundFunc;
}var obj = {}function createAgumon(gender, age) {this.name = "agumon";this.gender = gender;this.age = age;
}var createAgumonBind = createAgumon.Zbind(obj, 'female');
var newObj = new createAgumonBind(22);
obj // {}
newObj // {name: "agumon", gender: "female", age: 22}
关键的地方在于这里:this instanceof boundFunc ? this : othis,如果是new操作的话,此时this的__proto__已经指向了boundFunc,所以使用instanceof可以检测出是否在使用new操作
小细节
原型丢失
刚刚实现的Zbind方法有个小问题:
Function.prototype.Zbind = function (othis) {var originFunc = this;var partArgs = [].slice.call(arguments, 1);var func = function() {};var boundFunc = function () {var finalArgs = partArgs.concat([].slice.call(arguments));return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);}return boundFunc;}var obj = {}function createAgumon(gender, age) {this.name = "agumon";this.gender = gender;this.age = age;}createAgumon.prototype.college = 'THU'var createAgumonBind = createAgumon.Zbind(obj, 'female');var newObj = new createAgumonBind(22);console.log(newObj.college)// undefined
可以看出来原型链丢失了,newObj.college得是'THU'才行
修改:
Function.prototype.Zbind = function (othis) {var originFunc = this;var partArgs = [].slice.call(arguments, 1);var func = function() {};var boundFunc = function () {var finalArgs = partArgs.concat([].slice.call(arguments));return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);}func.prototype = originFunc.prototype;boundFunc.prototype = new func();return boundFunc;}var obj = {}function createAgumon(gender, age) {this.name = "agumon";this.gender = gender;this.age = age;}createAgumon.prototype.college = 'THU'var createAgumonBind = createAgumon.Zbind(obj, 'female');var newObj = new createAgumonBind(22);console.log(newObj.college)// 'THU'
为什么要使用func.prototype = originFunc.prototype;boundFunc.prototype = new func();,而不是直接用boundFunc.prototype = originFunc.prototype;是因为这样写的话,修改boundFunc.prototype会影响到原函数的prototype。
that'all
参考资料:
mdn-bind
javascript中,new操作符的工作原理是什么?
【build your own xxx】实现你自己的bind函数相关推荐
- ERROR: Could not build wheels for XXX, which is required to install pyproject.toml-based projects
报错内容: ERROR: Could not build wheels for pynacl, which is required to install pyproject.toml-based pr ...
- 无法将“XXX”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 对这个问题的解决方法
我在windows里用powershell跑ps1格式的文件,会报如下的错误. 无法将"XXX"项识别为 cmdlet.函数.脚本文件或可运行程序的名称. 首先我用powershe ...
- nothing to build for project 'XXX'
有时候使用Eclipse CDT或者CCS 写程序时出现 nothing to build for project 的错误,这是因为新建的项目类型和实际的源代码类型不一致造成的,比如你新建了C Pr ...
- 无法将“xxx”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
在学习国产某芯片时,跟着b站某视频搭建编译环境,如题报错,找了一天错误,试了网上能找到的所有方法,皆无果,后面发现是某视频的字幕有问题,字幕中命令行为.\install.psl xxxx,实际因为.\ ...
- 全网详细解决:无法将 “xxx” 项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次
文章目录 1. 复现问题 2. 分析问题 3. 解决问题 1. 复现问题 今天,使用如下命令在Windows PowerShell中执行时: telnet 127.0.0.1 80 却报出如下错误: ...
- 【解决】无法将“XXX”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次
进入PowerShell 模式 Get-ExecutionPolicy -List 查看当前所有作用域 上图显示就最后一个作用域有权限,其他作用域都没有权限,那么我们就需要去给它设置权限 设置权限 S ...
- 无法将“xxx”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
Win 键 + Q ,在搜索框内输入 Powershell . 点击以管理员身份运行. 输入代码 set-executionpolicy remotesigned 按回车键执行命令. 输入 A,按回车 ...
- [转]Nant daily build实践
本文转自:http://www.cnblogs.com/moonvan/archive/2006/11/07/552585.html 折腾了一个周,基于Nant的VS.NET项目每日构建终于成功了,在 ...
- iOS build faad
1.新建目录xxx,下载faad(http://downloads.sourceforge.net/faac/faad2-2.7.tar.gz)到xxx,解压,重命名为faad. 2.编写build. ...
最新文章
- 【资源分享】数字图像处理MATLAB版冈萨雷斯+中文高清版+随书源码链接
- 安装SAP Business One对软硬件有哪些要求
- initializeCachedDB function in JavaScript - how is the call delegated to
- html相对定位向上偏移,使用CSS的相对定位和偏移量
- asp.net接受表单验证格式后再提交数据_看滴普科技大前端如何玩转el-form-renderer 表单渲染器1.14.0
- openfeign seata事务不回滚_Spring,你为何中止我的事务?
- 猎豹网校C++ Primer学习笔记
- NRF52840 USB串口例程
- vmware虚拟机WinXp sp3的系统cpu占用100%的解决方案
- ECCV2022 | 网易AI 基于单幅图片的实时高分辨率人脸重演算法
- 微信小程序之小程序审核
- 成大事,赚大钱,都要有股永不服输的精神
- 怎么关闭Windows7显示器校准?
- 术语FXO和FXS的含义是什么?
- Android应用之——微信微博第三方sdk登录分享使用过程中的一些常见问题
- 深入理解时间和空间复杂度
- 四足步行机器人的结构设计及仿真
- 发明计算机的人的名人名言,60句关于发明的名言
- 分库分表之MyCat详解
- MTI雷达原理的学习