《JS权威指南学习总结--8.4 作为值的函数》
内容要点:
函数可以定义,也可以调用,这是函数最重要的特性。函数定义和调用是JS的词法特性,对于其他大多数编程语言来说也是如此。然而在JS中,函数不仅仅是一种语法,也是值,也就是说,可以将函数赋值给变量,存储在对象的属性或数组的元素中,作为参数传入另外一个函数等。
一.理解JS中的函数
定义一个函数:function square(x) { return x*x;}
这个定义创建了一个新的函数对象,并将其赋值给变量square。函数的名字实际上是看不见的,它仅仅是变量的名字,这个变量指代函数对象。函数还可以赋值给其他的变量,并且仍可以正常工作。
var s = square; //现在s和square指代同一个函数
square(4); //=>16
s(4); //=>16
除了可以将函数赋值给变量,同样可以将函数赋值给对象的属性。当函数作为对象的属性调用时,函数就称为方法:
var o = { square:function(x){ return x*x;}}; //对象直接量
var y = o.square(16);
函数甚至不需要带名字,当把它们赋值给数组元素时:
var a = [ function(x){ return x*x; },20]; //数组直接量
a[0](a(1)); //=>400
最后一句代码看起来很奇怪,但的确是合法的函数调用表达式!
例如:
//将函数用做值
//在这里定义一些简单的函数
function add(x,y){ return x + y; }
function subtract(x,y){ return x-y; }
function multiply(x,y){ return x*y; }
function divide(x,y){ return x/y; }
//这里的函数以上面的某个函数作为参数
//并给它传入两个操作数然后调用它
function operate( operator,operand1,operand2 ){ return operator(operand1,operand2); }
//这行代码所示的函数调用了实际上计算了(2+3)+(4*5) 的值
var i = operate( add,operate(add,2,3),operate(multiply,4,5));
//我们为这个例子重复实现一个简单的函数
//这次实现使用函数直接量,这些函数直接量定义在一个对象直接量中
var operators = {
add:function(x,y){ return x + y; },
subtract:function(x,y){ return x-y; },
multiply:function(x,y){ return x*y; },
divide:function(x,y){ return x/y },
pow:Math.pow //使用预定义的函数
};
//这个函数接收一个名字作为运算符,在对象中查找这个运算符
//然后将它作用于所提供的操作数
//注意这里调用运算符函数的语法
function operate2( operation,operand1,operand2 ){
if(typeof operators[operation] === "function" )
return operators[operation](operand1,operand2);
else
throw "unknown operator"
}
//这样来计算("hello" + "" +"world")的值
var j = operate2("add","hello",operator2("add"," ","world"));
//使用预定义的函数Math.pow()
var k = operator2("pow",10,2);
二.自定义属性
JS中的函数并不是原始值,而是一种特殊的对象,也就是说,函数可以拥有属性。
当函数需要一个 “静态”变量来调用时保持某个值不变,最方便的方式就是给函数定义属性,而不是定义全局变量,显然定义全局变量会让命名空间变得更加杂乱无章。
比如,假设写一个返回一个唯一整数的函数,不管在哪里调用函数都会返回这个整数。而函数不能两次返回同一个值,为了做到这一点,函数必须能够跟踪它每次返回的值,而且这些值的信息需要在不同的函数调过程中持久化。可以将这些信息存放到全局变量中,但这并不是必需的,因为这个信息仅仅是函数本身用到的。最好将这个信息保存到函数对象的一个属性中。
例如:
//初始化函数对象的计数器属性
//由于函数声明被提前了,因此这里是可以在函数声明之前给它的成员赋值的
uniqueInteger.counter = 0;
//每次调用这个函数都会返回一个不同的整数
//它使用一个属性来记住下一次将要返回的值
function uniqueInteger(){ return uniqueInteger.counter++; //先返回计数器的值,然后计数器自增1 }
例子2:函数factorial()使用了自身的属性(将自身当做数组来对待)来缓存上一次的计算结果
//计算阶乘,并将结果缓存至函数的属性中
function factorial(n){
//isFinite() 函数用于检查其参数是否是无穷大。如果 number 是有限数字(或可转换为有限数字),那么返回 true。否则,如果 number 是 NaN(非数字),或者是正、负无穷大的数,则返回 false。
if(isFinite(n)&&n>0&&n==Math.round(n)){ //有限的正整数
if(!(n in factorial)) //如果没有缓存结果
factorial[n]=n*factorial(n-1); //计算结果并缓存之
return factorial[n];
}
else return NaN; //如果输入有误
}
factorial[1]=1; //初始化缓存以保存这种基本情况
《JS权威指南学习总结--8.4 作为值的函数》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- Python random模块(获取随机数)常用方法和使用例子
random.randomrandom.random()用于生成一个0到1的随机符点数: 0 <= n < 1.0 random.uniformrandom.uniform(a, b),用 ...
- 【51Nod】1005 大数加法
给出2个大整数A,B,计算A+B的结果. Input 第1行:大数A 第2行:大数B (A,B的长度 <= 10000 需注意:A B有可能为负数) Output 输出A + B Input示例 ...
- GOPS2017全球运维大会深圳站 出席嘉宾盘点!
去年,GOPS全球运维大会在深圳出发,当时门票提前几周收盘,2017年,承载着运维人的期望,GOPS全球运维大会再次来到了深圳.第六届GOPS2017全球运维大会深圳站(本次)将于2017年4月21日 ...
- LR日志解析
在录制和回放的时候,VU会分别把发生的事件记录成日志文件,这些日志有利于我们跟踪VU和服务器的交互过程. 1.回放日志(Replay log) 脚本回放运行时的输出都记在这个log里. "输 ...
- 将mysql的data目录移走方法
如移动到"/home/mysql/data",我的mysql是装在/usr/local/mysql下的 1. 将/usr/local/mysql/data移动到/home/mysq ...
- error: a label can only be part of a statement and a declaration is not a statement
GCC: error: a label can only be part of a statement and a declaration is not a statement switch(a){ ...
- 笔记本开临时Wifi
笔记本开临时热点 1. netsh wlan set hostednetwork mode=allow ssid=xianzhonPC key=123456782. 打开共享和网络—更改适配器设置—本 ...
- supervisor启动流程
Supervisor结构: 单点结构如图: 1. 初始化时,启动进程Supervisor,根据 Nimbus分配的任务情况触发启动/停用Worker Jvm进程! 2. 每个Worker进程启动一个 ...
- out和ref之间的区别
首先:两者都是按引用传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...
- Regmon7.04绿色版(注册表变动实时监视工具)
Regmon V7.04 简繁中文绿色版 软件大小: 155KB软件语言: 简体中文运行环境:Win9x/NT/2000/XP/2003/软件类别:国外软件 / 免费版 / 系统其它Regmon Re ...