本文大部分内容翻译自 MDN内容, 翻译内容经过自己的理解。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Function.prototype.bind

Syntax

fun.bind(thisArg[, arg1[, arg2[, ...]]])
Parameters
thisArg

The value to be passed as the this parameter to the target function when the bound function is called. The value is ignored if the bound function is constructed using the new operator.

arg1, arg2, ...

Arguments to prepend to arguments provided to the bound function when invoking the target function.

bind函数,首先是所有函数的共有的属性,这个属性是一个函数,此函数为函数类(Function构造函数)的原型的一个属性(Function.prototype.xx),所以只有函数才能调用此接口,

故用法一般是定义一个函数,然后此函数调用bind接口

function XX(){}

XX.bind(thisArg[, arg1[, arg2[, ...]]])

此函数作用是,生成一个新的函数, 新函数具有和被绑定的函数具有相同功能(函数体)。

当新函数调用的时候,新函数中的this指代bind调用的第一个参数thisArg;

同时,如果bind调用时候有可选参数(arg1等),则这些参数则会作为被绑定函数默认前若干个参数。

为辅助理解,给出如下伪代码描述:

假设有函数

function XX(variable){ alert(this.variable=variable) }

则XX函数经过绑定后的效果

// var YY = XX.bind(widow, variable) 返回的函数 等价于如下代码段

function YY(Yvariable)

{

function XX(){ alert(widow.variable=variable) }  //XX函数中的 this 替换为 window, 待绑定的目标

XX(variable,  Yvariable); //XX调用,绑定的可选参数在前,YY的形参在后

}

函数绑定到一个对象

绑定之后的调用, 最后一行 boundGetX,虽然是被全局对象(window)调用,但是其中的this已经被替换为module,故其中this.XX 都会在module对象中查询。

this.x = 9;
var module = {
x: 81
};
var getX = function() { return this.x; } 

getX(); // 9, because in this case, "this" refers to the global object // Create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
boundGetX(); // 81

给函数预置前导参数值

如果有种需求,需要某个函数被调用的第一个参数,是一个恒值,则需要使用封装,朴素做法

function XX() {} // 有种需求, 需要XX第一个参数恒为 1

function YY(){

var xxArgs = [1];

xxArgs.concat(Array.prototype.slice.call(arguments));  // [1,  YYarguments]

XX(xxArgs)

}

bind提供了另外一种简便方法

function list() {
return Array.prototype.slice.call(arguments);
} var list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

setTimeout触发函数中this保持绑定对象

默认 setTimeout触发函数执行时候, this是绑定全局环境window, 如果想让绑定固定对象,可以使用bind接口。

如下, 对象的declare函数需要在事件到达后执行, 执行时候, declare其中的this实际上是代指LateBloomer创建的对象,但是直接作为setTimout参数则this指代window。 绑定替换为对象方法:

function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
} // Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
}; LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
}; var flower = new LateBloomer();
flower.bloom(); // after 1 second, triggers the 'declare' method

一则定时器封装应用: https://github.com/fanqingsong/Timer_Javascript/blob/master/src/timer_core.js

绑定函数作为构造函数

Warning: This section demonstrates JavaScript capabilities and documents some edge cases of the bind() method. The methods shown below are not the best way to do things and probably should not be used in any production environment.

如下例子, 将原构造函数 Point绑定到一个空对象{}上, 并生成了一个新的构造函数YAxisPoint ,此构造函数具有两个特性:

1、 其原型和Point相同的原型,即bind生成的函数,继承了待绑定函数的原型(但是你直接使用 YAxisPoint.prototype打印是undfined,只能在new之后的对象上体现)。

2、 YAxisPoint 是特定对象绑定之后的构造函数,只在普通调用情况下(YAixPoint()) 才执行this指代绑定对象的逻辑。

但是在new操作来调用的情况下, 即new YAxisPoint(), 绑定失效, 即Point中的this不指代绑定的对象。

new操作符号将按照普通构造函数逻辑,将生成一个新的对象, 将构造函数代码执行一遍,构造函数中的this指代,新建立的对象。new Construtor() 执行逻辑:

var instance = {}

Constructor.apply(instance)

instance.__proto__ = Constructor.prototype;

3、虽然Point中this不指代YAxisPoint 绑定对象(YAxisPoint 绑定啥对象也没有关系了, 但是为了避免YAxisPoint ()造成污染其他变量,尽量使用null 和空对象), 但是绑定的参数还是按照bind的定义作为前导参数传递到Point构造函数中。

修改下开头绑定的为伪代码,添加new调用的情况:

假设有函数

function XX(variable){ alert(this.variable=variable) }

则XX函数经过绑定后的效果

// var YY = XX.bind(widow, variable) 返回的函数 等价于如下代码段

function YY(Yvariable)

{

if  YY called classically then // YY普通调用模式, 由于XX已经绑定对象,需要对XX的this做替换

function XX(){ alert(widow.variable=variable) }  //XX函数中的 this 替换为 window, 待绑定的目标

else if YY called by new operator then // new YY 情况, bind不影响创建新对象

function XX(){ alert(this.variable=variable) }  //XX函数中的 this不替换,对应 被new调用的情况

end

XX(variable,  Yvariable); //XX调用,绑定的可选参数在前,YY的形参在后

}

------ MDN 实例-----

function Point(x, y) {
this.x = x;
this.y = y;
} Point.prototype.toString = function() {
return this.x + ',' + this.y;
}; var p = new Point(1, 2);
p.toString(); // '1,2' var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// not supported in the polyfill below,
// works fine with native bind:
var YAxisPoint = Point.bind(null, 0/*x*/); var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5' axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true

创建快捷方式

对于一些原型对象的函数, 如果需要引用, 往往需要些很长的一串代码, 如将array-like对象,转换为数组的 slice接口应用, 则需要如下写法:

Array.prototype.slice.apply(arguments);

进一步通过变量首先声明下slice接口, 然后调用,可以简洁点:

var slice = Array.prototype.slice;

// ...

slice.apply(arguments);

但是不能进一步将apply也放到 slice的声明中, 如果这样会有js报错, 原因为slice指向了apply函数,然后slice在window全局环境下执行, 效果相当于 window.apply,window是个对象, 不是函数,所以会有报错:

var slice = Array.prototype.slice.apply;

// ...

slice(arguments);

为了更简洁的写法,下面有请bind:

// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice); // ... slice(arguments);

现在给出进一步解释:

apply是任意函数的原型函数, 即 为 Function.prototype属性, 任意定义的一个函数 例如 function XX(){}

都可以调用apply, 即 XX.apply(obj), 此函数的意思是将 XX函数中的this替换为obj,并执行。 这里说的任意函数,当然也包括 上面例子的 Array.prototy.slice这也是函数。

function XX() { this.attr = 0}

XX(); // 由于在全局环境window中调用, this指代window对象

var obj = {}

XX.apply(obj) //将XX中的this替换为obj, 然后执行XX

// 上一行等价于, 先根据XX生成一个替换过this的函数YY, 然后再执行, 即apply有如下实现(伪代码):

function Function.prototype.apply(obj) //obj为XX函数中this替换的目标

var YYGenerator = function( caller)  // caller为 apply调用对象,  即XX

return function() {  caller.functionBody.replace( this, obj)  } // XX函数体中 this 替换为 obj

end

var YY() = YYGenerator(this);  // this 为apply调用者, 即为 XX函数

YY();

end

则apply函数经过绑定后的效果,构造过程包括三步,逐步填充slice函数体:

1、将Function.prototype.apply代码 复制到另一函数  boundapply

2、执行绑定动作, 将boundapply中 this 替换为 bind的第一个参数 unboundSlice

3、添加boundapply调用语句。

//var unboundSlice = Array.prototype.slice;

//var slice = Function.prototype.apply.bind(unboundSlice);    生成的函数等价于如下伪代码

function slice()

{

function boundapply(obj) //obj为unboundSlice函数中this替换的目标

var YYGenerator = function( caller)  // caller为 apply调用对象,  即unboundSlice

return function() {  caller.functionBody.replace( this, obj)  } // unboundSlice函数体中 this 替换为 obj

end

var YY() = YYGenerator(unboundSlice);  // this替换为unboundSlice为apply调用者, 即为 unboundSlice函数

YY();

end

boundapply(arguments);  //arguments为unboundSlice函数中this替换的目标

}

slice(arguments)

此场景不太好理解, 故给出上文描述, 其中牵扯到两个易混淆点:

1、 bind 将apply函数中 this替换为 bind的入参 Array.prototype.slice, 这个在绑定的时刻即执行。

2、 apply生效,将Array.prototype.slice函数中 this替换为arguments,并执行, 这个在slice被调用阶段执行。

3、 例子当中的 bind之后的参数名称, slice为按照应用场景命名, 实际上此名称应该是 sliceBoundApply,即实际上它函数体还是Function.prototype.apply的代码,只不过 Function.prototype.apply代码中的this固定为一个函数 Array.prototype.slice, 那么 sliceBoundApply  === Array.prototype.slice.apply (apply函数中的this指代Array.prototype.slice,因为是Array.prototype.slice对象调用了apply)

所以 sliceBoundApply(obj) ===  Array.prototype.slice.apply (obj)

通篇出现两种情况的绑定: 1、 被绑定函数中,将this作为Object使用, 则绑定的目标为Object,如”函数绑定到对象例子” 2、被绑定函数中,将this作为函数使用, 则绑定的目标为Function, 如“创建快捷方式”

绑定前后一图明义:

Function.prototype.bind接口浅析的更多相关文章

  1. 浅析 JavaScript 中的 Function.prototype.bind() 方法

    Function.prototype.bind()方法 bind() 方法的主要作用就是将函数绑定至某个对象,bind() 方法会创建一个函数,函数体内this对象的值会被绑定到传入bind() 函数 ...

  2. 一起Polyfill系列:Function.prototype.bind的四个阶段

    昨天边参考es5-shim边自己实现Function.prototype.bind,发现有不少以前忽视了的地方,这里就作为一个小总结吧. 一.Function.prototype.bind的作用 其实 ...

  3. JavaScript 函数绑定 Function.prototype.bind

    ECMAScript Edition5 IE9+支持原生,作用为将一个对象的方法绑定到另一个对象上执行. Function.prototype.bind = Function.prototype.bi ...

  4. Function.prototype.bind

    解析Function.prototype.bind 简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. b ...

  5. 解析Function.prototype.bind

    简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. bind的作用 bind最直接的作用就是改变this的 ...

  6. javascript Function.prototype.bind

    语法: fn.bind(obj,arg1,arg2,arg3...) bind是es5新增的方法,顾名思义,它的作用是将函数绑定到某个对象上,就像是某个对象调用方法一样.其本质还是改变了该函数的上下文 ...

  7. 理解javascript中的Function.prototype.bind

    在初学Javascript时,我们也许不需要担心函数绑定的问题,但是当我们需要在另一个函数中保持上下文对象this时,就会遇到相应的问题了,我见过很多人处理这种问题都是先将this赋值给一个变量(比如 ...

  8. 理解 JavaScript 中的 Function.prototype.bind

    函数绑定(Function binding)很有可能是你在开始使用JavaScript时最少关注的一点,但是当你意识到你需要一个解决方案来解决如何在另一个函数中保持this上下文的时候,你真正需要的其 ...

  9. prototype.js中Function.prototype.bind方法浅解

    prototype.js中的Function.prototype.bind方法: Function.prototype.bind = function() { var __method = this; ...

随机推荐

  1. VMware 虚拟机使用 NAT 方式联网

    选择要设置的虚拟主机: 点击右键,选择 “属性”,查看 “网络适配器”: 此时选择的连接方式是 “Host-only”,在 Host-only 模式中,所有的虚拟系统是可以相互通信的,但虚拟系统和真实 ...

  2. Redis 笔记与总结1 安装部署

    NoSQL 使用场景: 1.对数据高并发读写 2.对海量数据的高效率存储和访问 3.对数据的高可扩展性和高可用性 Redis 通常被称为数据结构服务器,因为键可以包含字符串(strings).哈希(h ...

  3. 西川善司【神秘海域(Uncharted)】的图形分析

          本文是为传播0月8日发售的[神秘海域 合集]魅力而短篇连载的第2回,这次主要集中在神秘海域系列的图形的技术方面.原文链接在 http://weekly.ascii.jp/elem/000/ ...

  4. Scrapy入门教程

    关键字:scrapy 入门教程 爬虫 Spider作者:http://www.cnblogs.com/txw1958/出处:http://www.cnblogs.com/txw1958/archive ...

  5. Java中方法的覆写

    所谓方法的覆写override就是子类定义了与父类中同名的方法,但是在方法覆写时必须考虑权限,即被子类覆写的方法不能拥有比父类方法更加严格的访问权限. 修饰符分别为public.protected.d ...

  6. Peeking into Apache Flink's Engine Room

    http://flink.apache.org/news/2015/03/13/peeking-into-Apache-Flinks-Engine-Room.html   Join Processin ...

  7. 迷宫dfs

    #include<stdio.h>int mov1[4]={0,0,1,-1};int mov2[4]={1,-1,0,0};int map[5][5]={0,1,0,0,1,      ...

  8. JAVA中的throws和throw的区别

    Java     一直对java中的throws和throw不太理解.最近一直在查这两个方面的资料,算是能明白一点吧.如果我下面的观点哪有不对,希望指出来,我加以改进.         throw:( ...

  9. WIN10 ANDROIDSTUDIO1.2 安装完首次启动报错

    环境 ACER NOTEBOOK  WIN10 ANNDROID 1.2 解决方案: 在Android Studio安装目录下的 bin 目录下,找到 idea.properties 文件,在文件最后 ...

  10. USB2.0协议笔记

    1.概述     USB(Universal Serial Bus)具有传输速率快,可热插拔等显著特点,应用已经十分广泛,目前的相当多的设备已经支持最新的USB3.0协议.理论上USB1.1的传输速度 ...