在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C#或其他描述性语言那样仅仅作为一个模块来使用。函数有四种调用模式,分别是:函数调用形式、方法调用形式、构造器形式、以及apply形式。这里所有的调用模式中,最主要的区别在于关键字 this 的意义,下面分别介绍这个几种调用形式。
本文主要内容:
1.分析函数的四种调用形式
2.弄清楚函数中this的意义
3.明确构造函对象的过程
4.学会使用上下文调用函数
一、函数调用形式
函数调用形式是最常见的形式,也是最好理解的形式。所谓函数形式就是一般声明函数后直接调用即是。例如:
function func() {
alert("Hello World");
}
func();
或者:
var func = function() {
alert("你好,程序员");
};
func();
这两段代码都会在浏览器中弹出一个对话框,显示字符串中的文字,这个就是函数调用。
可以发现函数调用很简单,就是平时学习的一样,这里的关键是,在函数调用模式中,函数里的 this 关键字指全局对象,如果在浏览器中就是 window 对象。例如:
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 的意义。如下面代码:
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,看下面代码:
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、添加代码
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 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函数的4种调用方法详解的更多相关文章
-
JavaScript 函数的4种调用方法
JavaScript 函数有 4 种调用方式. 每种方式的不同方式在于 this 的初始化. 作为一个函数调用 function myFunction(a, b) { return a * b; } ...
-
javascript中函数的四种调用模式详解
介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已.函数:如果一个函数与任何对象关系,就称该函数为函数.方法:如果一个函数作为一个对象属性存在,我们 ...
-
javascript 函数的4种调用方式与 this(上下文)的指向
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! javascript中作用域链和this(上下文)的指向是很容易混淆的,简单的说就是: 作用域链取决于函数 ...
-
javascript 函数的4种调用模式
1. 函数模式 // this 指向 window 全局对象 2. 方法模式 // this 指向调用这个方法的对象 3. 构造函数模式 // this 指向 new 新创建出来的实例 4. 上下文模 ...
-
JavaScript中数组Array.sort()排序方法详解
JavaScript中数组的sort()方法主要用于对数组的元素进行排序.其中,sort()方法有一个可选参数.但是,此参数必须是函数. 数组在调用sort()方法时,如果没有传参将按字母顺序(字符编 ...
-
servlet两种配置方法详解
1.web.xml中Servlet的注解 <servlet> <!-- servlet的内部名称,自定义 --> <servlet-name>DemoAction ...
-
iOS中 三种随机数方法详解
ios 有如下三种随机数方法: //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(t ...
-
javascript this 代表的上下文,JavaScript 函数的四种调用形式
JavaScript 是一种脚本语言,支持函数式编程.闭包.基于原型的继承等高级功能.其中JavaScript 中的 this 关键字,就是一个比较容易混乱的概念,在不同的场景下,this会化身不同的 ...
-
javascript函数的4种调用方式
在javascript中一共有4种函数调用模式,分别是:方法调用模式.函数调用模式.构造函数调用模式和apply(call)调用模式,这4种模式的主要差异在于如何初始化关键参数this. 方法调用模式 ...
随机推荐
-
NGUI Camera&#39;s raycast hit through the UI Layer issue
Raycast into GUI?http://forum.unity3d.com/threads/raycast-into-gui.263397/ << ; Ray myray = UI ...
-
$(function(){})与$(document).ready(function(){})
$(function(){ //jq ready()的简写 }); $(document).ready(function(){ // }); 或者: $().ready(function(){ //j ...
-
Color
http://poj.org/problem?id=2154 题意:经典polya题 解析:差别就是项链数目不定,采用欧拉函数,求出所有情况求解即可 // File Name: poj2154.cpp ...
-
javascript各种专业名词
刚开始学javascript经常看到各种专业名词,在此整理一下个人的学习笔记: 直接量 直接量——就是程序中直接使用的数据值,如:88 //数字(String)"hello world ...
-
张高兴的 Xamarin.Android 学习笔记:(一)环境配置
最近在自学 Xamarin 和 Android ,同时发现国内在做 Xamarin 的不多.我在自学中间遇到了很多问题,而且百度到的很多教程也有些过时,现在打算写点东西稍微总结下,顺便帮后人指指路了. ...
-
sqlplus 的安装和配置
sqlplus : oracle公司提供用户操作oracle数据库的工具. 安装所需的包: 1.oracle 客户端 2.sqlplus工具 官方下载地址 http://www.oracl ...
-
C#获取用户登录IP地址
public static string GetUserIp() { string ip; string[] temp; bool isErr = false ...
-
插入MongoDB文档:mongo控制台查看插入到MongoDB文档中的内容
const MongoClient = require('mongodb').MongoClient; const assert = require('assert'); const url = 'm ...
-
2018-No.7-SicnuCtf
5月份的比赛现在才有时间在博客贴出来,这是我第二次出题了,第一次是上届的初赛,这次是决赛的题. 签到(base_or_base) 解压得到两个文件小明.zip和......txt,根据文件名提示猜测是 ...
-
springboot+VUE(一)
https://segmentfault.com/blog/wangjihong 安装nodejs与NPM 下载nodejs的LTL版本,并安装 https://nodejs.org/en/ 执行no ...