深入理解JS中的Function.prototype.bind()方法


Posted in Javascript onOctober 11, 2016

前言

对于函数绑定(Function binding)很有可能是大家在使用JavaScript时最少关注的一点,但是当你意识到你需要一个解决方案来解决如何在另一个函数中保持this上下文的时候,你真正需要的其实就是 Function.prototype.bind() ,只是你有可能仍然没有意识到这点。

第一次遇到这个问题的时候,你可能倾向于将this设置到一个变量上,这样你可以在改变了上下文之后继续引用到它。

一. bind的语法

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

1.1 定义

bind()的定义如下:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体。当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。

1.2 原理

可以用如下代码模拟bind()的原理:

Function.prototype.bind = function(context) {
 var self = this; // 保存原函数
 return function() { // 返回一个新函数
  return self.apply(context, arguments); // 执行新函数时,将传入的上下文context作为新函数的this
 }
}

1.3 语法

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])

二. bind的应用场景

2.1 实现对象继承

var A = function(name) {
 this.name = name;
}

var B = function() {
 A.bind(this, arguments);
}

B.prototype.getName = function() {
 return this.name;
}

var b = new B("hello");
console.log(b.getName()); // "hello"

2.2 事件处理

var paint = {
 color: "red",
 count: 0,
 updateCount: function() {
  this.count++;
  console.log(this.count);
 }
};

// 事件处理函数绑定的错误方法:
document.querySelector('button')
 .addEventListener('click', paint.updateCount); // paint.updateCount函数的this指向变成了该DOM对象

// 事件处理函数绑定的正确方法:
document.querySelector('button')
 .addEventListener('click', paint.updateCount.bind(paint)); // paint.updateCount函数的this指向变成了paint

2.3 时间间隔函数

var notify = {
 text: "Hello World!",
 beforeRender: function() {
  alert(this.text);
 },
 render: function() {

  // 错误方法:
  setTimeout(this.beforeRender, 0); // undefined

  // 正确方法:
  setTimeout(this.beforeRender.bind(this), 0); // "Hello World!"
 }
};

notify.render();

2.4 借用Array的原生方法

var a = {};
Array.prototype.push.bind(a, "hello", "world")();

console.log(a); // "hello", "world"

三. bind()方法的浏览器兼容性

深入理解JS中的Function.prototype.bind()方法

四. bind()的兼容性写法

if (!Function.prototype.bind) {
 Function.prototype.bind = function() {
  var self = this, // 保存原函数
   context = [].shift.call(arguments), // 需要绑定的this上下文
   args = [].slice.call(arguments); // 剩余的参数转成数组
  return function() { // 返回一个新函数
   // 执行新函数时,将传入的上下文context作为新函数的this
   // 并且组合两次分别传入的参数,作为新函数的参数
   return self.apply(context, [].concat.call(args, [].slice.call(arguments))); 
  }
 };
}

五. bind与 call/apply方法的区别

共同点:

都可以改变函数执行的上下文环境;

不同点:

bind: 不立即执行函数,一般用在异步调用和事件; call/apply: 立即执行函数。

总结

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用Javascript能有一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
JAVASCRIPT实现的WEB页面跳转以及页面间传值方法
May 13 Javascript
jquery加载页面的方法(页面加载完成就执行)
Jun 21 Javascript
JavaScript制作简易的微信打飞机
Mar 31 Javascript
JavaScript简单遍历DOM对象所有属性的实现方法
Oct 21 Javascript
基于原生js淡入淡出函数封装(兼容IE)
Oct 20 Javascript
微信公众号支付H5调用支付解析
Nov 04 Javascript
利用babel将es6语法转es5的简单示例
Dec 01 Javascript
微信小程序登录换取token的教程
May 31 Javascript
微信小程序中上传图片并进行压缩的实现代码
Aug 28 Javascript
vue-cli 3.x 配置Axios(proxyTable)跨域代理方法
Sep 19 Javascript
原生JS实现轮播图效果
Oct 12 Javascript
JavaScript面向对象程序设计中对象的定义和继承详解
Jul 29 Javascript
Bootstrap轮播插件使用代码
Oct 11 #Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
Oct 11 #Javascript
JavaScript获取URL中参数querystring的方法详解
Oct 11 #Javascript
JS实现表单验证功能(验证手机号是否存在,验证码倒计时)
Oct 11 #Javascript
Node.js的环境安装配置(使用nvm方式)
Oct 11 #Javascript
javascript 动态样式添加的简单实现
Oct 11 #Javascript
表单input项使用label同时引用Bootstrap库导致input点击效果区增大问题
Oct 11 #Javascript
You might like
PHP 时间日期操作实战
2011/08/26 PHP
PDO版本问题 Invalid parameter number: no parameters were bound
2013/01/06 PHP
php实现的发送带附件邮件类实例
2014/09/22 PHP
使用PHP uniqid函数生成唯一ID
2015/11/18 PHP
PHP图形计数器程序显示网站用户浏览量
2016/07/20 PHP
浅析JavaScript基本类型与引用类型
2014/05/28 Javascript
javascript 寻找错误方法整理
2014/06/15 Javascript
javascript简单实现类似QQ头像弹出效果的方法
2015/08/03 Javascript
Bootstrap风格的zTree右键菜单
2017/02/17 Javascript
vuejs响应用户事件(如点击事件)
2017/03/14 Javascript
详解A标签中href=""的几种用法
2017/08/20 Javascript
Angular4.x通过路由守卫进行路由重定向实现根据条件跳转到相应的页面(推荐)
2018/05/10 Javascript
Node.js 获取微信JS-SDK CONFIG的方法示例
2019/05/21 Javascript
vue-router跳转时打开新页面的两种方法
2019/07/29 Javascript
[04:44]显微镜下的DOTA2第二期——你所没有注意到的细节
2014/06/20 DOTA
[40:56]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Liquid vs TNC
2018/04/01 DOTA
[01:21]2018DOTA2亚洲邀请赛4.5采访 打DOTA2也能有女朋友?
2018/04/06 DOTA
Python代理抓取并验证使用多线程实现
2013/05/03 Python
利用Python的Twisted框架实现webshell密码扫描器的教程
2015/04/16 Python
python实现井字棋游戏
2020/03/30 Python
python实现在遍历列表时,直接对dict元素增加字段的方法
2019/01/15 Python
opencv实现静态手势识别 opencv实现剪刀石头布游戏
2019/01/22 Python
Python如何应用cx_Oracle获取oracle中的clob字段问题
2019/08/27 Python
tensorflow实现残差网络方式(mnist数据集)
2020/05/26 Python
萌新的HTML5 入门指南
2020/11/06 HTML / CSS
美国职棒大联盟官方网上商店:MLBShop.com
2017/11/12 全球购物
英国假发网站:Hothair
2018/02/23 全球购物
加拿大床上用品、家居装饰、厨房和浴室产品购物网站:Linen Chest
2018/06/05 全球购物
英国领先的独立时装店:Van Mildert
2019/10/28 全球购物
美国沃尔玛网上超市:Walmart
2020/08/14 全球购物
活动倡议书范文
2014/05/13 职场文书
关于建议书的格式范文
2014/05/20 职场文书
端午节活动总结
2014/08/26 职场文书
2014年街道办事处工作总结
2014/12/11 职场文书
西安大雁塔导游词
2015/02/10 职场文书
2015年班干部工作总结
2015/04/29 职场文书