深入理解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 相关文章推荐
JS实现打开本地文件或文件夹
Mar 09 Javascript
Ctrl+Enter提交内容信息
Jun 26 Javascript
jQuery帮助之CSS尺寸(五)outerHeight、outerWidth
Nov 14 Javascript
js 格式化时间日期函数小结
Mar 20 Javascript
基于jQuery的获得各种控件Value的方法
Nov 19 Javascript
Bootstrap每天必学之导航
Nov 26 Javascript
JS组件Bootstrap Table布局详解
May 27 Javascript
javascript 中iframe高度自适应(同域)实例详解
May 16 Javascript
webpack配置导致字体图标无法显示的解决方法
Mar 06 Javascript
Less 安装及基本用法
May 05 Javascript
js input输入百分号保存数据库失败的解决方法
May 26 Javascript
Vue常用API、高级API的相关总结
Feb 02 Vue.js
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 getsiteurl()函数
2009/09/05 PHP
php控制linux服务器常用功能 关机 重启 开新站点等
2012/09/05 PHP
简单理解PHP的面向对象编程方式
2016/05/17 PHP
PHP生成各种随机验证码的方法总结【附demo源码】
2017/06/05 PHP
laravel csrf排除路由,禁止,关闭指定路由的例子
2019/10/21 PHP
TP5框架安全机制实例分析
2020/04/05 PHP
js 上传图片预览问题
2010/12/06 Javascript
JavaScript中valueOf函数与toString方法深入理解
2012/12/02 Javascript
js冒泡法和数组转换成字符串示例代码
2013/08/14 Javascript
javascript的parseFloat()方法精度问题探讨
2013/11/26 Javascript
Javascript限制网页只能在微信内置浏览器中访问
2014/11/09 Javascript
js验证上传图片的方法
2015/05/12 Javascript
BootStrap实用代码片段之一
2016/03/22 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
2016/04/18 Javascript
JS在Chrome浏览器中showModalDialog函数返回值为undefined的解决方法
2016/08/03 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
React入门教程之Hello World以及环境搭建详解
2017/07/11 Javascript
javascript填充默认头像方法
2018/02/22 Javascript
axios 封装上传文件的请求方法
2018/09/26 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
VUE项目中加载已保存的笔记实例方法
2019/09/14 Javascript
vue3实现v-model原理详解
2019/10/09 Javascript
vue项目中常见问题及解决方案(推荐)
2019/10/21 Javascript
json_decode 索引为数字时自动排序问题解决方法
2020/03/28 Javascript
在vue中使用Echarts利用watch做动态数据渲染操作
2020/07/20 Javascript
python3 读取Excel表格中的数据
2018/10/16 Python
pycharm中使用anaconda部署python环境的方法步骤
2018/12/19 Python
Python使用matplotlib 画矩形的三种方式分析
2019/10/31 Python
Python连接mysql数据库及简单增删改查操作示例代码
2020/08/03 Python
澳大利亚网上买书:Angus & Robertson
2019/07/21 全球购物
什么是动态端口(Dynamic Ports)?动态端口的范围是多少?
2014/12/12 面试题
个人找工作自荐信格式
2013/09/21 职场文书
手把手教你用SpringBoot将文件打包成zip存放或导出
2021/06/11 Java/Android
聊聊SpringBoot自动装配的魔力
2021/11/17 Java/Android
详解MySql中InnoDB存储引擎中的各种锁
2022/02/12 MySQL
深入浅出的讲解:信号调制到底是如何实现的
2022/02/18 无线电