此文的目的是分析函数的四种调用形式,弄清楚函数中this的意义,明确构造函对象的过程,学会使用上下文调用函数。

  在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C#或 其他描述性语言那样仅仅作为一个模块来使用. 函数有四种调用模式,分别是:函数调用形式、方法调用形式、构造器形式、以及apply形式. 这里所有的调用模式中,最主要的区别在于关键字 this 的意义. 下面分别介绍这个几种调用形式.

  一、函数调用形式

  函数调用形式是最常见的形式,也是最好理解的形式. 所谓函数形式就是一般声明函数 后直接调用即是. 例如:

 //声明一个函数,并且调用
 function func(){
       alert('Hello World!!');
 }
 func();

或者

 //使用函数的Lambda表达式定义函数
 var func = function(){
      alert("Hello World!!");
 }
 func();

  这两段代码都会弹出一个对话框,显示字符串中的文字. 这个就是函数调用。

  可以发现函数调用很简单,就是平时学习的一样. 这里的关键是,在函数调用模式中, 函数里的 this 关键字指全局对象,如果在浏览器中就是 window 对象. 例如:

 var func = function(){
        alert(this);
 }
 func();

  此时,会弹出对话框,打印出 [object Window]

  二、方法调用模式

  函数调用模式很简单,是最基本的调用方式. 但是同样的是函数,将其赋值给一个对象的成员以后,就不一样了. 将函数赋值给对象的成员后,那么这个就不在称为函数,而

应该叫做方法. 例如:

  // 定义一个函数
  var func = function() {
      alert("我是一个函数么?");
 };
  // 将其赋值给一个对象
  var o = {};
  o.fn = func; // 注意这里不要加圆括号
  // 调用
  o.fn();

  此时,o.fn 则是方法,不是函数了. 实际上 fn 的方法体与 func 是一模一样的,但是这里有个微妙的不同. 看下面的代码:

  // 接上面的代码
 alert(o.fn === func);

打印结果是 true ,这个表明两个函数是一样的东西. 但是修改一下函数的代码:

  // 修改函数体
 var func = function() {
     alert(this);
  };
  var o = {};
  o.fn = func;
  // 比较
  alert(o.fn === func);
  // 调用
  func();
  o.fn();

  这里的运行结果是,两个函数是相同的,因此打印结果是 true. 但是由于两个函数的调用是不一样的,func 的调用,打印的是 [object Window],而 o.fn 的打印结果是 [object Object].

  这里便是函数调用与方法调用的区别. 函数调用中,this 专指全局对象 window,而 在方法中 this 专指当前对象. 即 o.fn 中的 this 指的就是对象 o.

  三、构造器调用模式

  同样是函数,在单纯的函数模式下,this 表示 window;在对象方法模式下,this 指的是当前对象. 除了这两种情况,javascript 中函数还可以是构造器. 将函数作为构造器来使用的语法就是在函数调用前面加上一个 new 关键字. 如代码:

 // 定义一个构造函数
  var Person = function() {
      this.name = "传智播客";
     this.sayHello = function() {
      alert("你好,这里是" + this.name);
     };
 };
  // 调用构造器,创建对象
  var p = new Person();
  // 使用对象
  p.sayHello();

  上面的案例首先创建一个构造函数Person,然后使用构造函数创建对象p. 这里使用 new 语法. 然后在使用对象调用sayHello()方法. 这个使用构造函数创建对象的案例比较简单. 从案例可以看到,此时 this 指的是对象本身.

  除了上面简单的使用以外,函数作为构造器还有几个变化. 分别为:

   1、 所有需要由对象使用的属性,必须使用 this 引导;

   2、 函数的 return 语句意义被改写,如果返回非对象,就返回this;

  3.1 构造器中的 this

  我们需要分析创建对象的过程,方能知道 this 的意义. 如下面代码:

 var Person = function() {
     this.name = "Hello cc!!";
  };
  var p = new Person();

  这里首先定义了函数 Person,下面分析一下整个执行:

  1、 程序在执行到这一句的时候,不会执行函数体,因此javascript 的解释器并不知道这个函数的内容。

  2、 接下来执行 new 关键字,创建对象,解释器开辟内存,得到对象的引用,将新对象的引用交给函数。

  3、 紧接着执行函数,将传过来的对象引用交给 this 也就是说,在构造方法中,this 就是刚刚被 new 创建出来的对象.

  4、 然后为 this 添加成员,也就是为对象添加成员.

  5、 最后函数结束,返回 this, 将 this 交给左边的变量.

  分析过构造函中数的执行以后,可以得到,构造函数的 this 就是当前对象.

  3.2 构造器中的 return

  在构造函数中 return 的意义发生了变化,首先如果在构造函数中,如果返回的是一个对 象,那么就保留原意. 如果返回的是非对象,比如数字、布尔和字符串,那么就返回 this,如

果没有 return 语句,那么也返回 this. 看下面代码:

  // 返回一个对象的 return
  var ctr = function() {
      this.name = "cc";
      return {
         name:"xx"
      };
 };
 // 创建对象
  var p = new ctr();
  // 访问name属性
  alert(p.name);

执行代码,这里打印的结果是"xx". 因为构造方法中返回的是一个对象,那么保留 return的意义,返回内容为 return 后面的对象. 再看下面代码:

 // 定义返回非对象数据的构造器
  var ctr = function() {
      this.name = "cc";
      return "xx";
  };
  // 创建对象
  var p = new ctr();
  // 使用
  alert(p);
  alert(p.name);

代码运行结果是,先弹窗打印[object Object],然后打印"cc". 因为这里 return 的是一个字符串,属于基本类型,那么这里的 return 语句无效,返回的是 this 对象. 因此第一个打印的 是[object Object]而第二个不会打印 undefined.

四、apply调用模式

  除了上述三种调用模式以外,函数作为对象还有 apply 方法与 call 方法可以使用,这便是 第四种调用模式,我称其为 apply 模式.

  首先介绍 apply 模式,首先这里 apply 模式既可以像函数一样使用,也可以像方法一样使用 可以说是一个灵活的使用方法. 首先看看语法: 函数名.apply(对象, 参数数组);

  这里看语法比较晦涩,还是使用案例来说明:

  1、 新建两个 js 文件,分别为"js1.js"与"js2.js";

  2、 添加代码

  3、 分别运行着两段代码,可以发现第一个文件中的 name 属性已经加载到全局对象 window 中;而第二个文件中的 name 属性是在传入的对象 o 中. 即第一个相当于函数调用,第二个相当于方法调用.

  // js1.js 文件中
  var func1 = function() {
      this.name = "Hello cc!!";
  };
  func1.apply(null);
  alert(name);
  // js2.js 文件
  var func2 = function() {
      this.name = "Hello xx!!";
  };
  var o = {};
  func2.apply(o);
  alert(o.name);

   这里的参数是方法本身所带的参数,但是需要用数组的形式存储在. 比如代码:

 // 一个数组的例子
  var arr1 = [1,2,3,[4,5],[6,7,8]];
  // 将其展开
  var arr2 = arr1.conact.apply([], arr1);

  然后介绍一下 call 模式. call 模式与 apply 模式最大的不同在于 call 中的参数不用数组. 看下面代码就清楚了:

  // 定义方法
 var func = function(name, age, sex) {
      this.name = name;
      this.age = age;
     this.sex = sex;
  };
  // 创建对象
  var o = {};
  // 给对象添加成员
  // apply 模式
  var p1 = func.apply(o, ["xx", 25, "男"]);
  // call 模式
  var p2 = func.call(o, "xx", 25, "男");

上面的代码,apply 模式与 call 模式的结果是一样的.

  实际上,使用 apply 模式和 call 模式,可以任意的操作控制 this 的意义,在函数 js 的设 计模式中使用广泛. 简单小结一下,js 中的函数调用有四种模式,分别是:函数式、方法式、构造

器式和 apply 式. 而这些模式中,this 的含义分别为:在函数中 this 是全局对象 window,在方法中 this 指当前对象,在构造函数中 this 是被创建的对象,在 apply 模式中 this 可以随意的

指定. 在 apply 模式中如果使用 null,就是函数模式,如果使用对象,就是方法模式.

                                     

javascript——四种函数调用形式的更多相关文章

  1. JavaScript高级之函数的四种调用形式

    主要内容 分析函数的四种调用形式 弄清楚函数中this的意义 明确构造函对象的过程 学会使用上下文调用函数 了解函数的调用过程有助于深入学习与分析JavaScript代码. 本文是JavaScript ...

  2. Perl,Python,Ruby,Javascript 四种脚本语言比较

    Perl 为了选择一个合适的脚本语言学习,今天查了不少有关Perl,Python,Ruby,Javascript的东西,可是发现各大阵营的人都在吹捧自己喜欢的语言,不过最没有争议的应该是Javascr ...

  3. Tensorflow 损失函数及学习率的四种改变形式

    Reference: https://blog.csdn.net/marsjhao/article/details/72630147 分类问题损失函数-交叉熵(crossentropy) 交叉熵描述的 ...

  4. JavaScript四种数值取整方法

    一.Math.trunc() 1.定义 Math.trunc()方法去除数字的小数部分,保留整数部分. 2.语法 Math.trunc(value) 3.示例 console.log(Math.tru ...

  5. javascript四种类型识别的方法

    × 目录 [1]typeof [2]instanceof [3]constructor[4]toString 前面的话 javascript有复杂的类型系统,类型识别则是基本的功能.javascrip ...

  6. Android颜色值(RGB)所支持的四种常见形式

    Android中颜色值是通过红(Red).绿(Green).蓝(Blue)三原色,以及一个透明度(Alpha)值来表示的,颜色值总是以井号(#)开头,接下来就是Alpha-Red-Green-Blue ...

  7. 我的Android进阶之旅------>Android颜色值(RGB)所支持的四种常见形式

    Android中颜色值是通过红(Red).绿(Green).蓝(Blue)三原色,以及一个透明度(Alpha)值来表示的,颜色值总是以井号(#)开头,接下来就是Alpha-Red-Green-Blue ...

  8. Javascript四种调用模式中的this指向

    第一种:函数直接调用执行的模式 function add(a,b){ console.log(this); return a+b; } add(,) //this===window 这里的this指向 ...

  9. 【javascript】函数中的this的四种绑定形式

    目录 this的默认绑定 this的隐式绑定 隐式绑定下,作为对象属性的函数,对于对象来说是独立的 在一串对象属性链中,this绑定的是最内层的对象 this的显式绑定:(call和bind方法) n ...

随机推荐

  1. java web.xml配置详解

    1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Servl ...

  2. 使用Unity3d做异形窗口

    项目马上上线,因为之前的登录器是使用VS2010的MFC做的,在很多电脑上会提示缺失mfcXXXX.dll,中间找寻这种解决方案,最后确定将vcredist2010_x86和我的程序打包到安装包里面, ...

  3. Eclipse中启动tomcat报错:A child container failed during start

    我真的很崩溃,先是workspace崩了,费了好久重建的workspace,然后建立了一个小demo项目,tomcat中启动却报错,挑选其中比较重要的2条信息如下: A child container ...

  4. PHP Deprecated: Comments starting with &#39;#&#39; are deprecated in *.ini 警告解决办法

    新装的ubuntu 10.04系统,使用新立得装的PHP,但是每次我在命令行下执行php脚本时都会出如下的警告信息: PHP Deprecated:  Comments starting with ' ...

  5. 指针属性直接赋值 最好先retain 否则内存释放导致crash

    //先释放之前的 YK_RELEASE_SAFELY(_selectedDate); //retain新的 _selectedDate = [aDate retain]; NSString 属性的好像 ...

  6. C++模板使用介绍

    1. 模板的概念. 我们已经学过重载(Overloading),对重载函数而言,C++的检查机制能通过函数参数的不同及所属类的不同.正确的调用重载函数.例如,为求两个数的最大值,我们定义MAX()函数 ...

  7. Python 快捷键

    Ctrl + [ .Ctrl + ] 缩进代码Alt+3 Alt+4 注释.取消注释代码行Alt+5 Alt+6 切换缩进方式 空格<=>TabAlt+/ 单词完成,只要文中出现过,就可以 ...

  8. C语言中头文件和cpp文件解析

    务必提前预读这里的内容:http://www.cnblogs.com/stemon/p/3999844.html 回到cpp文件与头文件各写什么内容的话题上: 理论上来说cpp文件与头文件里的内容,只 ...

  9. Andrew Ng机器学习课程笔记--week5(下)

    Neural Networks: Learning 内容较多,故分成上下两篇文章. 一.内容概要 Cost Function and Backpropagation Cost Function Bac ...

  10. IDEA XML注释与取消注释快捷键

    IntelliJ IDEA和eclipse中编辑Java文件时,注释和取消注释的快捷键都是: "CTRL + / " 编辑xml文件时, 注释:CTRL + SHIFT + / 取 ...