-
定义函数
定义函数方式:函数声明,函数表达式;
函数声明:有函数声明提升,可把函数声明放在调用它的语句后面
函数表达式:创建一个函数并将它赋值给一个变量,这种情况下创建的函数叫做匿名函数,该函数表达式在使用前必须先赋值匿名函数与普通函数的区别:
-
闭包
有权访问另一个函数作用域中的变量的函数,常见创建方式,就是在一个函数内部创建另一个函数内部函数的作用域链中包含外部函数的作用域,当函数被调用时,会创建一个执行环境及相应的作用域链。
每个执行环境都有一个表示变量的对象:变量对象,局部环境的变量对象,只在函数执行的过程中存在。
-
在创建函数时:会创建一个预先包含外部环境的变量对象的作用域链,该 作用域链被保存在内部的[[Scope]]属性中,作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
-
调用函数时:会为函数创建一个执行环境,然后复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链,创建该函数的活动对象并推入执行环境作用域链的前端,则其作用域链中包含的变量对象:本地活动对象和复制而来的活动对象
-
-
作用域链
如下有一个全局环境下的函数function compare(value1, value2) { if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { return 0; } } var result = compare(5, 10);
其作用域链如图所示:
闭包函数的作用域链原理相同function fun1(name) { return function () { console.log(name) } } var re = fun1('wang') re() //解除对匿名函数的引用(以便释放内存) re = null
当
fun1
执行完毕以后,其作用域链被销毁,但是其内部匿名函数的作用域链还引用着fun1
的活动对象,所以fun1
的活动对象不会被销毁,匿名函数被销毁后,fun1
活动对象才会被销毁 -
匿名函数的执行环境具有全局性,其 this 对象通常指向 window;
var obj={ sayName(){ console.log(this) //指向obj return function(){ console.log(this) //指向window } } } obj.sayName()() //{sayName: ƒ} //Window
obj.sayName()()
的执行顺序等同于var a=obj.sayName() //把匿名函数赋值给变量a a() //执行该函数,则该函数中的this指向全局window
这样就很容易看出
sayName()
方法中的匿名函数的this指向window -
闭包的变量问题
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){ return i; }; } return result; } createFunctions() //[ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ] createFunctions()[1]() //10 createFunctions()[3]() //10
看似每个函数都应该返自己的索引值,但实际上,每个函数都返回 10
因为每个函数的作用域链中都保存着 createFunctions() 函数的活动对象(是指针指向不是副本),即每个函数都引用同一个变量 i 。 当执行了createFunctions()后,变量 i 的值已经是 10,此时每个函数都指向该变量 i ,所以在每个函数内部 i 的值都是 10。(关键理解作用域链只引用不实际包含活动对象)解决1:立即执行函数
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; }
每次执行 立即执行函数时,都把i值以num副本的形式保存在相应的函数中
解决2:letfunction createFunctions(){ var result = new Array(); for (let i =0; i < 10; i++){ result[i] = function(){ return i; } } return result; }
-
利用闭包创建私有作用域
(function(){ var date=new date() })()
在该函数中定义的任何变量,都会在函数立即执行结束时被销毁,这样限制向全局作用域中添加过多的变量和函数,来减少命名冲突
红皮书函数
最新推荐文章于 2021-11-17 10:47:55 发布