为什么需要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. OpenStreetMap初探(一)——了解OpenStreetMap

    1. 開始关注OpenStreetMap始于此博文:<微软对抗谷歌的秘密武器:开源地图OpenStreetMap>  http://news.csdn.net/a/20120328/313 ...

  2. MFC 总体理解

    在MFC程序中,我们并不经常直接调用Windows API,而是从MFC类创建对象并调用属于这些对象的成员函数.也就是说MFC封装了Windows API 你说你喜欢C++而MFC换一种说法就是一个用 ...

  3. C/C++中constkeyword

    今天在做一个趋势笔试题的时候.才让我有了系统把constkeyword好好总结一下的冲动,由于这个关键词大大小小好多地方都出现过,出现频率很高,而每次仅仅是简短的把答案看了一下,没有真正将其整个使用方 ...

  4. PageHeap,调试Heap问题的工具

    <Windows用户态程序高效排错>第二章主要介绍用户态调试相关的知识和工具.本文主要讲了PageHeap,调试Heap问题的工具. AD:51CTO学院:IT精品课程在线看! 2.4.2 ...

  5. [置顶] Cocos2d-x 实例源码分析之二 小实例的主框架

    这篇文章是分析第一个小实例ActionTest的源码.其实所有实例程序的结构都是一样的,只有特定方法里的代码不同,大的框架都是一样的.也就是说看完这篇文章你就可以自己开始分析其他源码了. 废话不多说, ...

  6. Spring Framework AOP具体解释

    此前对于AOP的使用仅限于声明式事务,除此之外在实际开发中也没有遇到过与之相关的问题.近期项目中遇到了下面几点需求,细致思考之后,认为採用AOP来解决.一方面是为了以更加灵活的方式来解决这个问题,还有 ...

  7. Hbase集群环境搭建

    Hbase数据库依赖 Hadoop和zookeeper,所以,安装Hbase之前,需要先把zookeeper集群搭建好.(当然,Hbase有内建的zookeeper,不过不建议使用).Hbase配置上 ...

  8. MVC之国际化

    MVC之国际化 前言 在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于 ...

  9. 如何开发auto complete 智能提示功能

    目录(?)[+] 如何开发auto complete 智能提示功能 最近网上好像流传用redis实现,其实智能提示和用什么存储关系不大 07年,我过一个类似的项目 我有几千个名字,随着用户在输入框中不 ...

  10. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...