一、bind()方法的实现

  在JavaScript中,方法往往涉及到上下文,也就是this,因此往往不能直接引用。就拿最常见的console.log("info…")来说,避免书写冗长的console,直接用log("info…")代替,不假思索的会想到如下语法:

var log = console.log;
log("info");

  很遗憾,运行报错:TypeError: Illegal invocation。

  原因很清楚:对于console.log("info…")而言,log方法在console对象上调用,因此log方法中的this指向console对象,而我们用log变量指向console.log方法,然后直接调用log方法,此时log方法的this指向的是window对象,上下文不一致,当然会报错了。

  此时我们可以用bind方法解决这个问题。bind方法允许手动传入一个this,作为当前方法的上下文,然后返回持有上下文的方法。例如:

var write = document.write.bind(document);
write("hello");

  这样就不会报错了。但是,bind方法并不支持ie 8以及更低版本的浏览器,我们完全可以自己实现一个,很简单。

Function.prototype.bind = Function.prototype.bind || function(context){
var _this = this;
return function(){
_this.apply(context, arguments);
};
};

  核心就是通过apply方法实现,闭包的经典应用。_this指向当前方法,context指向当前方法的上下文,二者均通过闭包访问。

  bind所做的就是自动封装函数在函数自己的闭包中,这样我们可以捆绑上下文(this关键字)和一系列参数到原来的函数。你最终得到的是另一个函数指针。

function add(a,b){
return a + b;
}
var newFoo = add.bind(this,,);

  请注意,我们不仅捆绑this到newFoo()函数,而且我们也捆绑了两个参数。所以,当我们调用newFoo()的时候,返回值将是7。但是,如果我们在调用之前newFoo更改的参数的话,会发生什么?

  如果我们使用变量绑定参数到newFoo(),然后在调用newFoo()前改变变量,你觉得值会变为什么呢?

function add(a,b){
return a + b;
}
var a = ;
var b = ;
var newFoo = add.bind(this,a, b);
a = ;
b = ;
console.log(newFoo());

  返回值仍然是7,因为bind()绑定的是参数的值,而不是实际变量的值。这是好消息,我们可以在代码中利用这个巨大的优势。

二、bind()的应用:

1、绑定函数的this值

  bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象。如果不做特殊处理,一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题:

this.num = ;
var mymodule = {
num: ,
getNum: function() { return this.num; }
}; module.getNum(); // var getNum = module.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象 // 创建一个'this'绑定到module的函数
var boundGetNum = getNum.bind(module);
boundGetNum(); //

  改变对象方法里this的值

  改变事件处理函数里的this值,因为在事件处理函数中的this指向的是dom元素,在某些情况下我们需要改变这个this值

2、偏函数实现

  截取一段关于偏函数的定义:

Partial application can be described as taking a function that accepts some number of arguments, 
binding values to one or more of those arguments,
and returning a new function that only accepts the remaining, un-bound arguments.

  这是一个很好的特性,使用bind()我们可以设定函数的预定义参数,然后调用的时候传入其他参数即可。

//使用bind,我们就可以像这样写代码实现Currying:
function add(a,b,c) {
return a+b+c;
}
var addAgain = add.bind(this, , );
var result = addAgain();
function list() {
return Array.prototype.slice.call(arguments);
} var list1 = list(, , ); // [1, 2, 3] // 预定义参数37
var leadingThirtysevenList = list.bind(undefined, ); var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(, , ); // [37, 1, 2, 3]

3、在定时器中使用,比如和setTimeout一起使用

  一般情况下setTimeout()的this指向window或global对象。当使用类的方法时需要this指向类实例,就可以使用bind()将this绑定到回调函数来管理实例。

4、bind用于事件处理程序

  当一个事件处理程序被调用时,它访问的上下文会生成事件,而不是在创建事件处理程序的对象中。通过使用bind,可以肯定的是,函数会被访问正确的上下文。

三、多次绑定bind方法

  如果使用bind()方法多次绑定,最终得到的this会是哪个绑定的呢?

function say() {
alert(this.x);
};
var a = say.bind({x: });
var b = a.bind({x: });
b(); // 这里会输出1还是2呢?

  那么我们不妨分析一下:

//say函数使用bind方法,穿进去了一个对象,相当于
var a = function() {
return say.apply({x: });
}; //如果我们对得到的函数a再进行绑定,则相当于
var b = function() {
return a.apply({x: });
};

var b = function() {
return function() {
return say.apply({x: });
}.apply({x: });
};
  这样虽然我们改变了函数a里this的值,但是最后函数say里的this的值还是由第一次绑定时的参数决定,而与函数a中的this值无关。

1、多次绑定的结果

  所以无论使用bind绑定多少次,最终原函数的this值是由第一次绑定传的参数决定的

 2、多次绑定参数的顺序

function say() {
alert(this.x);
};
var a = say.bind({x: },,,);
var b = a.bind({x: },,,);
a(,,);
b(,,);
// 此时原函数say参数的顺序的怎样的呢?
// 是[4,5,6,1,2,3,7,8,9]还是[1,2,3,4,5,6,7,8,9]

  首先对say使用bind方法,会改变函数say的this值,和“内置”参数。所以 a(7,8,9) 的参数组成是:内置的参数 + 调用时传入的参数 = 最终函数,即[1,2,3]+ [7,8,9] = [1,2,3,7,8,9]

  而对函数a使用bind方法,只会改变函数a的this值,和往函数a里“内置”参数。所以 b(7,8,9) 的参数组成是:[1,2,3](在函数say内置的参数) + [4,5,6](在函数a内置的参数) + [7,8,9] = [1,2,3,4,5,6,7,8,9]
  总结:对哪个函数使用bind()方法即改变这个函数的this值,和内置其参数,或者说像克里化一样理解,先预置好参数

var a = say.bind({x:},,,); // 是改变函数say的this值,和在函数say上预置参数1,2,3
var b = a.bind({x: }, ,,); // 是改变函数a的this,和在函数a上预置预置参数4,5,6

JavaScript中的bind方法及其常见应用的更多相关文章

  1. JavaScript中的工厂方法、构造函数与class

    JavaScript中的工厂方法.构造函数与class 本文转载自:众成翻译 译者:谢于中 链接:http://www.zcfy.cc/article/1129 原文:https://medium.c ...

  2. JavaScript中的bind,call和apply函数的用法和区别

    一直没怎么使用过JavaScript中的bind,call和apply, 今天看到一篇比较好的文章,觉得讲的比较透彻,所以记录和总结如下 首先要理解的第一个概念,JavaScript中函数调用的方式, ...

  3. javascript中的splice方法介绍&示例

    javascript 中的 splice 方法很强大,它可以用于插入.删除或替换数组的元素. 下面来一一介绍! 删除:用于删除元素,两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数 ...

  4. javascript中的toString()方法

    javascript中的toString()方法,主要用于Array.Boolean.Date.Error.Function.Number等对象.下面是这些方法的一些解析和简单应用,做个纪律,以作备忘 ...

  5. javascript 中的 bind (编辑中。。。。)

    这篇文章说的非常好!http://my.oschina.net/blogshi/blog/265415 我的体会就是,函数中的this,指的是运行时,它是被哪个对象调用的.因为javascrpit的函 ...

  6. Java和JavaScript中使用Json方法大全

    林炳文Evankaka原创作品. 转载请注明出处http://blog.csdn.net/evankaka   摘要:JSON(JavaScript Object Notation) 是一种轻量级的数 ...

  7. Javascript中遍历数组方法的性能对比

    Javascript中常见的遍历数组的方法 1.for循环 for(var i = 0; i < arr.length; i++) { // do something. } 2.for循环的改进 ...

  8. 把玩Javascript中的bind

    前言 今天闲着无聊随便逛了逛MDN,忽而看到一个方法Function.prototype.bind(),突然发现除了使用这个方法之外都没有仔细琢磨过这个方法.于是乎,找到了kill time的事情-写 ...

  9. Json学习总结(1)——Java和JavaScript中使用Json方法大全

    摘要:JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语 ...

随机推荐

  1. LeetCode 192:Reverse Bits

    Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...

  2. HDU 4344 大数分解大素数判定

    这里贴个模板吧.反正是不太理解 看原题就可以理解用法!! #include <cstdio> #include <iostream> #include <algorith ...

  3. springboot整合jsp模板

    springboot整合jsp模板 在使用springboot框架里使用jsp的时候,页面模板使用jsp在pom.xnl中需要引入相关的依赖,否则在controller中无法返回到指定页面 〇.搭建s ...

  4. Java和Js的高精度计算

    转载自:http://blog.csdn.net/zhutulang/article/details/6844834#comments Java: import java.math.BigDecima ...

  5. [ MongoDB ] 分片集群及测试

    分片 在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求. 当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量. ...

  6. Selenium2+python自动化49-判断文本(text_to_be_present_in_element)【转载】

    前言 在做结果判断的时候,经常想判断某个元素中是否存在指定的文本,如登录后判断页面中是账号是否是该用户的用户名. 在前面的登录案例中,写了一个简单的方法,但不是公用的,在EC模块有个方法是可以专门用来 ...

  7. VS2010编写C++程序出现error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "StdAfx.h"”?

    用VS2010编写C++程序,编译时出现如下错误: 修改方法: 右击项目,选择属性 点击确定,重新编译,错误解决.

  8. hdu 1423(LCS+LIS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1423 好坑啊..还有公共串为0时的特殊判断,还有格式错误..看Discuss看知道除了最后一组测试数据 ...

  9. “equals”和“==”

    “equals”和“==” 首先对于基本类型来说,当值相同的时候,地址也是相同的,所以可以使用“==”进行比较,但是对于equals来说,equals比较的是栈中引用指向的堆中的对象.所以在比较对象的 ...

  10. Bot Framework测试

    在开发完成Bot Framework后,在本机的模拟器都是成功的,但未知在发布后会出现什么样的问题,所以需要将本机发布的站点给到Bot 1.在Bot Framework注册一个Bot,打开Bot Fr ...