JavaScript函数的4种调用方法详解


Posted in Javascript onApril 22, 2014

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

本文主要内容:

1.分析函数的四种调用形式
2.弄清楚函数中this的意义
3.明确构造函对象的过程
4.学会使用上下文调用函数

一、函数调用形式

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

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

或者:
// 使用函数的Lambda表达式定义函数,然后调用
var func = function() {
    alert("你好,程序员");
};
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。

构造器中的 this

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

var Person = function() {
    this.name = "程序员";
};
var p = new Person();

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

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

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

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

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

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

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

构造器中的 return

在构造函数中 return 的意义发生了变化,首先如果在构造函数中,如果返回的是一个对象,那么就保留原意。如果返回的是非对象,比如数字、布尔和字符串,那么就返回 this,如果没有 return 语句,那么也返回 this,看下面代码:

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

执行代码,这里打印的结果是”牛亮亮”。因为构造方法中返回的是一个对象,那么保留 return 的意义,返回内容为 return 后面的对象,再看下面代码:
// 定义返回非对象数据的构造器
var ctr = function() {
    this.name = "赵晓虎";
    return "牛亮亮";
};
// 创建对象
var p = new ctr();
// 使用
alert(p);
alert(p.name);

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

四、apply调用模式

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

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

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

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

2、添加代码

// js1.js 文件中
var func1 = function() {
    this.name = "程序员";
};
func1.apply(null);
alert(name);
// js2.js 文件
var func2 = function() {
    this.name = "程序员";
};
var o = {};
func2.apply(o);
alert(o.name);

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

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

// 一个数组的例子
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, ["赵晓虎", 19, "男"]);
// call 模式
var p2 = func.call(o, "赵晓虎", 19, "男");

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

实际上,使用 apply 模式和 call 模式,可以任意的操作控制 this 的意义,在函数 js 的设 计模式中使用广泛。简单小结一下,js 中的函数调用有四种模式,分别是:函数式、方法式、构造 器式和 apply 式. 而这些模式中,this 的含义分别为:在函数中 this 是全局对象 window,在方 法中 this 指当前对象,在构造函数中 this 是被创建的对象,在 apply 模式中 this 可以随意的指定.。在 apply 模式中如果使用 null,就是函数模式,如果使用对象,就是方法模式。

五、综合例子

下面通过一个案例结束本篇吧。案例说明:有一个div,id为dv,鼠标移到上面去高度增大2倍,鼠标离开恢复,下面直接上js代码:

var dv = document.getElementById("dv");
var height = parseInt(dv.style.height || dv.offsetHeight);
var intervalId;
dv.onmouseover = function() {
    // 停止已经在执行的动画
    clearInterval(intervalId);
    // 得到目标高度
    var toHeight = height * 2;
    // 获得当前对象
    var that = this;
    // 开器计时器,缓慢变化
    intervalId = setInterval(function() {
        // 得到现在的高度
        var height = parseInt(dv.style.height || dv.offsetHeight);
        // 记录每次需要变化的步长
        var h = Math.ceil(Math.abs(height - toHeight) / 10);
        // 判断变化,如果步长为0就停止计时器
        if( h > 0 ) {
            // 这里为什么要用that呢?思考一下吧
            that.style.height = (height + h) + "px";
        } else {
            clearInterval(intervalId);
        }
    }, 20);
};
dv.onmouseout = function() {
    // 原理和之前一样
    clearInterval(intervalId);
    var toHeight = height;
    var that = this;
    intervalId = setInterval(function() {
        var height = parseInt(dv.style.height || dv.offsetHeight);
        var h = Math.ceil(Math.abs(height - toHeight) / 10);
        if( h > 0 ) {
            that.style.height = (height - h) + "px";
        } else {
            clearInterval(intervalId);
        }
    }, 20);
};
Javascript 相关文章推荐
Js中setTimeout()和setInterval() 何时被调用执行的用法
Apr 12 Javascript
extjs 时间范围选择自动判断的实现代码
Jun 24 Javascript
js实现按钮控制图片360度翻转特效的方法
Feb 17 Javascript
JavaScript动态添加css样式和script标签
Jul 19 Javascript
jQuery Easyui Datagrid实现单行的上移下移及保存移动的结果
Aug 15 Javascript
很棒的js Tab选项卡切换效果
Aug 30 Javascript
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
Jul 12 jQuery
XMLHttpRequest对象_Ajax异步请求重点(推荐)
Sep 28 Javascript
详解JavaScript对数组操作(添加/删除/截取/排序/倒序)
Apr 28 Javascript
vue实现多条件和模糊搜索功能
May 28 Javascript
详解element-ui中el-select的默认选择项问题
Aug 02 Javascript
Node.JS获取GET,POST数据之queryString模块使用方法详解
Feb 06 Javascript
JavaScript实现存储HTML字符串示例
Apr 21 #Javascript
JavaScript获取flash对象与网上的有所不同
Apr 21 #Javascript
js unicode 编码解析关于数据转换为中文的两种方法
Apr 21 #Javascript
jquery form 加载数据示例
Apr 21 #Javascript
三种方式获取XMLHttpRequest对象
Apr 21 #Javascript
JavaScript中的Math 使用介绍
Apr 21 #Javascript
jQuery过滤选择器:not()方法使用介绍
Apr 20 #Javascript
You might like
PHP实现下载功能的代码
2012/09/29 PHP
php多文件上传功能实现原理及代码
2013/04/18 PHP
PHP实现对xml的增删改查操作案例分析
2017/05/19 PHP
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
jQuery学习笔记之jQuery中的$
2015/01/19 Javascript
jQuery插件animateSlide制作多点滑动幻灯片
2015/06/11 Javascript
jQuery实现两款有动画功能的导航菜单代码
2015/09/16 Javascript
jQuery对象的链式操作用法分析
2016/05/10 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
微信小程序 教程之wxapp视图容器 swiper
2016/10/19 Javascript
利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换
2017/01/13 Javascript
JS组件系列之Gojs组件 前端图形化插件之利器
2017/11/29 Javascript
vue-cli 目录结构详细讲解总结
2019/01/15 Javascript
利用JS判断元素是否为数组的方法示例
2021/01/08 Javascript
[01:07:47]Secret vs Optic Supermajor 胜者组 BO3 第一场 6.4
2018/06/05 DOTA
Python+树莓派+YOLO打造一款人工智能照相机
2018/01/02 Python
Python爬虫包BeautifulSoup异常处理(二)
2018/06/17 Python
我喜欢你 抖音表白程序python版
2019/04/07 Python
python常用数据重复项处理方法
2019/11/22 Python
浅谈Pytorch torch.optim优化器个性化的使用
2020/02/20 Python
Pycharm无法打开双击没反应的问题及解决方案
2020/08/17 Python
mysql的最长数据库名,表名,字段名可以是多长
2014/04/21 面试题
西安夏日科技有限公司Java笔试题
2013/01/11 面试题
十八大报告观后感
2014/01/28 职场文书
食品厂厂长岗位职责
2014/01/30 职场文书
高三政治教学反思
2014/02/06 职场文书
超市仓管员岗位职责
2014/04/07 职场文书
环保建议书200字
2014/05/14 职场文书
2014大学生职业生涯规划书最新范文
2014/09/13 职场文书
个人授权委托书范文
2014/09/21 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
2014年综治维稳工作总结
2014/11/17 职场文书
孕妇病假条怎么写
2015/08/17 职场文书
聊聊JS ES6中的解构
2021/04/29 Javascript
详解Laravel框架的依赖注入功能
2021/05/27 PHP
PostgreSQL之连接失败的问题及解决
2023/05/08 PostgreSQL