理解函数提升的关键,就是理解函数声明与函数表达式之间的区别。
arguments.callee是一个指向正在执行的函数的指针
函数对象属性:caller;这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。
function outer(){ inner() } function inner(){ console.log(arguments.callee.caller) } outer()
示例闭包函数
function createCompareFunction(propertyName){ return function(obj1,obj2){ let val1 = obj1[propertyName],val2 = obj2[propertyName]; if(val1 < val2){ return -1 }else if(val1 > val2){ return 1 }else{ return 0 } } }
解析:在一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。因此,在createCompareFunction函数内部定义的匿名函数的作用域链中,实际上将会包含外部函数createCompareFunction的活动对象。在匿名函数从createCompareFunction中被返回后,它的作用域链被初始化为包含createCompareFunction函数的活动对象和全局变量对象。这样匿名函数就可以访问在createCompareFunction中定义的所有变量。createCompareFunction函数执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当createCompareFunction函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中,直到匿名函数被销毁后,createCompareFunction的活动对象才会被销毁。
注:所以使用闭包不及时释放内存,会造成内存泄漏。像V8等优化后的JavaScript引擎会尝试回收被闭包占用的内存。
MST
var obj = { name:'zjy', getName(){ return ()=>{ return this.name } } } var name = 'lyn' var obj = { name:'zjy', getName(){ return function(){ return this.name } } } var name = 'lyn' var obj = { name:'zjy', getName(){ var that = this return function(){ return that.name } } }