浅谈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的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...
随机推荐
- 【HDU 5832】A water problem(大数取模)
1千万长度的数对73和137取模.(两个数有点像,不要写错了) 效率要高的话,每15位取一次模,因为取模后可能有3位,因此用ll就最多15位取一次. 一位一位取模也可以,但是比较慢,取模运算是个耗时的 ...
- navigate连接MySQL报错:navigate your password has expired to log in your must change it using a client that supports
如图: 终端进入mysql: 第一次show databases的的时候,密码过期了,然后重置密码为12345,再次就可以显示了 参考连接:http://www.jb51.net/article/79 ...
- iOS推送后页面跳转
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...
- 浅谈 GPU图形固定渲染管线
图形渲染管道被认为是实时图形渲染的核心,简称为管道.管道的主要功能是由给定的虚拟摄像机.三维物体.灯源.光照模型.纹理贴图或其他来产生或渲染一个二维图像.由此可见,渲染管线是实时渲染技术的底层工具.图 ...
- [bzoj3670][2014湖北省队互测week2]似乎在梦中见过的样子
Description 已知一个字符串S,求它有多少个形如A+B+A的子串(len(A)>=k,len(B)>=1 ). Input 第一行一个字符串,第二行一个数 k. Output 仅 ...
- 【BZOJ-4668】冷战 并查集 + 按秩合并 + 乱搞
4668: 冷战 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 37 Solved: 24[Submit][Status][Discuss] Des ...
- 【poj1085】 Triangle War
http://poj.org/problem?id=1085 (题目链接) 题意 A,B两人玩游戏,在一个大三角形上放火柴,若A放上一根火柴后成功组成一个三角形,那么这个三角形就归属于A,并且A被奖励 ...
- Nginx 日志分享
Nginx 日志对于大部分人来说是个未被发掘的宝藏,总结之前做某日志分析系统的经验,和大家分享一下 Nginx 日志的纯手工分析方式. Nginx 日志相关配置有 2 个地方:access_log 和 ...
- SQLite Learning、SQL Query Optimization In Multiple Rule
catalog . SQLite简介 . Sqlite安装 . SQLite Programing . SQLite statements 1. SQLite简介 SQLite是一款轻型的数据库,是遵 ...
- waf2控件名
1,查询表格(queryGrid),编辑表格(editGrid) wafGrid 2,快速F7 wafPromptQuick 3,表格F7 wafPromptGrid 4,自定义F7 wafPromp ...