浅谈JavaScript中的Function引用类型
引言
在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引用类型的更多相关文章
- 浅谈JavaScript中的闭包
		浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ... 
- 浅谈JavaScript中的null和undefined
		浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ... 
- 浅谈JavaScript中的正则表达式(适用初学者观看)
		浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ... 
- 浅谈JavaScript中的继承
		引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ... 
- 浅谈JavaScript中的内存管理
		一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ... 
- 浅谈JavaScript中闭包
		引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ... 
- 浅谈JavaScript中的变量、参数、作用域和作用域链
		基本类型和引用类型 在JavaScript中有两种数据类型值.基本类型值和引用类型值.基本类型值指的是简单的数据段,而引用类型值指的是可能由多个值构成的对象.在JavaScript中有5种基本数据类型 ... 
- 浅谈JavaScript中的string拥有方法的原因
		我们都知道,JavaScript数据类型分两大类,基本类型(或者称原始类型)和引用类型. 基本类型的值是保存在栈内存中的简单数据段,它们是按值访问的.JS中有五种基本类型:Undefined.Null ... 
- 浅谈JavaScript中继承的实现
		谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ... 
随机推荐
- js学习笔记5----函数传参
			构建函数的原则: 1) 尽量保持HTML结构一致: 2) 把核心主程序实现,用函数包起来: 3) 把每组里不同的值找出来,通过传参实现. 
- Java非静态内部类中为什么不能有静态变量却可以有常量?
			如:public class InnerClassDemo{ int x; class A{ static int a = 0;//这样写是不合法的. static final int b=0;//这 ... 
- 3.python算法之完全数
			代码: #!/usr/bin/env python # encoding: utf-8 """ @author: 侠之大者kamil @file: 3.完全数.py @t ... 
- JEECMS中返回列表跳转的几种方式
			1.返回的不是当前类 <span class="tools pull-right"> <button class="btn btn-info" ... 
- oracle 10g 安装时字符集的选择,和后边的修改
			先用system和密码登陆SQLPLUS,然后: 1.用sys登录到oracle中 connect sys/密码 as sysdba; (能直接以sys登陆到sqlplus吗?)2.开始修改编码 sh ... 
- golang学习之旅:官方文档汇总
			The Go Programming Language Specification:http://localhost:8080/ref/spec学习Constants.Variables.Types. ... 
- ZooKeeper分布式集群安装
			我特意选择了稳定版...... 奇数意思是说奇数和偶数对故障的容忍度是一致的....所以建议配置奇数个,并不是必须奇数... 一.master节点上安装配置 1.下载并解压ZooKeeper-3.4. ... 
- Zend Guard Loader/Zend Loader是干什么的
			Zend Guard Loader 是加速php的,能提高30%—40%速度.PHP 5.3.X 开始 Zend Optimizer 正式被 Zend Guard Loader 取代.在PHP 5.5 ... 
- 向列布局动态添加F7
			function initBuildingEntryF7(sellId){ var comId = "buildingEntry"; var filter = "&quo ... 
- [MacOS NSAlert的使用]
			源:http://helloitworks.com/863.html NSAlert用于弹出一个确认对话框,在程序中被广泛地使用.常见的场景是用户删除数据,会弹出对话框给用户确认,免得用户不小心导致了 ... 
