深入理解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 相关文章推荐
IE 当eval遇上function的处理
Aug 09 Javascript
jQuery旋转插件—rotate支持(ie/Firefox/SafariOpera/Chrome)
Jan 16 Javascript
一个支付页面DEMO附截图
Jul 22 Javascript
Javascript核心读书有感之类型、值和变量
Feb 11 Javascript
JavaScript中Function详解
Feb 27 Javascript
js通过iframe加载外部网页的实现代码
Apr 05 Javascript
JavaScript中window.open用法实例详解
Apr 15 Javascript
javascript中eval函数用法分析
Apr 25 Javascript
JS数组返回去重后数据的方法解析
Jan 03 Javascript
jQuery Ajax全解析
Feb 13 Javascript
详解vuex数据传输的两种方式及this.$store undefined的解决办法
Aug 26 Javascript
vue之组件内监控$store中定义变量的变化详解
Nov 08 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
zf框架的校验器使用使用示例(自定义校验器和校验器链)
2014/03/13 PHP
yii2 数据库读写分离配置示例
2017/02/10 PHP
php中目录操作opendir()、readdir()及scandir()用法示例
2019/06/08 PHP
ASP.NET jQuery 实例14 在ASP.NET form中校验时间范围
2012/02/03 Javascript
js写出遮罩层登陆框和对联广告并自动跟随滚动条滚动
2014/04/29 Javascript
jQuery实现tab标签自动切换的方法
2015/02/28 Javascript
使用js复制链接中的部分文字的方法
2015/07/30 Javascript
web 前端常用组件之Layer弹出层组件
2016/09/22 Javascript
Angular表单验证实例详解
2016/10/20 Javascript
Vue.js如何实现路由懒加载浅析
2017/08/14 Javascript
angular 组件通信的几种实现方式
2018/07/13 Javascript
解决vue中post方式提交数据后台无法接收的问题
2018/08/11 Javascript
深入理解Vue父子组件生命周期执行顺序及钩子函数
2018/08/12 Javascript
在 Vue 应用中使用 Netlify 表单功能的方法详解
2019/06/03 Javascript
JavaScript定时器使用方法详解
2020/03/26 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
[49:58]完美世界DOTA2联赛PWL S3 Magma vs DLG 第一场 12.18
2020/12/19 DOTA
Python3 入门教程 简单但比较不错
2009/11/29 Python
跟老齐学Python之做一个小游戏
2014/09/28 Python
Python实现竖排打印传单手机号码易撕条
2015/03/16 Python
详解Python操作RabbitMQ服务器消息队列的远程结果返回
2016/06/30 Python
OpenCV2.3.1+Python2.7.3+Numpy等的配置解析
2018/01/05 Python
python requests post多层字典的方法
2018/12/27 Python
PyCharm安装Markdown插件的两种方法
2019/06/24 Python
基于python实现学生信息管理系统
2019/11/22 Python
Python一行代码解决矩阵旋转的问题
2019/11/30 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
2020/06/24 Python
Python是怎样处理json模块的
2020/07/16 Python
CSS3使用多列制作瀑布流
2016/05/10 HTML / CSS
Html5移动端获奖无缝滚动动画实现示例
2018/06/25 HTML / CSS
CAT鞋加拿大官网:CAT Footwear加拿大
2020/08/05 全球购物
党的群众路线教育实践活动党员个人剖析材料
2014/10/08 职场文书
2016年公共机构节能宣传周活动总结
2016/04/05 职场文书
详解PHP服务器如何在有限的资源里最大提升并发能力
2021/05/25 PHP
解决pycharm下载库时出现Failed to install package的问题
2021/09/04 Python
详解PyTorch模型保存与加载
2022/04/28 Python