定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。函数声明的语法如下:

function functionName(arg0,arg1,arg2){//函数体
}

函数声明,有一个重要特征就是函数声明提升。也就是在执行代码之前会先读取函数声明,也就意味着可以把函数声明放在调用它的语句后面。

sayHi();
function sayHi(){console.log("Hi!");
}

下面介绍函数表达式的语法:

var functionName = function(arg0,arg1,arg2){//函数体
}

这种看起来好像常规的变量赋值语句,就是创建一个函数并将它赋值给变量functionName,这样的函数就是匿名函数,注意function关键字后面没有标识符,匿名函数的name属性是空字符串。

函数表达式和其他表达式一样,在使用之前必须先赋值。

sayHi(); //错误:函数还不存在
var sayHi = function(){alert("Hi!");
};

一、闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。栗如:

function createComparisonFunction(propertyName) {return function(object1, object2){var value1 = object1[propertyName];var value2 = object2[propertyName];if (value1 < value2){return -1;} else if (value1 > value2){return 1;} else {return 0;}};
}

在函数执行过程中,为读取和写入变量的值,需要在作用域链中查找变量,栗如:

function compare(value1, value2){if (value1 < value2){return -1;} else if (value1 > value2){return 1;} else {return 0;}
}
var result = compare(5, 10);

上面代码先定义了compare()函数,然后又在全局作用域调用了它,当调用compare()时,会创建一个包含arguments、value1、value2的活动对象。全局执行环境的变量对象在compare()执行环境的作用域链中则处于第二位,如图:

在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。因此,在createComparisonFunction()函数内部定义的匿名函数的作用域链中,实际上将会包含外部函数createComparisonFunction()的活动对象。

var compare = createComparisonFunction("name");
var result = compare({ name: "Nicholas" }, { name: "Greg" });

在匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就可以访问在createComparisonFunction()中定义的所有变量。更为重要的是,createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中;直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁。

//创建函数
var compareNames = createComparisonFunction("name");
//调用函数
var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
//解除对匿名函数的引用(以便释放内存)
compareNames = null;

首先,创建的比较函数被保存在变量compareNames中,通过设置compareNames为null解除该函数的引用,就等于通知垃圾回收机制将其清除。匿名函数的作用域链被销毁,其他作用域(除了全局作用域)也都可以安全地销毁了。

作用域链带来了一个副作用,闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的变量。举栗:

function createFunctions(){var result = new Array();for (var i=0; i < 10; i++){result[i] = function(){return i;};}return result;
}

这个函数会返回一个函数数组,表面上看,似乎每个函数都有自己的索引值,即位置0的函数返回0,位置1的函数返回1,以此类推。但实际上,每个函数都返回10。因为每个函数的作用域链中凑保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。当createFunctions()函数返回后,变量i的值是10,此时每个函数都引用着保存变量i的同一个变量对象,所以在每个函数内部i的值都是10。

我们可以通过创建另一个匿名函数强制让闭包的行为符合预期。

function createFunctions(){var result = new Array();for (var i=0; i < 10; i++){result[i] = function(num){return function(){return num;};}(i);}return result;
}

重写了createFunctions()函数后,每个函数就会返回各自不同的索引值了。在这里,我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并立即执行该匿名函数的结果赋给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。

在调用每个匿名函数时,我们传入了变量i。由于函数参数是按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,又创建并返回一个访问num的闭包。这样一来,result数组中的每个函数都有自己num变量的一个副本,因此就可以参会各自不同的数值了。

参考资料

《javascript高级程序设计(第3版)》第7章 函数表达式

转载于:https://www.cnblogs.com/winteronlyme/p/6723234.html

函数表达书-读书笔记相关推荐

  1. 《机器学习》(周志华)西瓜书读书笔记

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 第1章 绪论 第2章 模型评估与选择 第3章 线性模型 第4章 决策树 第5章 神经网络 第6章 神经网络 第7章 贝 ...

  2. 花书读书笔记(十一)-应用

    全部笔记的汇总贴:<深度学习>花书-读书笔记汇总贴 一.大规模深度学习 快速的 CPU 实现 GPU 实现:是为图形应用而开发的专用硬件组件. 大规模的分布式实现:数据并行.模型并行.异步 ...

  3. 20220509数据结构绿书读书笔记

    20220509 数据结构读书笔记 全书目录如下 1.编程原则 2.栈 3.队列 4.链栈&队列 5.回溯 6.列表和串 7.搜索 8.排序 9.表格与信息检索 10.二叉树 11.多叉树 1 ...

  4. 《Java: The Complete Reference》等书读书笔记

    春节期间读了下<Java: The Complete Reference>发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统 ...

  5. 红宝书读书笔记 第八章

    对象.类与面向对象编程 属性的类型 内部属性用两个中括号如[ [ Enumerable ] ] 开发者不能直接访问 数据属性 数据属性:数据属性包含一个保存数据值的位置.值会从这个位置读取,也会写入到 ...

  6. 思维导图操作书 读书笔记

    既然是思维导图的读书笔记,那笔记也就用思维导图来呈现.

  7. 《产品思维》一书读书笔记

    作者简介  · · · · · · 刘飞,资深产品人,滴滴出行司机方向前产品负责人,点我达前产品专家,嘟嘟美甲联合创始人,锤子科技产品经理.在知乎累计446579次赞同,224900人关注," ...

  8. 现代操作系统-原理与实现(下)【银杏书-读书笔记】

    上篇链接戳这里 目录 第7章-进程间通信 多进程协助的目的 进程间通信IPC 数据传递 基于共享内存的消息传递 操作系统辅助的消息传递 控制流转移 单向和双向 同步和异步 超时机制 通信连接管理 直接 ...

  9. python编程入门书-读书笔记之《编程小白的第1本Python入门书》

    本书电子版下载地址:百度网盘 写在前面:你需要这本书的原因 有没有那一个瞬间,让你想要放弃学习编程? 在我决心开始学编程的时候,我为自己制定了一个每天编程1小时的计划,那时候工作很忙,我只能等到晚上9 ...

最新文章

  1. java程序设计输入输出实验_20145320《Java程序设计》第五次实验报告
  2. JVM专题(2)-类加载器子系统
  3. who whoami who am i的区别
  4. leetcode 55. Jump Game | 55. 跳跃游戏(暴力递归->傻缓存->DP)
  5. [剑指offer]面试题第[58]题[Leetcode][JAVA][第151题][翻转单词][字符串常用函数总结]
  6. mysql 关联查询_mysql数据库调优(二)
  7. uml边界类例子_面向对象UML笔记
  8. php设置路径别名,设置别名php = / bin / php56,但今天它已恢复为原始路径:/ bin / php...
  9. [转]Directx11 3D空间坐标系认识
  10. (转)Rust :文件分层
  11. 自然语言处理简明教程——序言、第一章
  12. OpenCV的二值化处理函数threshold()详解
  13. [rtsp]海康IPC监控摄像头远程外网监控配置(DDNS)
  14. krita绘图_如何使用Krita制作动画视频
  15. QT串口助手设计流程(如何实现一个串口助手
  16. 世界性能服务器图片,王思聪花了一百万组装了台服务器:全球跑分第四 64核心128线程!快来围观~...
  17. DEM数字高程模型、DSM数字地表模型和DOM正射影像的区别联系
  18. 携程帐号变更函(对私)
  19. vue 自定义事件 解绑
  20. Python3.6 新特性f-string

热门文章

  1. Hibernate中把Session和线程绑定的配置
  2. localdatetime转化为date_LocalDateTime用法(jdk1.8 )
  3. 静态多态之泛型编程(模板)
  4. qq ip探测仪 php,巧用Win7资源监视器,查看QQ好友IP
  5. 评估报告有效期过期了怎么办_托福成绩过期了怎么办?
  6. 浅拷贝+引用计数--写时拷贝---模拟实现string容器
  7. 关联式容器(map,set,multimap,multiset)
  8. linux中bin与sbin目录的作用及区别介绍
  9. 1040 有几个PAT (25 分
  10. 线程控制原语之pthread_self和pthread_create函数