一步步学习javascript基础篇(6):函数表达式之【闭包】
回顾前面介绍过的三种定义函数方式
1. function sum (num1, num2) { return num1 + num2; } //函数声明语法定义
2. var sum = function(num1, num2){ return num1 + num2; }; //函数表达式定义
3. var sum = new Function("num1", "num2", "return num1 + num2"); //Function 构造函数
在分析闭包之前我们先来看看,定义和调用函数容易犯的错误。
例1:
sayHi(); //错误:函数还不存在
var sayHi = function () {
alert("test");
};
例2:
if (true) {
function sayHi() {
alert("1");
}
} else {
function sayHi() {
alert("2");
}
}
sayHi();//打印结果并不是我们想要的
例3:
var fun1 = function fun2() {
alert("test");
}
fun2();//错误:函数还不存在
在例1中,我们不能在使用函数声明式语法定义之前调用函数。解决方案:
1.如果使用函数表达式定义函数的话,需要在表达式定义后调用。
var sayHi = function () {
alert("test");
};
sayHi()
2.使用函数声明式。(这里浏览器引擎会函数声明提升,在所有代码执行之前先读取函数声明)
sayHi();
function sayHi () {
alert("test");
};
在例2中,我们预期的结果应该是打印1,实际结果是打印2。
if (true) {
function sayHi() {
alert("1");
}
} else {
function sayHi() {
alert("2");
}
}
sayHi();//打印结果并不是我们想要的
为什么会这样?正因为函数声明提升,所以浏览器在预解析的时候不会判断if条件,直接解析第二个函数定义的时候覆盖了第一个。
解决方案:
var sayHi;
if (true) {
sayHi = function () {
alert("1");
}
} else {
sayHi = function () {
alert("2");
}
}
sayHi();
在例3中,发现只能只用fun1()调用,而不能使用fun2()调用。
我自己的理解,真正原因不知道。没找到资料。
因为1: function fun3() { }; 等效与 var fun3 = function fun3() { }; 如图:

所以只能只用fun1()调用,而不能使用fun2()调用。
其实这里我还是有疑问的?哪位大神知道,望告知。
既然,fun2在外面不能调用为什么在函数内部能调用?虽然在debugger还是得不到fun1。

好了,通过上面的三道题目热身。我们继续今天的主题“闭包”。
1.什么是闭包?
定义:就是有权访问另一个函数作用域的变量的函数
我们先从一个示例函数开始:
例1:
function fun() {
var a = "张三";
}
fun();//在我们执行完后,变量a就被标记为销毁了
例2:
function fun() {
var a = "张三";
return function () {
alert("test");
}
}
var f = fun();//同样,在我们执行完后,变量a就被标记为销毁了
例3:
function fun() {
var a = "张三";
return function () {
alert(a);
}
}
var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】
f();//【然后变量a的值正常的被访问到了】
//这就是闭包,当函数A 返回的函数B 里面使用到了函数A的变量,那么函数B就使用了闭包。
示例:
function fun() {
var a = "张三";
return function () {
alert(a);
}
}
var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】
f();//【然后变量a的值正常的被访问到了】
显然,滥用闭包会增大内存的使用。所以非特殊情况尽量不要使用闭包。如果用到了,记得手动设置空引用,内存才能被回收 f = null;
图解:(不了解作用域链的同学请先看前面的文章作用域和作用域链)

补充:例4:(闭包的实例应用)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
.tempBut {
display: none;
}
</style>
</head>
<body>
<div class="mydiv">
<input value="but" type="button" class="tempBut" />
</div>
<script src="Scripts/jquery-1.8.2.js"></script>
<script type="text/javascript"> for (var i = 0; i < 10; i++) {
var tempHtml = $(".tempBut").clone().removeClass("tempBut");
//tempHtml.click(function (i) {
// alert(i);//怎样打印 0 到 9
//});
(function (num) {//使用闭包传值
tempHtml.click(function () {
alert(num);
});
})(i);
$(".mydiv").append(tempHtml);
}
</script>
</body>
</html>
2.什么是匿名函数?(仅仅只是解释这个概念)
如:(即,没有名字的函数)

关于对象中函数的返回值是匿名函数时,this的怪异现象
讲解之前,先清醒下头脑,不要越看越迷糊了。如果迷糊了,那就直接忽略下面的。
var name1 = "张三";
var obj = {
name1: "李四",
fun2: function () {
alert(this.name1);
},
fun3: function () {
return function () {
alert(this.name1);
}
}
}
obj.fun2();//打印结果"李四"意料之中的。
obj.fun3()();//因为这里返回的是一个函数,所以要再加一对()来调用。打印结果是"张三",意料之外。
//真是百事不得其解啊,什么this指向了全局?
我们前面讲过“哪个对象点出来的方法,this就是哪个对象”,那我们的 obj.fun3()() 打印的是“张三”也就是说this执行了全局作用域。
我们看看下面的示例也许就知道为什么了。
var name1 = "张三";
var obj = {
name1: "李四",
fun2: function () {
alert(this.name1);
},
fun3: function () {
return function () {
alert(this.name1);
}
}
}
//obj.fun3()();
var obj2 = {};
obj2.name1 = "test";
obj2.fun = obj.fun3();
obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.
var name1 = "张三";
var obj = {
name1: "李四",
fun2: function () {
alert(this.name1);
},
fun3: function () {
return function () {
alert(this.name1);
}
}
}
//obj.fun3()();
var obj2 = {};
obj2.name1 = "test";
obj2.fun = obj.fun3();
obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.
我们来分解下 obj.fun3()() 先是 obj.fun3() 返回一个匿名函数到了window作用域,然后接着调用this就指向了window了。(感觉解释有点勉强,也不知道对不,暂时自己先是这么理解的)
这是学习记录,不是教程。文中错误难免,您可以指出错误,但请不要言辞刻薄。
原文链接:http://haojima.net/zhaopei/519.html
本文已同步至目录索引:一步步学习javascript
一步步学习javascript基础篇(6):函数表达式之【闭包】的更多相关文章
- 一步步学习javascript基础篇(0):开篇索引
索引: 一步步学习javascript基础篇(1):基本概念 一步步学习javascript基础篇(2):作用域和作用域链 一步步学习javascript基础篇(3):Object.Function等 ...
- 一步步学习javascript基础篇(3):Object、Function等引用类型
我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...
- 一步步学习javascript基础篇(8):细说事件
终于学到事件了,不知道为何听到“事件”就有一种莫名的兴奋.可能是之前的那些知识点过于枯燥无味吧,说起事件感觉顿时高大上了.今天我们就来好好分析下这个高大上的东西. 可以说,如果没有事件我们的页面就只能 ...
- 一步步学习javascript基础篇(1):基本概念
一.数据类型 数据类型 基本数据类型(五种) Undefined Null Boolean Number String 复杂数据类型(一种) Object Undefined:只有一个值undefin ...
- 一步步学习javascript基础篇(7):BOM和DOM
一.什么是BOM.什么是DOM BOM即浏览器对象模型,主要用了访问一些和网页无关的浏览器功能.如:window.location.navigator.screen.history等对象. DOM即文 ...
- 一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)
上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承. 一.原型链继承 1.通过设置prototype指向“父类”的实例来实现继承. function Obj1() { this.name1 ...
- 一步步学习javascript基础篇(4):面向对象设计之创建对象(工厂、原型和构造函数等模式)
前面我们介绍了可以通过Object构造函数或对象字面量都可以用来创建单个对象,但是如果需要创建多个对象的话,显然很多冗余代码. 接下来介绍几种模式来创建对象.不过在此之前,我们还是先来了解下 type ...
- 一步步学习javascript基础篇(2):作用域和作用域链
作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = & ...
- 一步步学习javascript基础篇(9):ajax请求的回退
需求1: ajax异步请求 url标识请求参数(也就是说复制url在新页面打开也会是ajax后的效果) ajax异步请求没问题,问题一般出在刷新url后请求的数据没了,这就是因为url没有记录参数.如 ...
随机推荐
- LeetCode 22. Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- NotePad++中如何出去闪烁的光标?
当在写代码时出现的光标闪烁(横线闪烁),在键盘上找 Insert ,按这个Insert就可以把横向闪烁光标( _ )修改成竖向闪烁光标样式( | ),横向光标会在你写代码的时候修改前面的代码,把光标移 ...
- 【Java并发系列01】Thread及ThreadGroup杂谈
img { border: solid black 1px } 一.前言 最近开始学习Java并发编程,把学习过程记录下.估计不是那么系统,主要应该是Java API的介绍(不涉及最基础的概念介绍), ...
- 12.Java中Comparable接口,Readable接口和Iterable接口
1.Comparable接口 说明:可比较(可排序的) 例子:按照MyClass的y属性进行生序排序 class MyClass implements Comparable<MyClass> ...
- Windows7 64位系统搭建Cocos2d-x-2.2.1最新版以及Android交叉编译环境(详细教程)
Windows7 64位系统搭建Cocos2d-x-2.2.1最新版以及Android交叉编译环境(详细教程) 声明:本教程在参考了以下博文,并经过自己的摸索后实际操作得出,本教程系本人原创,由于升级 ...
- winform快速开发平台->让有限的资源创造无限的价值!
最近一直在维护一套自己的快速开发平台. 主要应对针对C/S架构下的项目.然而对winform这快,还真没有看到过相对好的快速开发平台, 何为快速,在博客园逛了了好久, 预览了很多通用权限管理系统. 确 ...
- Nginx - Linux下按天分割日志
待完善. 可参考:https://www.iteblog.com/archives/1244
- npm 基础
npm账户 npm adduser npm whoami 初始化项目: npm init --scope=<username> 项目必要文件 README.md pageage.json: ...
- [翻译svg教程]Path元素 svg中最神奇的元素!
先看一个实例 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999 ...
- mysql数据库表的自增主键号不规律,重新排列
mysql数据库表的自增主键ID乱了,需要重新排序. 原理:删除原有的自增ID,重新建立新的自增ID. 1.删除原有主键: ALTER TABLE `table_name` DROP `id`; 2. ...