js 里函数调用有 4 种模式:方法调用、正常函数调用、构造器函数调用、apply/call 调用。

同时,无论哪种函数调用除了你声明时定义的形参外,还会自动添加 2 个形参,分别是 this 和arguments。

arguments 不涉及到上述 3 个函数,所以这里只谈 this。this 的值,在上面 4 中调用模式下,分别会绑定不同的值。分别来说一说:

方法调用:

这个很好理解,函数是一个对象的属性,比如

  1. var a = {
  2. v : 0,
  3. f : function(xx) {
  4. this.v = xx;
  5. }
  6. }
  7. a.f(5);

这个时候,上面函数里的 this 就绑定的是这个对象 a。所以 this.v 可以取到对象 a 的属性 v。

正常函数调用:依然看代码

  1. function f(xx) {
  2. this.x = xx;
  3. }
  4. f(5);

这个时候,函数 f 里的 this 绑定的是全局对象,如果是在浏览器运行的解释器中,一般来说是 window 对象。所以这里 this.x 访问的其实是 window.x ,当然,如果 window 没有 x 属性,那么你这么一写,按照 js 的坑爹语法,就是给 window 对象添加了一个 x 属性,同时赋值。

构造器函数调用:

构造函数一直是我认为是 js 里最坑爹的部分,因为它和 js 最初设计的基于原型的面向对象实现方式格格不入,就好像是特意为了迎合大家已经被其他基于类的面相对象实现给惯坏了的习惯。

如果你在一个函数前面带上 new 关键字来调用,那么 js 会创建一个 prototype 属性是此函数的一个新对象,同时在调用这个函数的时候,把 this 绑定到这个新对象上。当然 new 关键字也会改变return 语句的行为,不过这里就不谈了。看代码

  1. function a(xx)
  2. {
  3. this.m = xx;
  4. }
  5. var b = new a(5);

上面这个函数和正常调用的函数写法上没什么区别,只不过在调用的时候函数名前面加了关键字 new罢了,这么一来,this 绑定的就不再是前面讲到的全局对象了,而是这里说的创建的新对象,所以说这种方式其实很危险,因为光看函数,你不会知道这个函数到底是准备拿来当构造函数用的,还是一般函数用的。所以我们可以看到,在 jslint 里,它会要求你写的所有构造函数,也就是一旦它发现你用了 new 关键字,那么后面那个函数的首字母必须大写,这样通过函数首字母大写的方式来区分,我个人只有一个看法:坑爹:)

apply/call 调用:

我们知道,在 js 里,函数其实也是一个对象,那么函数自然也可以拥有它自己的方法,有点绕,在js 里,每个函数都有一个公共的 prototype —— Function,而这个原型自带有好几个属性和方法,其中就有这里困惑的 bind、call、apply 方法。先说 apply 方法,它让我们构造一个参数数组传递给函数,同时可以自己来设置 this 的值,这就是它最强大的地方,上面的 3 种函数调用方式,你可以看到,this 都是自动绑定的,没办法由你来设,当你想设的时候,就可以用 apply()了。apply 函数接收 2 个参数,第一个是传递给这个函数用来绑定 this 的值,第二个是一个参数数组。

看代码

  1. function a(xx) {
  2. this.b = xx;
  3. }
  4. var o = {};
  5. a.apply(o, [5]);
  6. alert(a.b);    // undefined
  7. alert(o.b);    // 5

是不是很神奇,函数 a 居然可以给 o 加属性值。当然,如果你 apply 的第一个参数传递 null,那么在函数 a 里面 this 指针依然会绑定全局对象。

call() 方法和 apply() 方法很类似,它们的存在都是为了改变 this 的绑定,那 call() 和apply() 有什么区别呢?就我个人看来,没啥鸟区别。。。开玩笑!刚刚说了,上面 apply() 接收两个参数,第一个是绑定 this 的值,第二个是一个参数数组,注意它是一个数组,你想传递给这个函数的所有参数都放在数组里,然后 apply() 函数会在调用函数时自动帮你把数组展开。而 call()呢,它的第一个参数也是绑定给 this 的值,但是后面接受的是不定参数,而不再是一个数组,也就是说你可以像平时给函数传参那样把这些参数一个一个传递。

所以如果一定要说有什么区别的话,看起来是这样的

  1. function a(xx, yy) {
  2. alert(xx, yy);
  3. alert(this);
  4. alert(arguments);
  5. }
  6. a.apply(null, [5, 55]);
  7. a.call(null, 5, 55);

仅此而已。

最后再来说 bind() 函数,上面讲的无论是 call() 也好, apply() 也好,都是立马就调用了对应的函数,而 bind() 不会, bind() 会生成一个新的函数,bind() 函数的参数跟 call() 一致,第一个参数也是绑定 this 的值,后面接受传递给函数的不定参数。 bind() 生成的新函数返回后,你想什么时候调就什么时候调,看下代码就明白了

  1. var m = {
  2. "x" : 1
  3. };
  4. function foo(y) {
  5. alert(this.x + y);
  6. }
  7. foo.apply(m, [5]);
  8. foo.call(m, 5);
  9. var foo1 = foo.bind(m, 5);
  10. foo1();

末了来个吐槽,你在 js 里想定义一个函数,于是你会这么写:

  1. 1function jam() {};

其实这是 js 里的一种语法糖,它等价于:

  1. var jam = function() {};

然后你想执行这个函数,脑洞大开的你会这么写:

  1. function jam() {}();

但是这么写就报错了,其实这种写法也不算错,因为它确实是 js 支持的函数表达式,但是同时 js 又规定以function 开头的语句被认为是函数语句,而函数语句后面是肯定不会带 () 的,所以才报错,于是聪明的人想出来,加上一对括号就可以了。于是就变成了这样:

1(function jam() {}());

这样就定义了一个函数同时也执行它,详情参加 ECMAScript  Expression Statement 章节。

Javascript中bind、call、apply函数用法的更多相关文章

  1. 面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗

    一.前言    不知道大家还记不记得前几篇的文章:<面试官:能解释一下javascript中的this吗> 那今天这篇文章虽然是介绍javascript中bind.apply和call函数 ...

  2. Javascript中call、apply函数浅析

    call/apply函数作用其实就是改变this的取值,有一句话是:谁调用的这个方法那方法里的this就是指谁,而有时我们会需要改变this值,所以call/apply就能派上用场. 下面我写个方法来 ...

  3. Javascript中call()和apply()的用法 ----2

    前言 call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向.call 和 apply二者的作用完全一样,只是接受 ...

  4. Javascript中call()和apply()的用法 ----1

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  5. 博文推荐】Javascript中bind、call、apply函数用法

    [博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...

  6. javascript中this的四种用法

    javascript中this的四种用法 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-05-11我要评论 在javascript当中每一个function都是一个对象,所 ...

  7. jquery中attr()与prop()函数用法实例详解(附用法区别)

    本文实例讲述了jQuery中attr()与prop()函数用法.分享给大家供大家参考,具体如下: 一.jQuery的attr()方法 jquery中用attr()方法来获取和设置元素属性,attr是a ...

  8. 说说 JavaScript中 call和apply

    下面有关JavaScript中 call和apply的描述,错误的是? call与apply都属于Function.prototype的一个方法,所以每个function实例都有call.apply属 ...

  9. [转]Javascript中的自执行函数表达式

    [转]Javascript中的自执行函数表达式 本文转载自:http://www.ghugo.com/javascript-auto-run-function/ 以下是正文: Posted on 20 ...

  10. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

随机推荐

  1. equals(),hashcode(),克隆学习心得

    equals(),hashcode(),克隆学习心得 其实在开发时候,很少去重写equals(),hashCode()方法,但是有些时候业务需要还是要重写. 注意: 重写equals()方法一定要重写 ...

  2. sublime 添加代码片段(snippets)

    1.工具-新代码片段(Tools -> New Snippet) 2. <snippet> <content><![CDATA[ if(\$rs && ...

  3. NOI上看到的几个小学奥数

    :余数相同问题 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 已知三个正整数 a,b,c. 现有一个大于1的整数x,将其作为除数分别除a,b,c,得到的余数相同 ...

  4. http获取图片信息

    一.安卓访问网络需要AndroidManifest.xml配置这样一个节点 <manifest> <uses-permission android:name="androi ...

  5. 去除magento多店铺URL地址中的“___from_store=”

    magento 的多店铺功能,大多数情况下是根据语言来进行选择的,当添加了多店铺之后,一般情况下我们会选择开启添加store code到url地址中. Magento 自带的这种功能算是比较不错了,但 ...

  6. ruby -检查数据类型

    HashObj={","language"=>"zh","make"=>"Apple"," ...

  7. Python之路-(Django进阶二)

    model: 双下划线: # 获取个数 # # models.Tb1.objects.filter(name='seven').count() # 大于,小于 # # models.Tb1.objec ...

  8. Django补充及初识Ajax

    Django创建一对多表结构 首先现在models.py中写如下代码: from django.db import models # Create your models here. class Bu ...

  9. js判断手机 横屏模式

    js判断手机 横屏模式 方法名称:orientation 实例: if(window.orientation!=0){ var obj=document.getElementById('orienta ...

  10. [Git] Ubuntu 升级 git 版本

    $ sudo add-apt-repository ppa:git-core/ppa $ sudo apt-get update $ sudo apt-get install git