转载

一步步学习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() { }; 如图:

一步步学习javascript基础篇(6):函数表达式之【闭包】

所以只能只用fun1()调用,而不能使用fun2()调用。

其实这里我还是有疑问的?哪位大神知道,望告知。

既然,fun2在外面不能调用为什么在函数内部能调用?虽然在debugger还是得不到fun1。

一步步学习javascript基础篇(6):函数表达式之【闭包】

好了,通过上面的三道题目热身。我们继续今天的主题“闭包”。

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 ;

图解:(不了解作用域链的同学请先看前面的文章 作用域和作用域链 )

一步步学习javascript基础篇(6):函数表达式之【闭包】

2.什么是匿名函数? (仅仅只是解释这个概念)

如:(即,没有名字的函数)

一步步学习javascript基础篇(6):函数表达式之【闭包】

关于对象中函数的返回值是匿名函数时,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

欢迎对个人博客感兴趣的道友加入群:【嗨-博客】 469075305 入群须知

正文到此结束
Loading...