理解建议:如果对this指向规则不了解的话,建议先了解this指向规则,最好还能对call和apply的使用和内部原理也有所了解,不然直接研究bind还是会有些难度的。

一、bind()的使用

//html
<button id="btn"></button>
//js
var list = {
init:function(){
this.ms = "duyi";
this.dom = document.getElementById("btn");
this.bindEvent();
},
bindEvent:function(){
this.dom.onclick = this.showMessage.bind(this);
},
showMessage:function(){
alert(this.ms);
}
}
list.init();

在单对象编程中,有一种非常典型的bind()的应用,就以上面的示例来说,当出现给DOM绑定事件回调函数时,又还需要继续保持函数的this指向原来的对象,就可以按照示例的这种方式来实现:this.dom.onclick = this.showMessage.bind(this);

我们知道call和apply可以改变函数执行的this指向,但是call和apply都是立即执行该函数,而bind是将this指向绑定到指定的对象上,并且返回函数并维持this指向这个对象。接下来再来看看bind的参数设置示例:

function show(x,y,z,w){
console.log(this,x,y,z,w);
}
var DuyiO = {
x : 20
}
var newShow = show.bind(DuyiO,"1","2",3);
newShow(4);//Object {x: 20} "1" "2" 3 4

bind的参数和call非常类似,唯一的区别就在于除了调用bind时传入参数外,还可以在正式执行时传入参数,两次传入参数以拼接的方式作为函数执行的实参。但是需要注意的是,第一个参数作为函数的this指向对象必须要在调用bind方法时传入,如果调用bind方法不传入任何参数,函数的this指向就会绑定到window上。比如下面这种情况:

var newShow = show.bind();
newShow(DuyiO,"1","2",3,4);//Window {…} Object {x: 20} "1" "2" 3

最后还有一个基本上不会被应用到的功能,就是返回的函数被new关键字用来创建一个新的对象,而构造函数还是原函数本身(第二个示例中的show)。这个功能在模仿bind源码不能100%实现,但是也可以间接的实现其需要的功能。

二、bind手写实现

1.首先实现函数调用bind修改this指向即参数设置:

 Function.prototype.MyBind = function(target){
var self = this;
var args = [].slice.call(arguments,1);
var f = function(){
return self.apply( target || window,args );
}
return f;
}

2.接着再来实现函数正式调用执行时传入设置:

 Function.prototype.MyBind = function(target){
var self = this;
var args = [].slice.call(arguments,1);
var f = function(){
var _arg = [].slice.call(arguments,0);
return self.apply( target || window,args.concat(_arg) );
}
return f;
}

3.最后实现当返回函数被new操作符引用作为构造函数依然指向原函数(模拟实现功能):

 Function.prototype.MyBind = function(target){
var self = this;
var args = [].slice.call(arguments,1);
var temp = function(){};
var f = function(){
var _arg = [].slice.call(arguments,0);
return self.apply(this instanceof temp ? this : ( target || window ),args.concat(_arg) );
}
temp.prototype = self.prototype;
f.prototype = new temp();
return f;
}

这个模拟实现主要有两个关键点需要重点理解:

a.代码第七行中的this instanceof temp ? this : ( target || window ):当返回函数f被new作为构造函数引用时,这时候this指向了函数执行时内部隐式添加在变量对象上的this(这里不清楚的话可以参考JavaScript中的this指向规则),当然普通调用执行就是指向self。

b.代码第九行和第十行为什么需要改变f的原型,这就是我前面讲的模拟实现方法构造,我们知道bind在JS内部实现的是其返回函数还是那个原来的函数,这里我们多加了一层f来实现的,所以在函数被当做构造函数的时候,将f的原型指向self也可以实现其功能,但是构造的实例对象是基于f实现的,最终构造原型链还是指向self原型,该有的方法属性依然都会有。只是在原型链上多了f这个包装层。

源码来袭:bind手写实现的更多相关文章

  1. 带着萌新看springboot源码13(手写一个自己的starter)

    springboot的最强大的就是那些xxxAutoconfiguration,但是这些xxxAutoConfiguration又依赖那些starter,只有导入了这些场景启动器(starter),我 ...

  2. (3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析【待写】

    (3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析[待写]

  3. 真想用c#开发个 wp五笔输入法。。。奈何网上资料太少,源码都是c++写的。求大神指点!!!

    真想用c#开发个 wp五笔输入法...奈何网上资料太少,源码都是c++写的.求大神指点!!!!

  4. 源码来袭:call、apply手写实现与应用

    关于this指向可以了解我的另一篇博客:JavaScript中的this指向规则. 一.call与apply的使用 回顾call与apply的this指向: var value = "win ...

  5. BIND简易教程(0):在Ubuntu下源码安装BIND(其实跟前面的教程没太大关系)

    之前介绍过BIND的基本使用啦.关于BIND的入门级使用方法见:http://www.cnblogs.com/anpengapple/p/5877661.html简易教程系列,本篇只讲BIND安装. ...

  6. 源码分析系列 | 从零开始写MVC框架

    1. 前言 2. 为什么要自己手写框架 3. 简单MVC框架设计思路 4. 课程目标 5. 编码实战 5.1 配置阶段 web.xml配置 config.properties 自定义注解 5.2 初始 ...

  7. 带码农《手写Mybatis》进度3:实现映射器的注册和使用

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  8. 源码来袭!!!基于jquery的ajax分页插件(demo+源码)

    前几天打开自己的博客园主页,无意间发现自己的园龄竟然有4年之久了.可是看自己的博客列表却是空空如也,其实之前也有写过,但是一直没发布(然而好像并没有什么卵用).刚开始学习编程时就接触到博客园,且在博客 ...

  9. 社交媒体(朋友圈、微博、QQ空间)开发一网打尽,PC端移动端都有!——源码来袭!

    一.应用场景 曾几何时,社交媒体已经驻扎到了几乎每个人的生活中.看看你身边的朋友,有几个不玩朋友圈的?就算他不玩朋友圈,那也得玩微博吧.再没有底线,也得玩QQ空间. 不过,作为程序员的我们,没事还是少 ...

随机推荐

  1. 用Angular部署Cesium

    用到的集成开发环境是WebStrom,Cesium版本是1.50.0,Angular版本是6.2.4  1.首先我们安装cesium,在webstorm中的Termianl中输入 npm instal ...

  2. django--use

    https://docs.djangoproject.com/zh-hans/2.0/intro/

  3. Operation category READ is not supported in state standby

    Namenode 开启HA之后,由于zookeeper异常,出现脑裂现象 执行 $./hdfs haadmin -getServiceState nn1                         ...

  4. VS 附加到进程 加载“附加进程”弹窗很慢

    最近遇到一个问题,点击Ctrl + Alt + P 附加到进程的时候,弹出下图弹窗“附加到进程”很慢. 找了很多原因,后来发现,是因为少安装了一个插件,安装后,弹窗的耗时明显少了. 下载    Win ...

  5. Oracle 执行计划(一)-------基本介绍

    本文参照自:https://www.cnblogs.com/Dreamer-1/p/6076440.html 打开SQL执行计划: 1.选中一句正在执行的SQL 2.F5快捷键,就会出现下图,这就是执 ...

  6. session和application内置对象

    一.Session内置对象 分析得知request内置对象中的属性只是在当次请求中有效,经过客户端跳转之后就无效,因为客户端跳转属于第二个请求,也就是说request只代表当次请求的对象,如果要让客户 ...

  7. python小白——进阶之路——day1天---认识python和变量、注释

    ###-python的认知 89年开发的语言,创始人范罗苏姆(Guido van Rossum),别称:龟叔(Guido) (1)版本: python2.x原码不规范,重复较多 python3x:原码 ...

  8. 【Topcoder 1643】PossibleOrders

    题意:给一些等价关系,问把所有的数按照大小排序的种类数. 思路:首先并查集维护等价类,然后设有\(n\)个等价类. 那么就可以\(dp\)了. 考虑\(dp(i)\)表示还剩下\(i\)个等价类,答案 ...

  9. 《通过C#学Proto.Actor模型》之PID

    PID对象是代表Actor对象的进程,是能过Actor.Spawn(props)获取的:它有什么成员呢?既然代理Actor,首先有一个ID,标识自己是谁,Actor在Spawn时可以命名这个ID,否则 ...

  10. Linux内存管理 (13)回收页面

    专题:Linux内存管理专题 关键词:LRU.活跃/不活跃-文件缓存/匿名页面.Refault Distance. 页面回收.或者回收页面也即page reclaim,依赖于LRU链表对页面进行分类: ...