蒋坤:(.Net主讲老师)
个人简介:精通.Net技术,熟悉。Net Framework基础类库,对CLR运行原理深有研究,善于利用图形逻辑表述技术难点。曾经参与项目有:广东华兴OA系统、中小学跟踪测评与教学测评系统。
学生评价:授课很有激情。
![](http://bbs.itcast.cn/data/attachment/forum/201403/13/145046d44mbsmzm86qqbmx.jpg)
1) 分析函数的四种调用形式
2)弄清楚函数中this的意义
3) 明确构造函对象的过程
4)学会使用上下文调用函数
了解函数的调用过程有助于深入学习与分析JavaScript代码。 本文是JavaScript高级这个系列中的第三篇文章,主要介绍JavaScript中函数的四种使用形式。
在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C#或其他描述性语言那样仅仅作为一个模块来使用。函数有四种调用模式,分别是:函数调用形式、方法调用形式、构造器形式、以及apply形式。这里所有的调用模式中,最主要的区别在于关键字this的意义。下面分别介绍这个几种调用形式。
一、函数调用形式
函数调用形式是最常见的形式,也是最好理解的形式。 所谓函数形式就是一般声明函数后直接调用即是。 例如:
复制代码
这两段代码都会在浏览器中弹出一个对话框,显示字符串中的文字。 这个就是函数调用。可以发现函数调用很简单,就是平时学习的一样。 这里的关键是,在函数调用模式中,函数里的this关键字指全局对象,如果在浏览器中就是window对象。例如:
复制代码
函数调用模式很简单,是最基本的调用方式。 但是同样的是函数,将其赋值给一个对象的成员以后,就不一样了。将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫做方法。例如:
复制代码
此时,o.fn则是方法,不是函数了。 实际上fn的方法体与func是一模一样的,但是这里有个微妙的不同。看下面的代码:
复制代码
这里的运行结果是,两个函数是相同的,因此打印结果是true。但是由于两个函数的调用是不一样的,func的调用,打印的是[object Window],而 o.fn的打印结果是[object Object]。
这里便是函数调用与方法调用的区别。 函数调用中,this专指全局对象window,而
在方法中this专指当前对象。 即o.fn 中的this指的就是对象o。
三、构造器调用模式
同样是函数,在单纯的函数模式下,this表示window;在对象方法模式下,this指的是当前对象。除了这两种情况,JavaScript中函数还可以是构造器。 将函数作为构造器来使用的语法就是在函数调用前面加上一个new关键字。 如代码:
复制代码
上面的案例首先创建一个构造函数Person,然后使用构造函数创建对p。这里使用new语法。然后在使用对象调用sayHello()方法。这个使用构造函数创建对象的案例比较简单。从案例可以看到,此时this指的是对象本身。
除了上面简单的使用以外,函数作为构造器还有几个变化。分别为:
1、 所有需要由对象使用的属性,必须使用this引导;
2、 函数的return语句意义被改写,如果返回非对象,就返回this;
3.1 构造器中的 this
我们需要分析创建对象的过程,方能知道this的意义。如下面代码:
复制代码
这里首先定义了函数Person,下面分析一下整个执行:
1、 程序在执行到这一句的时候,不会执行函数体,因此JavaScript 的解释器并不知道这个函数的内容。
2、 接下来执行new关键字,创建对象,解释器开辟内存,得到对象的引用,将新对象的引用交给函数。
3、紧接着执行函数,将传过来的对象引用交给this. 也就是说,在构造方法中,this就是刚刚被new创建出来的对象。
4、 然后为this添加成员,也就是为对象添加成员。
5、 最后函数结束,返回 this,将 this 交给左边的变量。
分析过构造函数的执行以后,可以得到,构造函数中的this就是当前对象。
3.2 构造器中的 return
在构造函数中return的意义发生了变化,首先如果在构造函数中,如果返回的是一个对象,那么就保留原意。 如果返回的是非对象,比如数字、布尔和字符串,那么就返回this,如果没有return语句,那么也返回this。 看下面代码:
复制代码
执行代码,这里打印的结果是“牛亮亮”。因为构造方法中返回的是一个对象,那么保留return的意义,返回内容为return后面的对象。再看下面代码:
复制代码
代码运行结果是,先弹窗打印[object Object],然后打印“赵晓虎”。 因为这里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中。即第一个相当于函数调用,第二个相当于方法调用。
这里的参数是方法本身所带的参数,但是需要用数组的形式存储在。 比如代码:
复制代码
然后介绍一下call 模式。 call 模式与apply 模式最大的不同在于call 中的参数不用数组。看下面代码就清楚了:
复制代码
上面的代码,apply 模式与call 模式的结果是一样的。
实际上,使用apply 模式和call 模式,可以任意的操作控制this的意义,在函数js的设计模式中使用广泛。简单小结一下,js中的函数调用有四种模式,分别是:函数式、方法式、构造器式和apply 式。而这些模式中,this 的含义分别为:在函数中 this 是全局对象 window,在方法中 this指当前对象,在构造函数中this是被创建的对象,在apply模式中this可以随意的指定。在apply模式中如果使用null,就是函数模式,如果使用对象,就是方法模式。
五、案例
下面通过一个案例结束本篇吧。
案例说明:有一个div,id为dv,鼠标移到上面去高度增大2倍,鼠标离开恢复。下面
接上js代码:
复制代码
个人简介:精通.Net技术,熟悉。Net Framework基础类库,对CLR运行原理深有研究,善于利用图形逻辑表述技术难点。曾经参与项目有:广东华兴OA系统、中小学跟踪测评与教学测评系统。
学生评价:授课很有激情。
![](http://bbs.itcast.cn/data/attachment/forum/201403/13/145046d44mbsmzm86qqbmx.jpg)
蒋坤老师
主要内容:1) 分析函数的四种调用形式
2)弄清楚函数中this的意义
3) 明确构造函对象的过程
4)学会使用上下文调用函数
了解函数的调用过程有助于深入学习与分析JavaScript代码。 本文是JavaScript高级这个系列中的第三篇文章,主要介绍JavaScript中函数的四种使用形式。
在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C#或其他描述性语言那样仅仅作为一个模块来使用。函数有四种调用模式,分别是:函数调用形式、方法调用形式、构造器形式、以及apply形式。这里所有的调用模式中,最主要的区别在于关键字this的意义。下面分别介绍这个几种调用形式。
一、函数调用形式
函数调用形式是最常见的形式,也是最好理解的形式。 所谓函数形式就是一般声明函数后直接调用即是。 例如:
- <font face="微软雅黑">// 声明一个函数,并调用
- function func() {
- alert("Hello World");
- }
- func();
- 或者// 使用函数的Lambda表达式定义函数,然后调用
- var func = function() {
- alert("你好,传智播客");
- };
- func();</font>
- <font face="微软雅黑"> var func = function() {
- alert(this);
- };
- func();</font>
此时,会弹出对话框,打印出 [object Window]。
二、方法调用模式
函数调用模式很简单,是最基本的调用方式。 但是同样的是函数,将其赋值给一个对象的成员以后,就不一样了。将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫做方法。例如:
- <font face="微软雅黑">// 定义一个函数
- var func = function() {
- alert("我是一个函数么?");
- };
- // 将其赋值给一个对象
- var o = {};
- o.fn = func; // 注意这里不要加圆括号
- // 调用
- o.fn();</font>
- <font face="微软雅黑">// 接上面的代码
- alert(o.fn === func);
- 打印结果是true ,这个表明两个函数是一样的东西。 但是修改一下函数的代码:
- // 修改函数体
- var func = function() {
- alert(this);
- };
- var o = {};
- o.fn = func;
- // 比较
- alert(o.fn === func);
- // 调用
- func();
- o.fn();</font>
这里便是函数调用与方法调用的区别。 函数调用中,this专指全局对象window,而
在方法中this专指当前对象。 即o.fn 中的this指的就是对象o。
三、构造器调用模式
同样是函数,在单纯的函数模式下,this表示window;在对象方法模式下,this指的是当前对象。除了这两种情况,JavaScript中函数还可以是构造器。 将函数作为构造器来使用的语法就是在函数调用前面加上一个new关键字。 如代码:
- <font face="微软雅黑">// 定义一个构造函数
- var Person = function() {
- this.name = "传智播客";
- this.sayHello = function() {
- alert("你好,这里是" + this.name);
- };
- };
- // 调用构造器,创建对象
- var p = new Person();
- // 使用对象
- p.sayHello();</font>
上面的案例首先创建一个构造函数Person,然后使用构造函数创建对p。这里使用new语法。然后在使用对象调用sayHello()方法。这个使用构造函数创建对象的案例比较简单。从案例可以看到,此时this指的是对象本身。
除了上面简单的使用以外,函数作为构造器还有几个变化。分别为:
1、 所有需要由对象使用的属性,必须使用this引导;
2、 函数的return语句意义被改写,如果返回非对象,就返回this;
3.1 构造器中的 this
我们需要分析创建对象的过程,方能知道this的意义。如下面代码:
- <font face="微软雅黑">var Person = function() {
- this.name = "传智播客";
- };
- var p = new Person();</font>
1、 程序在执行到这一句的时候,不会执行函数体,因此JavaScript 的解释器并不知道这个函数的内容。
2、 接下来执行new关键字,创建对象,解释器开辟内存,得到对象的引用,将新对象的引用交给函数。
3、紧接着执行函数,将传过来的对象引用交给this. 也就是说,在构造方法中,this就是刚刚被new创建出来的对象。
4、 然后为this添加成员,也就是为对象添加成员。
5、 最后函数结束,返回 this,将 this 交给左边的变量。
分析过构造函数的执行以后,可以得到,构造函数中的this就是当前对象。
3.2 构造器中的 return
在构造函数中return的意义发生了变化,首先如果在构造函数中,如果返回的是一个对象,那么就保留原意。 如果返回的是非对象,比如数字、布尔和字符串,那么就返回this,如果没有return语句,那么也返回this。 看下面代码:
- <font face="微软雅黑">// 返回一个对象的 return
- var ctr = function() {
- this.name = "赵晓虎";
- return {
- name:"牛亮亮"
- };
- };
- // 创建对象
- var p = new ctr();
- // 访问name属性
- alert(p.name);</font>
- <font face="微软雅黑">// 定义返回非对象数据的构造器
- var ctr = function() {
- this.name = "赵晓虎";
- return "牛亮亮";
- };
- // 创建对象
- var p = new ctr();
- // 使用
- alert(p);
- alert(p.name);</font>
四、apply调用模式
除了上述三种调用模式以外,函数作为对象还有apply方法与call方法可以使用,这便是第四种调用模式,我称其为apply模式。
首先介绍apply模式,首先这里apply 模式既可以像函数一样使用,也可以像方法一样使用可以说是一个灵活的使用方法。 首先看看语法:
函数名。apply(对象, 参数数组);
这里看语法比较晦涩,还是使用案例来说明:
1、 新建两个 js 文件,分别为"js1.js"与"js2.js";
2、 添加代码
- <font face="微软雅黑">// 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);</font>
而第二个文件中的name属性是在传入的对象o中。即第一个相当于函数调用,第二个相当于方法调用。
这里的参数是方法本身所带的参数,但是需要用数组的形式存储在。 比如代码:
- <font face="微软雅黑">// 一个数组的例子
- var arr1 = [1,2,3,[4,5],[6,7,8]];
- // 将其展开
- var arr2 = arr1.conact.apply([], arr1);</font>
- <font face="微软雅黑">// 定义方法
- 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, "男");</font>
实际上,使用apply 模式和call 模式,可以任意的操作控制this的意义,在函数js的设计模式中使用广泛。简单小结一下,js中的函数调用有四种模式,分别是:函数式、方法式、构造器式和apply 式。而这些模式中,this 的含义分别为:在函数中 this 是全局对象 window,在方法中 this指当前对象,在构造函数中this是被创建的对象,在apply模式中this可以随意的指定。在apply模式中如果使用null,就是函数模式,如果使用对象,就是方法模式。
五、案例
下面通过一个案例结束本篇吧。
案例说明:有一个div,id为dv,鼠标移到上面去高度增大2倍,鼠标离开恢复。下面
接上js代码:
- <font face="微软雅黑">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);
- };</font>