引言

  在JavaScript中最有意思的就是函数了,这一切的根源在于函数实际上是一个对象。每一个函数都是Function类型的实例,而且都和其他引用类型的实例一样具有属性和方法。函数作为一个对象,因此函数名称实际是一个指向函数对象的指针,不会与某一个函数进行绑定。

函数没有重载

  前面部分介绍过,函数名称实际是指向函数对象的一个指针,这样就不难理解Javacript中的函数不存在函数重载了。请看下面的例子

 function addNumber(number) {
return 100 + number;
} function addNumber(number) {
return 200 + number;
} var result = addNumber(300);
alert(result);//输出500

  在这个例子里面我们定义了两个同名函数,第一个函数我们在定义的时候会在全局作用域的变量对象中引用第一个函数对象,addNumber指向第一个函数对象。当运行到第二个函数的时候addNumber又指向第二个函数对象。所以addNumber现在指向第二个函数对象。所以下面在调用它引用的函数时,会执行第二个函数。

函数声明与函数表达式

  函数通常是使用函数声明语法定义的,当然函数表达式的语法也是可以的,不过它们之间有一些很重要的差异。实际上,解析器在向执行环境中加载数据时,会率先读取函数表达式,使其在任何代码之前可用(可以访问)。对于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正解析执行。

作为值的函数

  在JavaScript中函数名本身就是变量,因此函数也可以作为值来使用。函数不仅可用作为参数传递给另一个参数,也可以作为另一个函数的结果返回。我们来看下下面的例子

 //通过属性名称来对数组元素进行排序
function createComparisonFunction(propertyName) {
return function (obj1, obj2) {
var val1 = obj1[propertyName];
var val2 = obj2[propertyName];
if (val1 < val2) {
return -1;
}
else if (val1 > val2) {
return 1;
}
else {
return 0;
}
}
} var data = [{ name: "gxw", age: 25 }, { name: "zmm", age: 20 }];
//按照name属性来排序
data.sort(createComparisonFunction("name"));
alert(data[0].name);//输出gxw
//按照age属性来排序
data.sort(createComparisonFunction("age"));
alert(data[0].name);//输出zmm

  在这个例子中我们看到我们在createcomparisonFunction中返回了一个匿名函数,在匿名函数中我们根据属性来对对象数组进行排序。

函数内部属性

  在函数内部有两个非常特殊的对象,它们分别是:arguments和this。arguments对象在前面可能也介绍了一点。它是一个类似于数组的对象,但是它不是数组。它包含着传入函数的所有的参数。arguments对象还有一个callee属性,这个属性是一个指针,指向拥有这个arguments对象的函数。一个非常经典的例子是阶乘,请看例子:

 function factorial(number) {
if (number <= 1) {
return 1;
}
else {
//return number * factorial(number - 1);
return number * arguments.callee(number - 1);
}
} alert(factorial(5));

  在这个例子中我们看到我们定义了一个名叫factorial的阶乘函数。在第6行一般是我们常规的做法。但是这样有一个问题,阶乘函数和它的名称紧紧的耦合在一起,一旦以后改变了阶乘函数的名称,就需要在函数内部也修改名称。这时候通过使用arguments.callee可以代替第一种做法。消除了函数与名称紧紧耦合在一起的问题。

  在函数内部this对象引用的是函数据以执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window对象)。来看下面的例子:

 var color = "windows color";
var obj = { color: "obj color" }; function sayColor() {
alert(this.color);
} function sayColor2() {
return function () {
return this.color;
}
} sayColor(); //windows color obj.sayColor = sayColor;
obj.sayColor();//obj color alert(sayColor2()()); //windows color obj.sayColor2 = sayColor2;
alert(obj.sayColor2()());//windows color

  在这个例子中,我们看到在全局作用域下调用函数this指向的是window对象。看代码的第17行。如果在对象上调用函数的时候,我们看到this指向的当前调用函数的对象。重点是如果在函数内部还有一个函数的时候this指向的是什么呢?通过sayColor2函数我们知道在匿名函数中this指向的是window对象。那为什么不是包含作用域(或者外部作用域)的this对象呢?在前面我们介绍过,在函数被调用时,其活动对象都会自动获得2个特殊对象,this和arguments对象。内部函数在这两个变量时,只会搜索到活动对象为止,所以用于不可能获取到外部作用域中的这2个对象。

函数属性和方法

  JavaScript中函数时对象,因此函数也有属性和方法。每一个函数都包含两个属性,它们分别是:length和prototype属性。length属性表示函数希望接受到的参数的个数。例如一个函数在定义的时候参数列表定义了3个参数,那么length就是3。记住:定义的参数个数可以通过函数名.length来获取。实际传递的参数个数和参数值可以到arguments中获取。

  在JavaScript定义的全部属性中,最神秘的就是prototype属性了。对于JavaScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。在JavaScript中prototype是不可枚举的,所以for-in循环是找不到prototype属性的。

  每个函数都包含两个非继承而来的方法,call和apply方法。这两个函数的用途都是在特定的作用域中调用函数,实际上是等于设置函数体内this对象的值。事实上,传递参数并非是call和apply真正 用武之地,它们强大的地方在于可以扩充函数赖以生存的作用域。来看下面的例子:

 var color = "windows color";
var obj = { color: "obj color" }; function sayColor() {
alert(this.color);
} sayColor(); //windows color sayColor.call(this); //windows color
sayColor.call(window); //windows color
sayColor.call(obj); //obj color

  注意看代码的第12行,通过call函数指定函数体内this的值是obj对象。这样输出的就是obj color了。使用call或者apply来扩充作用域就是对象不需要与函数有任何耦合关系。在前面的例子中,我们先将sayColor绑定到obj对象上,然后使用obj.sayColor()来调用函数。通过call或者apply我们可以省去那些不必要的步骤。

  

浅谈JavaScript中的Function引用类型的更多相关文章

  1. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  2. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  3. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  4. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  5. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  6. 浅谈JavaScript中闭包

    引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...

  7. 浅谈JavaScript中的变量、参数、作用域和作用域链

    基本类型和引用类型 在JavaScript中有两种数据类型值.基本类型值和引用类型值.基本类型值指的是简单的数据段,而引用类型值指的是可能由多个值构成的对象.在JavaScript中有5种基本数据类型 ...

  8. 浅谈JavaScript中的string拥有方法的原因

    我们都知道,JavaScript数据类型分两大类,基本类型(或者称原始类型)和引用类型. 基本类型的值是保存在栈内存中的简单数据段,它们是按值访问的.JS中有五种基本类型:Undefined.Null ...

  9. 浅谈JavaScript中继承的实现

    谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...

随机推荐

  1. sublime text 如何设置”在浏览器浏览“的快捷键

    sublime text编辑器极其强大 ,但在刚开始用的时候,每次在浏览器中查看非得右键鼠标----”open in browser“,着实觉得麻烦....百度之,上面的方法有很多,但是根据我自己的经 ...

  2. 【奶昔队ROUND#1】

    奶昔队Round #1 热身 (奶昔队不是真正的队,是群) CodeForces 435C Cardiogram 模拟,不过我做的时候不是模拟,是计算...(写了好久,还wa了几次),现在看了别人的代 ...

  3. camerc文件播放

    下载CamtasiaStudio 5中文版,打开CamtasiaStudio.exe在左边有生成选项,点左边工具框内添加/导入媒体,则选择下面的批量生成.弹出添加文件的菜单点添加文件,加入你要转换的c ...

  4. angularjs 手动加载

    利用ng-app可以完成自动加载,如果不利用ng-app.那么使用bootstrarp实现手动加载模块 <html> <head> <script src="a ...

  5. SQL Server 2008及以上版本出现”SQL Server 复制需要有实际的服务器名称才能连接到服务器...“的问题解决

    出现如下错误: 这是由于安装时的计算机名更改导致会出现如上的错误. 解决方法: 1.SQL方式: 1)先执行如下脚本,看下名称是否一致 use master go select @@servernam ...

  6. poj3696 快速幂的优化+欧拉函数+gcd的优化+互质

    这题满满的黑科技orz 题意:给出L,要求求出最小的全部由8组成的数(eg: 8,88,888,8888,88888,.......),且这个数是L的倍数 sol:全部由8组成的数可以这样表示:((1 ...

  7. Pipe

    #一边压缩一边传 一边解压 到对方的目录为/tlj/2/ / | ssh root@172.16.200.56 tar xzf - -C /tlj #在一个需要文件名的地方 使用-重定向输出到stdo ...

  8. SLF4J的好处

    原来我们使用log4j去打印日志,如果我们要更改日志记录器,比如用comms-Logging,那我们在代码里面还要改每个类的引用包,但是如果用slf4j的话只要在配置的时候改下,代码完全用slf4j的 ...

  9. python函数(五)

    函数 1.函数基本语法及特性 背景提要 现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警, 你掏空了所有的知识量,写出了以下代码 ...

  10. linux配置网卡

    我爱折腾.在本地虚拟机里装了linux的环境.要配置linux的网卡文件. 如下: vi /etc/sysconfig/network-script/ifcfg-eth0; 刚装完系统,没有vim , ...