最近去参加了场面试,跟面试官聊了很多JS基础上的东西,其中有个问题是谈谈对apply、call、bind的理解和区别。顿时一愣,apply、call我知道,经常用的东西,bind是什么鬼!!!好像见过,也瞅过类似的文章,但是...不记得了...难道和jQuery的事件绑定的bind一样...

  既然不知道,那就整理总结下啰~

一、apply和call

  既然提到提到了这两兄弟,也跟着简单做下知识整理。在javascript中,this的指向是一个经常要处理的问题。比较经典的一个问题就是,document.getElementById太长了,敲着好累好烦,用一个短点的方法,对它进行封装一下,就下面这样,两行代码搞定,多么简单~

  1. <div id="test"></div>
  2. <script>
  3. var getDom = document.getElementById;
  4. console.log(getDom("test"))
  5. </script>

但是。。。调用时,系统提示Uncaught TypeError: Illegal invocation 啊..........这是什么鬼错误 !其实这就是this的问题,使用document.getElementById,函数执行时this指向document,但是使用getDom,函数执行时,this指向的是window。而在getElementById在内核实现中又使用了this,so 就报错了啰!!!

正确的封装方式为:(即用apply/call设定下函数调用时的this指向)

  1. <div id="test"></div>
  2. <script>
  3. var getDom = (function(func){
  4. return function(){
  5. return func.apply(document , arguments);
  6. }
  7. })(document.getElementById);
  8. console.log(getDom("test"))
  9. </script>

  总结:apply和call的用法是一致的,就是改变和确定函数执行时的this指向,区别就是apply后一个参数是数组,call后是一堆参数。话不多说,进入正题....

二、bind基本

首先来谈谈它跟apply/call的区别,bind方法返回的是一个函数,不会立即执行,待用()调用时才会执行,而apply/call则是立即执行函数。

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

接下来用demo简单使用下

1、单纯的绑定this

  1. var person1 = {
  2. name : "sky" ,
  3. getName : function(){
  4. return this.name;
  5. }
  6. }
  7. var person2 = {name : "moon"};
  8. var getName = person1.getName.bind(person2); //绑定person2作为getName函数执行的this
  9. console.log(getName()); //打印的值为moon

这样用法比较简单

2、传参数的形式

  1. var self = {name : "sky" , age: 26}
  2. var getDescription = function(country , city){
  3. console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
  4. }.bind(self , "China");
  5. getDescription("WuHan"); //my name is sky , my age is 26 , I'am from China WuHan

个人感觉,这种就是相当于通过bind方法预设一些参数,比如此时就是预设的country参数,调用时在传递动态的参数,比如这里的WuHan。通过这样的方式绑定this,配合预设参数,灵活程度十分的高

三、bind的使用场景

水平有限,仅谈谈个人。我在多层函数嵌套的代码编写中,喜欢使用var _this = this;来保存上级函数作用域中的this,这样在内嵌的函数中就是可以用_this获取上级作用域的this。如果用bind则可以换一种方式,具体对比如下:

  1. <div id="test1">test1</div>
  2. <div id="test2">test2</div>
  3. <script>
  4. //旧写法,使用_this保存
  5. var tool1 = {
  6. name: "sky1",
  7. bindEvent: function() {
  8. var _this = this;
  9. document.getElementById("test1").addEventListener("click", function() {
  10. console.log(_this.name)
  11. }, false)
  12. }
  13. }
  14. //新写法,使用bind绑定
  15. var tool2 = {
  16. name: "sky2",
  17. bindEvent: function() {
  18. document.getElementById("test2").addEventListener("click", function() {
  19. console.log(this.name)
  20. }.bind(this), false)
  21. }
  22. }
  23. tool1.bindEvent();
  24. tool2.bindEvent();
  25. </script>

怎么说呢,代码看起来更加优美一些把....我是颜值控

四、bind 兼容性

bind方法是ES5中扩展的方法,所以IE6、7、8均不兼容...整个人都不好了

怎么办呢,网上有一堆的兼容资料,我比较喜欢自己造轮子...其实也蛮简单的,就是apply/call的封装使用,学习嘛,循序渐进的来,分成两步,以下均用skyBind方法表示...

1、仅仅实现修改执行环境即this的功能

  1. Function.prototype.skyBind = function(context){
  2. var func = this; //就是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
  3. return function(){
  4. return func.apply(context , arguments); //绑定且执行
  5. }
  6. }
  7. var person1 = {
  8. name : "sky" ,
  9. getName : function(){
  10. return this.name;
  11. }
  12. }
  13. var person2 = {name : "moon"};
  14. var getName = person1.getName.skyBind(person2);
  15. console.log(getName()); //打印的值为moon

很简单有没有!!!

2、加入传参的功能

  1. Function.prototype.skyBind = function(){
  2. var func = this , //还是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
  3. context = [].shift.call(arguments) , //此时传入的参数就不单单有this的指向,还是其他的参数,按规定第一个参数就是执行环境,拿到它
  4. args = [].slice.call(arguments); //arguments具有数组的属性,毕竟JS是个弱类型的语言,但是它毕竟不是数组,用这个方法就是把arguments转换成数组,不用slice换成splice或者其他的都行
  5. return function(){
  6. /* 绑定且执行,执行函数的参数为两个数组的合并
  7. * 这里需要解释的是args是bind绑定时传入的参数,比如下面demo中的China,而下面的arguments则是实际调用时传入的参数WuHan
  8. * */
  9. return func.apply(context , [].concat(args , [].slice.call(arguments) ));
  10. }
  11. }
  12. //demo
  13. var self = {name : "sky" , age: 26}
  14. var getDescription = function(country , city){
  15. console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
  16. }.skyBind(self , "China");
  17. getDescription("WuHan"); //my name is sky , my age is 26 , I'am from China WuHan

搞定!!!

  

简要谈谈javascript bind 方法的更多相关文章

  1. 谈谈javascript数组排序方法sort()的使用,重点介绍参数使用及内部机制?

    语法:arrayObject.sort(sortby) 参数sortby可选,规定排序顺序,必须是函数: 注:如果调用该方法时没有使用参数,将按字符编码的顺序进行排序,要实现这一点,首先应把数组的元素 ...

  2. Javascript中call,apply,bind方法的详解与总结

    在 javascript之 this 关键字详解 文章中,谈及了如下内容,做一个简单的回顾: 1.this对象的涵义就是指向当前对象中的属性和方法. 2.this指向的可变性.当在全局作用域时,thi ...

  3. 如何在JavaScript中正确引用某个方法(bind方法的应用)

    在JavaScript中,方法往往涉及到上下文,也就是this,因此往往不能直接引用,就拿最常见的console.log("info…")来说,避免书写冗长的console,直接用 ...

  4. javascript中函数的call,apply及bind方法

    call 方法调用一个对象的一个方法,以另一个对象替换当前对象.call([thisObj[,arg1[, arg2[,  [,.argN]]]]])参数thisObj可选项.将被用作当前对象的对象. ...

  5. 《JavaScript总结》apply、call和bind方法

    在JavaScript中,apply.call.bind这个三个方法,它们的作用都是为了改变某个函数运行时的上下文, 也就是改变函数体内的this指向. 在一个函数里,存在“定义时上下文”.“运行时上 ...

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

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

  7. javascript原生bind方法详解

    bind()方法,是javascript原生的函数类的一个原型方法(即Function.prototype里的方法),不支持ie低版本. 基本格式: function.bind(obj1,obj2,o ...

  8. JavaScript中的call、apply、bind方法的区别

    在JavaScript 中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以我们需要一种可以把this的含义固定的技术,于是就有了call,apply 和bind这 ...

  9. javascript原生bind方法ie低版本兼容详解

    上一篇文章讲到了javascript原生的bind方法: http://www.cnblogs.com/liulangmao/p/3451669.html 这篇文章就在理解了原生bind方法的原理以后 ...

随机推荐

  1. Mycat教程---数据库的分库分表

    mycat介绍 介绍在官方网站上有比较详细的介绍,在这里复制粘贴没什么意思,大家到官网上看 官网链接 前置条件 本教程是在window环境下运行的,实际生产推荐在Linux上运行. 必备条件(自行安装 ...

  2. Hadoop集群的配置的主机和IP

    集群配置如下: hadoop        192.168.80.100 hadoop1      192.168.80.101 hadoop2      192.168.80.102   (注:ha ...

  3. SqlAlchemy基本

    安装SQLAlchemy: $ easy_install sqlalchemy 数据库表是一个二维表,包含多行多列 [ ('1', 'Michael'), ('2', 'Bob'), ('3', 'A ...

  4. TRegExpr正则表达式

    TRegExpr正则表达式 2006-10-24 10:55 DELPHi中的REGEXPR   [ 2006-03-29 11:33:46 am | Author: Admin ] 其实这个Pasc ...

  5. python 测试代码

    1.使用print()打印 测试代码最简单的就是添加一些print()语句.然而产品开发中,需要记住自己添加的所有print()语句并在最后删除,很容易出现失误. 2.使用pylint.pyflake ...

  6. 特别好用的swagger ui 封装

    Swagger简单介绍 Swagger是一个Restful风格接口的文档在线自动生成和测试的框架 官网:http://swagger.io 官方描述:The World’s Most Popular ...

  7. Java8中时间日期库的20个常用使用示例

    除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务示例来学习如何使用Java 8的这套API.Java对日期, ...

  8. redis 笔记05 Sentinel、集群

    Sentinel 1. Sentinel只是一个运行在特殊模式下的Redis服务器,它使用了和普通模式不同的命令表,所以Sentinel模式能够使用的命令和普通的Redis服务器能够使用的命令不同. ...

  9. jmeter之报告和分析

    转载:http://www.cnblogs.com/miaomiaokaixin/p/6118081.html jmeter -n -t 脚本名字.jmx -l xxx.jtl -e -o 指定目录( ...

  10. MySQL-5.7创建及查看数据库表

    1.创建数据库表的三种语句 创建一个新表: CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [tab ...