函数表达式与闭包

Posted Rank-Bill

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数表达式与闭包相关的知识,希望对你有一定的参考价值。

===============闭包与函数==
函数的两种方式:函数声明与函数表达式
函数申明的语法:
Function functionName(arg0,arg1,arg2)

其中function是关键字 +函数名 部分浏览器会给函数定义一个非标准的name属性
通过这个属性可以访问到指定的名字 function.name

函数申明重要特征是函数声明提升(function declaration hoisting)意思是执行代码前会读取函数申明。

函数表达式var fucntionName()=function(arg0.arg1,arg2)

;

可以看到functionName也即是指向函数的引用
很明显该创建的函数后面没有标识符 因此为匿名函数此时我们可以看到其实两者指向的均为函数本省

但两者并不是完全一样的 可以看到表达式中name属性为空字符串



注意使用函数申明与函数表达式的返回;

此时函数返回为undefined

如果用表达式形式则会返回 此时我们需在前面声明一个全局的变量接受返回
很明显依照 if语句 if(condition) statement1 else statement2
这两个语句可以是代码或代码块:
If (condition) Alert(“statement1”);
或:
If(condition)Alert(“statement2”)
所以上面例子中里面加入函数明显的代码是不符合语法的但是浏览器会尽可能的修复,看出测试中返回的是undefined ,但是为什么使用函数表达式后会返回函数引用的值呢?
我们可以看到复值运算符返回类型:

这样也就很好解释执行if里面的语句后返回的是condition的值

有时候也会在函数的返回中
比如直接在函数中返回匿名函数
Function compare()
Return function(arg0,arg1)

;

递归函数:
何为递归函数:也即是通过函数名调用自身的情况

Function factoria(num)
If(num<=1)
return 1;
else
return num*factorial(num-1);


然而但我们在代码中将factorial置空后就会产生很大的问题:
为什么会有将他置空的行为了:很明显在代码开发中希望 以前的或别人的代码不会影响到自己的代码 2.当攻击者或其他原因时会给代码造成影响;
其实js设计的思想最好做到互不影响 如:少用全局变量,等

第二行导致指向原始的引用只有一个而函数中又要调用factorial导致错误



Factorical
Indexnum

可以看到指向的是同一个函数的引用将factotial置空后也即是变为空了。后面在找时也找不到

解决办法:
1.非严格模式下:arguments.callee 指向正在执行的指针
2.

注意console若前面有错误则不会向下进行

此时仍正常返回指向函数 命名函数表达式 此时区别于匿名函数 因为在函数代码中要使用到该函数 并且要不受到外部的影响 此时用fac(5)即可执行该函数,此时大家会问为什么了。
其实我们在函数引用时候也是这样用的使用 fac=f; fac(5);f(5) 这里只是更加稍微饶了个弯而已。



此时nonefunction(5)大家会很熟悉的 ,从上面例子可以看到将nonefunction置空后会删除一个引用 而另外一个引用可以正常使用。可以认为函数名与将函数值复制后的变量绝大部分的性质是相同的,当然前面提到过两者的name属性的返回不一样。也可以看出js中是不存在指针的指针两者都会指向同一原始引用。
我们可以用:两个指针变量在验证当将函数名置空后其他变量是否仍然可以返回。可以看到其他的两个并不会受到置空的影响。

函数闭包:
闭包是指有权访问另一个函数作用域中的变量值
相信作用域链的问题大家很苦恼,其实函数执行会有上下文的环境里面存放的东西我们暂且不关心 类似于在c语言中函数调用要保存上下文环境一样。

我们以书本(javascript)的函数为例子详细解析这段代码的执行

关注参数object1,object2对象模型 之后用到了object1[propertyName]和object2[propertyName]
此时我们复习以下对象的初始化:可以使用对象字面量或new强攻的方式
New强攻的方式
Var person=new object();
Person.name=”object”;
对象字面量的方式
Var person=
name:”object”, //逗号分隔 属性名:属性值(自动转字符串) 属性名
5:true
;
杂交法:
Var person=
Person.name=”object”;
访问对象属性可以使用点表示法或者使用方括号的表示法(. ,[])

调用传递对象字面量参数的时候 display(name:object,age:25)

当每个函数第一次调用时都会创建一个执行环境(execution context)与相应的作用域链 并把作用域链赋值给特殊的内不属性:[[scope]] (在jquery或angularjs中都会用到),然后使用this argument或其他命名参数的值来初始化函数的活动对象(active object)
作用域链中外部函数始终处于第二位 ,之后的便会由此开始递推

提取从其中的比较函数并命名为compare()函数进行分析
Function compare(value1,value2)


Var result=compare(5,10);

由上面的图可以很清楚的看到每次函数的活动对象将会压入链表头 作用域链本质是指向变量对象的指针列表,只引用但不包含实际的变量对象
函数中访问一个变量时,就会从作用域中搜索具有相同名字的变量
函数只想完后局部活动对象销毁,只包含全局的作用域。
但是前面提到过闭包是指有权访问另一个函数作用域中的对象,既然不采用闭包时的作用域采用的是如上图的形式 每访问变量都会从作用域链中进行查找。很明显我们必须在作用域链中加入一个指向外部函数的引用,那么外部函数放在哪里呢?很显然前面说过外部函数始终放在第二位开始(序号为1),一旦链接上,此时内部函数可以访问外部函数作用域内的任何变量。
当执行完后返回后,其作用域的会被销毁但活动对象仍然会留在内存中,直至内部函数的引用完成后才可以销毁。

This,
This对象基于函数的执行环境绑定,全局中this等于windows,而当函数作为某个对象的方法时 this指向该对象。
匿名函数的执行环境具有全局性,因此其this对象通常指向window,

Object.getNameFunc()表示执行了外部函数

在加上一个()即object.getNameFunc()()
可以看到返回的是全局中的自变量
为什么我在函数里面却访问到的却是外部的东西了,其实每次都会从作用域链上进行查找
每个活动调用时都会取得两个特殊的变量:this和arguments。当内部函数搜索是都只会搜索到该活动对象为止
匿名函数的作用域具有全局性
也即是作用域顶上指向的全局windows,并不会找到其外部函数也即是两者清白的没有发生任何关系 只是住在了一起。如果钥匙忘带了的话还是得房东先处理

如果在外部中加入
Var that=this;

而在内部函数中 return that.name 则会相当于两者发生了微妙的关系 比如房东知道后 通知了你住在一起的人,住在一起那家伙的配了把钥匙给你 that=this 你回来时候必须叫他的名字才能开门 that.name很明显两者的作用域链是存在交叉的

此时输出的是

区分上面的不同 在于调用getNameFunc()返回的是匿名函数或者是表达式 匿名函数里再返回什么与表达式返回什么

YcUstc

以上是关于函数表达式与闭包的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript函数表达式

第五篇 函数进阶

函数表达式--总结

Swift学习笔记:闭包

闭包 (全局变量与局部变量)

闭包函数与装饰器