预解释继续。。。。。

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

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

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

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

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

例1:

var i=3;
function fn(){
    i*=2;
    return function(n){
        console.log(n*(++i))
    }
}
var f=fn();
f(3)
fn()(3);
f(4);
fn()(3);

解析: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):

从这一步开始才算真正进入差异化:因为f()再执行时,fn被变量f占据,并没有释放,所以不会再一次执行,所以直接套用i值,此时直接执行作为返回值的那个函数,得出结果为4*++i=4*(15+1)=4*16=64;此时全局变量i的值为16;

fn()(3):

这一步我们注意到,没有了全局变量占据着的函数,所以第二步函数已经释放了,来吧从新执行吧,fn() i*=2=16*2=32;fn()(3) 3*(32+1)=3*33=99 ,此时全局变量i的值为33;

我相信大家对预解释都很熟悉,从下题开始浅显的进行预解释,旨在对题的关键点做更细微的诠释,

上面那道题,比较简单,那么如果你认为它完了你就错了!来让我们接着变,接着引申:

此题做稍微的变化:

例2:引申

var i=3;
function fn(){
    i*=2;
    var i=3;
    return function(n){
        console.log(n*(++i))
    }
}
var f=fn();
f(3)
fn()(3);
f(4);
fn()(3);

解析:这道题的思路与上题类似,有一个点需要注意就是函数内部如果有私有变量那么他就不会去别的父级作用域上取值,所以此题中i的值是以私有变量i值为基准:

故解题步骤可以相较于例1,主要变的是私有变量i,不关全局变量的事,所以结果为

12,12,20,12;此题还有一个要点就是全局变量不会主观上释放,但私有变量随着函数执行完毕后随之释放,所以每次除了被变量占据的函数由于不释放私有变量的值依然在累加沿用,其他类似于此题中fn()(3),中的i值都会随着fn释放重新取值;

想一下此类题还能怎么改?相信大家都会想起来,那就是函数传参数,就类似于隐含的私有变量而已,有兴趣的可以一试;

本人做题总结出此类题的小技巧:

做预解释或理解预解释时,1.先看全局是否有var某个变量(假设为f)占据着某个函数,若有则在进行f()时,f不释放;2.若某变量为自执行函数的返回值时,若有则返回,没有则返回undefined;3.在函数执行时看自己作用域内是否有私有变量,若没有则需要注意对全局变量的影响,同时更加需要注意的是函数的声明优先于变量的声明;

  下篇继续来扯扯与面向对象原型相关的预解释,下章依然酸爽。。。。

时间: 2024-10-25 20:20:39

预解释继续。。。。。的相关文章

做预解释题的一点小方法和小技巧

在JavaScript中的函数理解中预解释是一个比较难懂的话题.原理虽然简单,寥寥数言,但其内涵却有深意,精髓难懂.如何在轻松活跃的头脑中将它学会,现在针对我在学习中的一点小窍门给大家分享一下,希望能给大家一些帮助: 万事需遵循"原理"--"预解释"无节操和"this"指向:(可先看例题解析然后结合原理进行学习) (感谢蕾蕾老师给归纳的预解释无节操原理:) 如果函数传参数则先于以下执行,就相当于在函数私有作用域下var了一个变量:根据作用域原理,

JS中的预解释

1.什么是预解释? 在当前作用域下,JS代码执行之前,首先会把带var/function关键字的进行提前的声明(declare)或者定义(defined). 2.预解释是如何操作的? a.带var关键字的在预解释阶段只完成了提前的声明:b.带function关键字的在预解释阶段完成了声明和定义两个操作. 3.预解释的注意点? a.不管条件判断是否成立,判断体中的内容都要进行预解释: 例如:if (!('a' in window)) { var a=12;  //判断'a'是否为window的一个

JavaScript那些事儿-预解释

带var关键字预解释 让我们先看下这段代码执行的结果: alert(n);//弹出undefined var n = 10; 弹出的结果是undefined,为何不是10?让我们再看下面这段代码执行的结果: alert(n); n = 10; 运行报如下错误:,为何这次会报错,原因是代码在运行的时候,没有声明这个变量n:通过这两段代码的比较,我们发现带var关键字和不带var关键字声明的变量是有区别的,带var声明的变量在代码执行之前,似乎浏览器已经给了它们一个初始值undefined,因此我们

预解释-基础

预解释(变量提升):在当前的作用域中,JS代码从上到下执行之前,浏览器会默认的先把所有带var/function关键字的进行提前的声明或者定义对带var变量的是提前声明(declare)对带function关键字的是提前定义(声明+定义)(defined) ->在预解释阶段,带var关键字的只是提前的声明,只有在JS从上到下执行的过程中才会进行定义赋值: 1 //->预解释阶段:告诉浏览器在当前的作用域中(window)有一个名字叫做num的变量:var num; 2 console.log(

课程笔记:——javascript中的预解释2

in:检测某一个属性是否属于这个对象(既可以检测私有的属性,也可以检测公有的属性) --> attr in obj 1.不管条件是否成立,在预解释的时候,判断体中的带var和function的都要进行预解释window下的预解释: var a; -->a=undefined 我们在全局作用域下声明的变量不仅仅是全局变量,也相当于给window增加了一个叫做"a"的属性名 if (!("a" in window)) {//"a" in

课程笔记:——Javascript 中的预解释

1.预解释(变量提升):在当前作用域下,JS代码执行之前,浏览器首先会把所有带var和function关键字的进行提前的声明或者定义var num = 12;声明(declare): var num; -->声明的时候没有赋值,我们的默认值是undefined定义(defined): num=12; 2.带var和带function的预解释不一样:var:在预解释的时候,只声明未定义(只有代码执行的时候才会完成赋值定义)function:在预解释的时候,声明和定义一起完成了(当代码在执行到定义的

预解释的初级理解

1.当浏览器加载html页面的时候,提供一个全局js代码执行的环境,即全局作用域 2.预解释:在当前作用域中,js代码执行之前浏览器会首先把var定义,把function定义且赋值(遇到function开一个内存空间地址,里面存函数内容的字符串) 3.预解释只发生在当前作用域,,如开始在window下预解释 函数执行的时候才会对函数中预解释因为作用域变了 4.js中内存的分类:栈内存和堆内存,栈内存用来提供js执行的环境(全局作用域 私有作用域),堆内存是存储引用数据类型的值(对象的键值对,函数

关于预解释的理解

正式课---预处理 预处理的解释(变量提声) 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有带var和function的进行提前的声明或者定义 1)理解声明和定义 var num =12; 声明(declare):var num; 告诉浏览器在全局作用域中有一个叫num的变量了 定义(defined) num=12;给变量赋值 2)对于带var和function的关键字的在预解释的时候操作还是不一样的 var在与解释的时候只是提前的声明 function在预解释的时候提前的声明+定

预解释

1.什么是预解释? 在当前作用域下,JS代码执行之前,首先会把带var和function关键字的进行提前的声明或者定义 例如: js中私有作用域是可以使用全局作用域的变量的,所以正常来讲,4行应该打印出10而不是undefined,这就是因为demo()被调用时先声明了私有作用域内的a,开辟了一块儿内存来存储它,提前完成了var变量的声明. 在当前作用域下,带有function关键字的在预解释阶段不仅提前声明,而且还会被定义. 则 在当前作用域下, 带var关键字的在预解释阶段只完成了提前的声明

JS 预解释相关理解

1.JS中的内存空间分为两种:栈内存.堆内存 栈内存:提供JS代码执行的环境;存储基本数据类型的值; ->全局作用域或者私有的作用域其实都是栈内存 堆内存:存储引用数据类型的值(对象是把属性名和属性值存储进去,函数是把函数体中的代码当做字符串存储进去) 2.当浏览器加载我们HTML页面的时候,首先会提供一个供JS代码执行的环境->全局作用域(global->window) 3.在JS代码执行之前,浏览器还需要自己做一些事情:把所有带var/function关键字的进行提前的声明或者定义