函数是JavaScript世界里的第一公民,换句话来说,就是我们如果可以精通JavaScript函数的使用,那么对JavaScript的运用可以更游刃有余了。熟悉JavaScript的人应该都知道,同样的函数,以不同的方式调用的话,受影响最大的应该是  this 。下面我们来说说JavaScript函数的各种调用模式。

一、普通函数的调用模式

  所谓普通函数的调用模式,也是JavaScript函数的最简单的一种调用模式,直接就是函数名后接一个  ()  实现调用,看下面代码:

function func(){
console.log(this === window); //true
}
func();

  上面代码,我们用function关键字声明了一个 func 函数,并且在函数体内打印 this===window,然后我们直接调用函数func,我们可以看到控制台是直接打印出 true ,也就是说,函数的这种普通调用模式,函数体内的  this  是指向全局环境 window 的。不清楚这点的同学,可以能会遇到这样的一个bug:

var color = 'gg';
var obj = {
color : 'red',
show : function(){
function func1(){
console.log(this.color); //gg
}
func1();
}
}
obj.show();

  我们在全局环境下声明了一个变量 color 和一个对象 obj ,在对象 obj 里面我们还声明了一个 color 属性 为 'red',一个 show 方法。而且在 show 方法里面呢,我们还声明了一个函数 func1 并且调用了 func1,func1 的作用是打印 this.color。最后我们运行代码  obj.show();   调用obj里面的show方法。不清楚函数的普通调用模式的特点的同学可能会认为此时在控制台答应出来的会是  'red' 。实际上此时在控制台答应出来的应该是  gg  。因为函数  func1  的调用模式是 普通函数调用模式(即使它是在  obj  的  show  方法里面调用的),所以此时函数体内的  this  是指向 全局环境window 的,所以就打印了全局环境下的变量  color 。

  可能有些同学会问:如果我们希望  func1  函数打印出来的是 'red' 呢,应该怎么改?其实很简单,因为  obj.color  才是 'red' ,所以我们只需要把  指向  obj  的  this 引入到函数 func1  里面就行了:

var color = 'gg';
var obj = {
color : 'red',
show : function(){
var that = this;
function func1(){
console.log(that.color); //red
}
func1();
}
}
obj.show();

  在上面的代码中,因为  show  里面的   this  指向   obj   的,所以我们在  show  里面声明一个变量  that = this;用来把指向  obj  的  this  引入到  func1 中,然后再把 func1 函数体内的  this.color  改为  that.color ,此时在控制台打印出来的就是我们想要的 'red' 了。

  可能现在又有同学会问:为什么   show   里面的  this  是指向  obj 的呢?这就是我们要说的JavaScript函数的第二种调用模式:方法调用模式

二、方法调用模式

  方法调用模式,简单来说就是把一个 JavaScript函数作为一个对象的方法来调用,当一个函数被保存为一个对象的属性是,我们就把它称为方法,例如上文的  obj  对象里的  show  ,当一个方法被调用时,函数体里面的   this  就会绑定到这个对象,例如上文的 show 里面的  this  。方法调用模式也很容易辨别:obj.show(),对象名 . 属性名 () ;代码的话可以参考上文的  obj  代码 ,博主就不多写了。记住:方法的调用是可以在函数体内通过  this  访问自己所属的那个对象的。

三、构造器调用模式

  博主认为构造器调用模式是相对于其他模式来说较为复杂点的调用模式了。通过关键字  new  可以把一个函数作为构造器来调用。关键字  new  可以改变函数的返回值:

function func2(name){
this.name = name;
} name; //undefined //普通函数调用模式
var foo = func2('afei');
foo; //undefined
name; //afei //构造器调用模式
var bar = new func2('lizefei');
bar.__proto__ === func2.prototype; //true
bar; //{name:'lizefei'}
bar.name; //'lizefei'

  在上示代码中我们声明了一个函数 func2 ,分别用两种不同的调用模式去调用它。因为函数  func2  并没有显式返回值,所以作为普通函数去调用时,它什么也没有返回,所以  foo  的值是  undefined  。因为普通调用模式的   this   是指向 全局环境   window  的,所以  func2('afei');  后,全局环境下就多了一个  name 变量且等于 'afei'。

  func2  作为构造器调用时,我们可以看到,它返回的是一个对象,因为关键字  new  使得函数在调用是发生了如下的特殊变化:

  1.   创建了一个新对象,而且这个新对象是链接到 func2  的  prototype  属性的
  2.   把函数里的  this  指向了这个新对象
  3.   如果没有显式的返回值,新对象作为构造器func2的返回值进行返回(所以bar 是 {name:'lizefei'})

  这样子我们就可以看出构造器的作用:通过函数的调用来初始化新创建出来的对象。在JavaScript的面向对象编程里面,这个可是相当重要的。

  因为在函数的声明上,在未来作为构造器调用的函数和普通函数的声明没什么区别,所以导致后来的开发者很容易因为调用模式的错误导致程序出问题。所以开发者们都默契地约定,用来做构造器调用的函数的函数名的第一个字符应该大写,例如:Person,People。这样子后来的开发者一看到函数名就知道要用构造器调用模式调用此函数了。

四、使用apply()和call()方法调用

  这种调用的模式是为了更灵活控制函数运行的上下文环境而诞生的。简单的说就是为了灵活控制函数体内  this  的值。

  apply 和 call这两个方法的第一个参数都是要传递被函数上下文的对象(简单点说就是要绑定给函数  this  的对象)。其他参数就有所不同了:

  apply方法的第二个参数是一个数组,数组里面的值将作为函数调用的参数;

  call方法,从第二个参数起(包括第二个参数),剩下的参数都是作为函数调用的参数;

  让我们看看栗子:

var obj = {
name :'afei'
}
function say(ag1,ag2){
console.log(ag1+':'+ag2+" "+ this.name);
}
say.apply(obj,['apply方法','hello']); //apply方法:hello afei
say.call(obj,'call方法','hi'); //call方法:hi afei

  正如栗子所示,我们把对象 obj  作为函数  say  的上下文来调用函数  say  ,所以函数里的  this  是指向 对象  obj  的。在apply方法里,我们通过数组  ['apply方法','hello']  给  say  方法传递了两个参数('apply方法' 和 'hello'),所以打印出来是:  apply方法:hello afei。

  同理  call 也是一样,而且函数传递的方式通过上面的代码也一目了然我,博主就不多做解释了。

  另外,博主还听说apply和call这两个方法除了传递参数的方式不一样,执行的速度还是apply 比 call 要快呢。不过博主就没有实验过。

五、总结

  在JavaScript里面,函数只要的调用模式就是这几种了(在ES6里面还有一种很奇怪很特殊的函数调用模式,叫做’标签模板‘,在这里博主也不多说了,有空另更),只要掌握了这几种主要的调用模式,那么日后再也不用担心  this 的值变来变去了。

  上文如果有漏的、有错误的地方,望各位小伙伴指出,小弟虚心向学。

ps:转载请标明出处  http://www.cnblogs.com/afeihome/

JavaScript函数的各种调用模式的更多相关文章

  1. ASP.net关于C#代码与javaScript函数的相互调用

    C#代码与javaScript函数的相互调用 问:1.如何在JavaScript访问C#函数?2.如何在JavaScript访问C#变量?3.如何在C#中访问JavaScript的已有变量?4.如何在 ...

  2. Javascript 函数声明、调用、闭包

    1 # Javascript 函数声明.调用.闭包 2 # 一.函数声明 3 # 1.直接声明.浏览器在执行前,会先将变量和函数声明进行提升. 4 fn(); 5 function fn () { 6 ...

  3. JavaScript 函数——语法,调用,返回值,局部变量,全局变量,未声明变量

    JavaScript 函数是被设计为执行特定任务的代码块. JavaScript 函数会在某代码调用它时被执行. ㈠函数 ⑴什么是函数 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. ⑵ ...

  4. 函数四种调用模式以及其中的this指向

    第一种:函数直接执行模式 function add(a,b){ console.log(this); return a+b; } add(10,20)//this===window 第二种:对象方法的 ...

  5. js函数之四大调用模式

    一.方法调用模式 当一个函数调用保存为一个对象的属性时我们称之为方法调用. var myObject = { value:0, increment:function(inc){ this.value ...

  6. JavaScript 函数定义和调用

    普通的函数定义方法: function abs(x):{ if (x >= 0){ return x; }else { return -x ; } } 两种方法是等价的 var abs = fu ...

  7. JavaScript函数定义和调用 变量作用域

     本文是笔者在看廖雪峰老师JavaScript教程时的个人总结   JavaScript中函数定义可以是这样的格式 function 函数名(参数) {     函数体 } 也可以是这样的格式     ...

  8. JavaScript 函数的定义-调用、注意事项

    函数定义 函数语句定义 function(a,b){ return a+b; } 表达式定义 var add = function(a,b){return a+b}; //函数表达式可以包含名称,这在 ...

  9. JavaScript函数参数与调用

    函数调用: /* 1. 函数调用 */ ,,,); /* 2. 方法调用 */ this.CName = "全局"; var o = { CName:"o类", ...

随机推荐

  1. C语言解析17monipdb.dat(http://www.ipip.net/)免费数据库

    官方给的链接打不开,而且里面的逻辑,每次都会打开文件,所以自己做了点个修改,发上来,借大家参考: #include <stdio.h> #include <stdlib.h> ...

  2. JAVA 编程规范

       软件开发技术规范 PTHINK-DEVELOP-JAVA-091010         Java语言编程规范   2009-10-10发布                2009-10-11实施 ...

  3. Python下划线的使用

    References: [1]. http://python.jobbole.com/81129/ 本文将讨论Python中下划线(_)字符的使用方法.我们将会看到,正如Python中的很多事情,下划 ...

  4. java虚拟机学习-JVM调优总结-调优方法(12)

    JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...

  5. OpenCV探索之路(十五):角点检测

    角点检测是计算机视觉系统中用来获取图像特征的一种方法.我们都常说,这幅图像很有特点,但是一问他到底有哪些特点,或者这幅图有哪些特征可以让你一下子就识别出该物体,你可能就说不出来了.其实说图像的特征,你 ...

  6. 冒泡排序的python代码实现

    li = [33, 2, 10, 1,564,880,8,99,51,3]# for i in range(len(li) - 1):#     current = li[i]#     next_v ...

  7. sql还原(.sql文件还原)

    第一步: 把还原文件直接拖到SQL Server 2012(或者其他版本)里面,这里以MyDB.sql为例

  8. Linux命令不熟悉(记录)

    1.回到上一次操作的目录 cd - 2.rz打开上传文件 rz 3.下载某个文件 wget httpdownload 4.根据名字查找文件 find / -name mysql 5.通配符删除 rm ...

  9. nodeJs中npm详解

    npm 是 Node.js 的模块依赖管理工具.作为开发者使用的工具,主要解决开发 node.js 时会遇到的问题.如同 RubyGems 对于 Ruby 开发者和 Maven 对于 Java 开发者 ...

  10. python之numpy库[2]

    python-numpy csv文件的写入和存取 写入csv文件 CSV (Comma‐Separated Value, 逗号分隔值),是一种常见的文件格式,用来存储批量数据. 写入csv文件 np. ...