深入的Javascript函数、递归和闭包(执行环境、变量对象和范围链)

深入的Javascript函数、递归和闭包(执行环境、变量对象和范围链)
功能性表达

1,在Javascript中,函数有2时钟方法

1-1。函数声明:
复制代码代码如下所示:
功能(arg1,arg2,funcname ARG3){
函数
}

(1)name属性:可以读取函数名。非标准的浏览支持:FF、Chrome、Safari、Opera。
函数声明升级:在代码执行前读取函数声明,也就是说函数调用可以放在函数声明之前。

1-2。函数表达式:
复制代码代码如下所示:
VaR(arg1,arg2 funcname =功能,ARG3){
函数
};

(1)匿名函数(匿名函数,或市拉姆达功能):功能关键词没有标识符的名称属性的值是一个空字符串。当使用一个函数作为一种价值,一个匿名函数可以使用。
与其他表达式类似,函数表达式在使用前需要分配,因此没有函数声明。
(3)ECMAscript无效的函数语法:
复制代码代码如下所示:
IF判断中的重复函数声明

如果(条件){
功能sayhi(){
警告(嗨)!;
}
{人}
功能sayhi(){
警惕(哟!;
}
}

浏览器Javascript引擎纠正错误差异:大多数浏览器将返回第二个语句,忽略条件;当条件为真时,FF将返回第一条语句。
函数表达式的使用可以被解决和实现:
复制代码代码如下所示:
判断函数表达式

VaR sayhi;
如果(条件){
打个招呼=函数(){
警告(嗨)!;
}
{人}
打个招呼=函数(){
警惕(哟!;
}
}

2。递归
递归函数是由一个函数用名称来调用的函数组成的。
复制代码代码如下所示:
函数阶乘(数字):一个经典递归阶乘函数
如果(数字< = 1){
返回1;
{人}
返回num *因子(num-1);
}
}

(1)如果使用下面的代码调用函数,就会出现错误:
复制代码代码如下所示:
无功anotherfactorial =因子;
阶乘=null;
警报(anotherfactorial(4));

当因子()函数保存到变量anotherfactorial,因子变量设置为null,而没有函数引用。(4)执行anotherfactorial阶乘()函数,所以它是错误的。
使用argument.callee(一个函数指针被执行)可以解决:
复制代码代码如下所示:
解决方案

函数阶乘(数字){
如果(数字< = 1){
返回1;
{人}
返回num * arguments.callee(num-1);
}
}

无功anotherfactorial =因子;
阶乘=null;
警报(anotherfactorial(4)); / / 24

在非严格模式,使用递归函数,它是与argument.callee代替函数名更安全
在严格的模式,对argument.callee的使用可以使一个错误,和函数表达式可以用来代替函数声明。
复制代码代码如下所示:
函数表达式而不是函数声明

变量=函数f(数字){
如果(数字< = 1){
返回1;
{人}
返回num * F(num-1);
}
}

4。关闭

在另一个函数域中有权访问变量的函数(常用的函数嵌套形式)。
复制代码代码如下所示:
函数围(临){
返回功能(obj1,obj2){
VaR val1 = obj1 {亲};
VaR val2 = obj2 {亲};
如果(val1 < val2){
返回- 1;
} else if(val1 > val2){
返回1;
其他{ }
返回0;
};
}
}

当一个匿名函数返回时,匿名函数被初始化为一个活动对象和一个包含函数的全局变量对象,也就是说,匿名函数包含了围()函数的作用域。
当调用每个函数时,将创建一个执行环境、一个变量对象和一个相应的动作链。

4-1。执行环境和范围

执行环境执行上下文,简称,定义了变量和函数有权访问的其他数据,并确定它们各自的行为。
每个执行环境都有一个可变对象、变量对象,以保存由环境定义的所有变量和函数。对象不能通过编码访问,但解析器在处理数据时使用后台。
全局变量对象是最外围的执行环境,在Web浏览器中,它被视为一个窗口对象,因此所有全局对象和函数都是由窗口对象的属性和方法创建的。
在执行环境中执行代码后,环境被破坏,其中的变量和函数定义也被销毁。

第二,当代码在环境中执行时,它将创建一个变量对象的范围链范围链,该链用于确保对所有能够访问执行环境的变量和函数进行有序访问。
作用域链的前端始终是当前执行代码的环境中的变量对象,当环境是一个函数时,活动对象用作变量对象。
活动对象开始只有一个变量,即对象的argumnt。
范围链中的下一个变量对象来自于包含的环境,下一个变量对象来自于下一个包含环境,直到它继续到全局执行环境。

(3)标识符解析:从上一段的动作链中搜索标识符在级别和级别上的过程,通常不可能导致错误发生。

当4-2。函数被创建和执行,
复制代码代码如下所示:
功能比较(val1,val2){
如果(val1 < val2){
返回- 1;
} else if(val1 > val2){
返回1;
其他{ }
返回0;
};
}
var结果比较(5, 10);

(1)创建函数比较()时,创建一个包含全局变量对象的动作链,并将其存储在内部{ } }属性中。
(2)局部函数比较()的变量对象仅在函数执行过程中。
当函数被传输时,创建一个执行环境,然后执行环境的作用域链是由复制函数的{ } }属性中的对象构建的。
第一次调用时被调用,比如比较(),活动对象包含此说法,val1和val2,,将创建。
(4)全局执行环境中的变量对象(包括这个、结果、比较)在比较()执行环境的范围链中的第二位链中。
一系列动作的性质是一个指向变量对象的指针的列表,它只引用,但实际上不包含变量对象。
无论什么时候访问函数中的变量,都会为范围链搜索相应的名称变量。

4-3的范围链。关闭

在另一个函数中定义的函数将一个包含该函数的活动对象添加到它的作用域链中。
首先,将null赋值给函数对象,它等于通知垃圾收集例程来清除它。当函数字段链被销毁时,范围链(除全局作用域)将被安全销毁。
因为闭包将包含函数的范围,所以它将占用比其他函数更多的内存

4-4。关闭和变量

作用链的一个副作用:闭包只能得到函数中任意变量的最后一个值。
复制代码代码如下所示:
功能createfunctions(){
var =新数组();
对于(var i = 0;i < 10;i + +){
结果{函数(){
还我;
};
}
返回结果;
}

(1)的createfunctions()函数,将10封到阵列的结果,并将结果返回数组,每个封闭返回自己的指数,但事实上它返回10。
由于每个功能(关闭)的所有createfunctions活动对象()的作用域链功能,它们指的是同一个变量,当createfunctions执行函数时,i的值是10,所以我在关闭10。
该解决方案,而不是使用闭包,创建一个匿名函数,该函数将i值分配给它的参数
复制代码代码如下所示:
功能createfunctions(){
var =新数组();
对于(var i = 0;i < 10;i + +){
结果{函数=(数字){
返回函数(){
返回num;
};
}(一);
}
返回结果;
}

创建一个匿名函数,每个周期执行一次:循环函数的i值作为参数存储在一个匿名函数中。因为函数参数是通过值传递而不是引用的,每个匿名函数中的数值是每个周期i值的副本。

4-5.this对象

该对象在运行时根据函数的执行环境进行绑定。
在一个全局函数中,这等于窗口;当一个函数被一个对象调用时,这是对象。
一个匿名函数的执行环境是全球性的,其对象通常是指窗口。当电话()或()供给变化函数的执行环境,这一点对其对象。
当每一个函数被调用时,两个特殊的变量自动得到:这个和参数。当内部函数搜索这两个变量时,它永远不可能访问外部函数的两个变量,直到它只是为了寻找到期的对象。
但是外部范围中的这个对象被保存在一个可以被闭包访问的变量中,闭包允许访问闭包。
复制代码代码如下所示:
闭包访问外部函数的这个对象。

窗口;

var对象{ { {
名称:我的对象

GetNameFunc:函数(){
var =;
返回函数(){
返回that.name;
};
}
};

警报(对象。getnamefunc)(()); / / myobject

包围函数的参数对象也可以通过闭包来访问。

5。函数声明转换成函数表达式。

Javascript昨晚启动函数关键字函数的声明,但是函数声明不能跟随括号,所以函数(){ }();将会有错误。
要将函数声明转换为函数表达式,应该在函数中添加一对括号。
复制代码代码如下所示:
(函数(){())
块级范围
});
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部