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

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

一、apply和call

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

<div id="test"></div>
<script>
var getDom = document.getElementById;
console.log(getDom("test"))
</script>

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

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

<div id="test"></div>
<script>
var getDom = (function(func){
return function(){
return func.apply(document , arguments);
}
})(document.getElementById);
console.log(getDom("test"))
</script>

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

二、bind基本

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

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

接下来用demo简单使用下

1、单纯的绑定this

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

这样用法比较简单

2、传参数的形式

var self = {name : "sky" , age: 26}
var getDescription = function(country , city){
console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
}.bind(self , "China");
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则可以换一种方式,具体对比如下:

<div id="test1">test1</div>
<div id="test2">test2</div>
<script>
//旧写法,使用_this保存
var tool1 = {
name: "sky1",
bindEvent: function() {
var _this = this;
document.getElementById("test1").addEventListener("click", function() {
console.log(_this.name)
}, false)
}
}
//新写法,使用bind绑定
var tool2 = {
name: "sky2",
bindEvent: function() {
document.getElementById("test2").addEventListener("click", function() {
console.log(this.name)
}.bind(this), false)
}
}
tool1.bindEvent();
tool2.bindEvent();
</script>

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

四、bind 兼容性

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

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

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

Function.prototype.skyBind = function(context){
var func = this; //就是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
return function(){
return func.apply(context , arguments); //绑定且执行
}
}
var person1 = {
name : "sky" ,
getName : function(){
return this.name;
}
}
var person2 = {name : "moon"};
var getName = person1.getName.skyBind(person2);
console.log(getName()); //打印的值为moon

很简单有没有!!!

2、加入传参的功能

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

    关于http协议GET和POST方法的区别我们可以从各处得到比较一致的答案,今天我们来填一个面试中可能碰到的一个坑. 当面试官问你“你觉得GET和POST有什么区别"时,我们可能会想到以下几 ...

  2. begoo——对象的CRUD操作

    如果已知主键的值,那么可以使用这些方法进行CRUD操作 对object操作的四个方法Read/Insert/Update/Delete o := orm.NewOrm() user := new(Us ...

  3. 解释一下python中的逻辑运算符

    python中有三个逻辑运算符:and.or.not print(False and True)#False print(7<7 or True)#True print(not 2==2)#Fa ...

  4. javac是啥

    javac是java语言编程编译器.全称java compiler. javac工具读有java语言编写的类和接口的定义,并将它们编译成字节代码的class文件.

  5. java GC 回收机制 转

    JVM分代垃圾回收策略的基础概念 由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分代这一策略.本文介绍了分代策略的目标,如何分代,以及垃圾回收的触发因素. 文章总结了JVM垃圾回收策略为 ...

  6. Spring 之通过 Java 代码装配 bean

    [关于IoC的几点认识] 1.面向接口编程 --> 每层只向上层提供接口 2.inversion of control (IoC)  -->参考百度百科 3.DI是IoC的一种实现方式 [ ...

  7. 【Flask】Flask-Migrate基本使用

    # flask_migrate笔记:在实际的开发环境中,经常会发生数据库修改的行为.一般我们修改数据库不会直接手动的去修改,而是去修改ORM对应的模型,然后再把模型映射到数据库中.这时候如果有一个工具 ...

  8. JavaWeb 自定义标签库开发传统标签

    自定义标签主要用于移除Jsp页面中的java代码. 移除jsp页面中的java代码,只需要完成两个步骤: 编写一个实现Tag接口的Java类,并覆盖doStartTag方法,把jsp页面中的java代 ...

  9. Java数据类型——面试题

    1.short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 +=1;有什么错? 答:对于short s1=1;s1=s1+1来说,在s1+1运算时会自动提升表 ...

  10. Kruskal算法-最小生成树

    2017-07-26  10:32:07 writer:pprp Kruskal算法是根据边的加权值以递增的方式,一次找出加权值最低的边来建最小生成树:并且每次添加的边不能造成生成树有回路,直到找到N ...