js关于“变量提升、作用域、私有作用域等知识点”高级解题思路

var i = 2,
    x = 5;
var fn = function (x) {
    x += 3;
    return function (y) {
        console.log((x++) + y + (–i));
    }
};
var f = fn(1);
f(2);
fn(3)(4);
f(5);

 
接着上篇文章我们继续探讨关于预解释的问题:当预解释的函数问题遇见诸如内存释放结合的时候,我们需要格外小心,我们都知道JavaScript属于弱类型语言,起初只是作为浏览器的脚本语言,现今js的用途变得越来越广泛,但作为一种单线程语言,性能优化则变得尤为重要,什么异步回调,浏览器自身的垃圾回收机制等各种行为都是为了优化性能。扯远了,闲话少说,接下来步入正题。为了更好,更快的地运行代码,我们需要了解内存释放机制:

答案:f(2) => 7;     fn(3)(4) => 10;    f(5) =>9;

内存包含:堆内存和栈内存
堆内存:用来存放数据的;
    + 对象数据类型的
        + 存的是键值对
key=value;
    + 函数数据类型的
        + 代码字符串
堆内存的释放:
    var a=[1,2,3,4]
    
释放:a=null;
栈内存:本身提供了一个供JS代码执行的环境
    + 包含:全局作用域 和 私有作用域
全局作用域的形成和销毁:
    + 形成:当一个页面被浏览器加载完成的时候,全局作用域就形成了;
    + 销毁:1)关闭页面
2)关闭浏览器
私有作用域的形成和销毁:
    + 形成:当函数被调用的时候,会形成私有作用域
    + 销毁:一般情况下,但函数执行完成的时候,默认就被销毁了;但是两种情况下不销毁:
       + 不销毁:当函数体内的东西被外面的变量或者其他占用的话,就不销毁;
       + 不立即销毁:当函数执行完成的时候,会返回一个函数,被返回的函数还需要再执行一次;只有所有的调用都完成的时候,这个函数才能销毁;
       

解题思路:

简言之:1.就是全局变量类似于 var a=function
fn(){}这种情况下fn
被函数占据,若果变量不重新赋值(或赋值为null),函数就会始终存在于内存中不释放;

  1. var f =
    fn(1);相当于开了一个堆内存(私有作用域),形参赋值。自上而下执行,x赋值为4;

  2. f(2)执行给return function(y)形参赋值,function(y)开辟一个堆内存,x
    在自身作用域没有赋值通过作用域链找上级 x 赋值为4,i
    同样通过作用域链找到全局作用域

  2.当function f1(){return
function
f2(){}}这类一种函数存在于另一个函数作用域中,当调用f2时,f2的执行依赖于f1的执行,此时f1不立即销毁,等f2执行完成后会销毁。

    下的 i 赋值为2;运算(x++)+y+(–i)结果为7   运算后此时的 x
形参赋值为5,全局作用域下的变量 i 为1。

 

  1. fn(3)(4)执行重新开辟了一个堆内存(私有作用域),形参赋值。x 为3,y
    为4。因为上一次的运算使全局作用域的 i 赋值为1.
    所以自上而下执行后此时(x++)+y+(–i)运算结果为10;运算后全局作用域下的变量
    i 赋值为0;

弄明白原理后,我们来根据实例具体阐述:

4.f(5)执行同f(2)一样形参赋值,但是要注意的是经过自上而下的运算后此时的 x
赋值为5,i 赋值为0;(x++)+y+(–i)运算结果为9;运算后此时的 x
形参赋值为6,全局作用域下的变量 i 为负1(-1)。

例1:

5.附一张详细解题配图!!!!图片 1

 1 <script>
 2     var i=3;
 3     function fn(){
 4         i*=2;
 5         return function(n){
 6             console.log(n*(++i))
 7         }
 8     }
 9     var f=fn();
10     f(3)
11     fn()(3);
12     f(4);
13     fn()(3);
14 </script>

    

 

  

解析:1.解题思路:做此类题时,我的做法是先不考虑什么预解释,先通篇看一下在全局变量中是否有函数被全局变量占据,此题var
f=fn();fn函数被全局变量f占据,所以类似于执行f()执行时,函数fn永远不会释放,里面i的值依然依次利用。但fn()(),恰好相反,执行依次释放依次,每次调用彼此之间互不影响。此上我觉得应该才是考点。

2.接下来正式解题,先对变量和函数进行预解释,var
i;function fn(){ i*=2;returnfunction(n){
        console.log(n*(++i))
    }
};var f;

3.代码从上到下执行:i=3;f=fn()=function(n){
        console.log(n*(++i))
    }  *fn()执行后的结果就是它的返回值

4.开始真正的做题:(谨记此题全局变量提供一切私有变量的值)

f(3):

就相当于function(3){
        console.log(3*(++i))
    }

 
解析:当前作用域中没有i;所以上级作用域去找找到i*=2;依然没有确切的值继续沿着作用域链找i=3;找到后再沿着反方向计算回去,i=6;所以最后console的结果为3*7=21;此处又有一个知识点i++和++i的区别,i++是先执行算,如果此题换成i++,就运算完了3*6=18;然后在i++=7;而++i正好相反,它是先运算后执行,先自身++为7再运算*3结果为21,此处我们应该可以想起刚才解析的考点,关键点说三遍,函数f不释放!不释放!!不释放!!!**此时全局变量i=7**

fn()(3):

 
解析:这也是考察的基本原理,函数fn执行后得到的函数再执行得到结果,fn()执行i*=2,因为全局变量i值为7,,所以i=2*7=14;
 fn()(3)此时console的值为3*++i=3*(14+1)=3*15=45;所以值为45;因为没有变量的占据,fn必须得释放;此时全局变量i的值为15;

 

f(4):