为什么需要bind

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
}; alert(object.getNameFunc()()); //"The Window"

object.getNameFunc()返回一个匿名函数,在全局环境调用该函数,this指向的全局对象

解决这一问题,可以像下面这样,将匿名函数外部作用域中this对象保存在闭包能够访问到的变量中

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
}
}
}; alert(object.getNameFunc()()); //"My Object"

上述解决方法需要修改对象的方法,如果不能修改原对象的方法,该如何做呢?

这时,我们可以像下面这样,使用apply或call方法指定函数的作用域

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
alert(func.apply(object)); //"My Object"

通过apply、call,已经可以输出预期的My Object

但是,每次调用时都需要以func.apply(object)的形式调用,这不是很怪么

理想的调用方式,当然是在通过某种处理后,之后可以以func()形式调用,像下面这样

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
func=func.bind(object);
alert(func()); //"My Object"

ECMAScript 5中的bind

ECMAScript 5定了了bind方法,这个方法会创建一个函数实例,其this值会被绑定到传给bind函数的值,上面代码给出了bind函数的使用方式,再给一个简单示例。

window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
} var func=sayColor.bind(o);
func();//"blue"

虽然大部分浏览器中已经可以使用ECMAScript 5定义的这个方法,但在少数不支持的浏览器中你还是会遇到兼容性问题,这是如何处理呢?

通过上面apply、call方法使用示例 ,可以像下面这样提供一个解决方案

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

Prototype.js中的bind

// The .bind method from Prototype.js
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};

上述代码中,

args=Array.prototype.slice.call(arguments)将调用bind函数时参数集合arguments转换为数组array

object=args.shift()将args数组第一个元素取出作为当前对象

匿名函数中,调用args.concat(Array.prototype.slice.call(arguments))是为了将调用匿名函数时传入的参数与调用bind时参数合并成一个参数数组

以一个调用示例来看上述过程

var obj = { x: 'prop x' };
//args = Array.prototype.slice.call(arguments)后args = [obj, 12, 23 ]
//object=args.shift()后,args =[12, 23] ,object =obj var boundExample = example.bind(obj, , );
boundExample(, ); // arguments => 36, 49 ,调用args.concat(Array.prototype.slice.call(arguments))后,arguments that our example() function receives => [12, 23, 36, 49]

Firefox中的bind

if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
} var aArgs = Array.prototype.slice.call(arguments, ),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
}; fNOP.prototype = this.prototype;
fBound.prototype = new fNOP(); return fBound;
};
}

Firefox为bind提供了一个兼容实现,主要代码与prototype.js中实现类似,不再逐句解释了

《Javascript高级程序设计》读书笔记之bind函数详解的更多相关文章

  1. javascript高级程序设计读书笔记

    第2章  在html中使用javascript 一般都会把js引用文件放在</body>前面,而不是放在<head>里, 目的是最后读取js文件以提高网页载入速度. 引用js文 ...

  2. JavaScript高级程序设计-读书笔记(7)

    第22章 高级技巧 1.高级函数 (1)安全的类型检测 在任何值上调用Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串. ...

  3. javascript高级程序设计读书笔记-事件(一)

    读书笔记,写的很乱   事件处理程序   事件处理程序分为三种: 1.html事件2. DOM0级,3,DOM2级别  没有DOM1 同样的事件 DOM0会顶掉html事件   因为他们都是属性  而 ...

  4. javascript高级程序设计读书笔记----引用类型

        Array类型. ECMAScript数组的每一项可以保存任何类型的数据. 数组大小是可以动态调整的. 创建数组第一种基本方式方式: 使用Array构造函数 var colors = new ...

  5. JavaScript高级程序设计读书笔记之JSON

    JSON(JavaScript Object Notation)JavaScript对象表示法.JSON是JavaScript的一个严格的子集,利用了JavaScript中的一些模式来表示结构化数据. ...

  6. javascript高级程序设计读书笔记----函数表达式

    定义函数两种方式: 1.函数声明 function sayHi(){ alert("Hi"); } sayHi();//调用函数 2.函数表达式 var sayHi = funct ...

  7. Javascript高级程序设计读书笔记(第六章)

    第6章  面向对象的程序设计 6.2 创建对象 创建某个类的实例,必须使用new操作符调用构造函数会经历以下四个步骤: 创建一个新对象: 将构造函数的作用域赋给新对象: 执行构造函数中的代码: 返回新 ...

  8. JavaScript高级程序设计 读书笔记

    第一章 JavaScript 简介 第二章 Html中使用JavaScript 第三章 基本概念 第四章 变量,作用域,内存 第五章 引用类型 第六章 面向对象 第七章 函数表达式 第八章 BOM 第 ...

  9. JavaScript高级程序设计-读书笔记(6)

    第20章 JSON JSON是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量 JSON的语法可以表示一下三种类型的值 l        简单值:使用与JavaScript相同的语法,可以在JS ...

随机推荐

  1. TApplication.Initialize的前世今生

    ---------------------------------------------------------------------------------------------------- ...

  2. C中程序的内存分配

    一.预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...

  3. fake it till you become it

    fake it till you become it_你泛起山川烟波里的不是我._百度空间 fake it till you become it

  4. fopen()功能

    1.2 文件输入和输出功能 键盘.显示器.打印机.磁盘驱动器和其他逻辑器件, 输入和输出可以通过文件管理方法可以完成. 最经常使用的编程是一个磁盘文件, 因此,这一部分主要是基于磁盘文件, 简介Tur ...

  5. VirtualBox,Kernel driver not installed (rc=-1908)

    http://hi.baidu.com/spt_form/item/316d6207b47b8ee03499020a VirtualBox,Kernel driver not installed (r ...

  6. 单页应用Scrat实践

    单页应用Scrat实践 1.开始 随着前端工程化深入研究,前端工程师现在碉堡了,甚至搞了个自己的前端网站http://div.io/需要邀请码才能注册,不过里面的技术确实牛.距离顶级的前端架构,目前博 ...

  7. ios王云鹤--iPhone中,点击换行,键盘消失。

    1.要在声明文件中实现 UItextFieldDelegate 协议 2.在实现文件中实现 UItextFieldDelegate 协议 中键盘消失的方法即: -(BOOL)textFieldShou ...

  8. Java抓取网页数据(原来的页面+Javascript返回数据)

    转载请注明出处! 原文链接:http://blog.csdn.net/zgyulongfei/article/details/7909006 有时候因为种种原因,我们须要採集某个站点的数据,但因为不同 ...

  9. 30分钟快速掌握AngularJs

    [后端人员耍前端系列]AngularJs篇:30分钟快速掌握AngularJs   一.前言 对于前端系列,自然少不了AngularJs的介绍了.在前面文章中,我们介绍了如何使用KnockoutJs来 ...

  10. 那些年我们装过的数据库---盘点sqlserver2008安装时遇到的各种的问题(持续更新中)

    给自己安过sqlServer2008,也给好多同学安过sqlServer2008,期间遇到了好多不同的另人心烦的问题,在这里整理一下,(涉及到的部分方法是在网上找的,有些也没试过,仅仅是在这里整理一下 ...