zoukankan      html  css  js  c++  java
  • Js 预加载

    开始 所有的测试,都是chrome浏览器。

      js本身是脚本语言,可以不经过编译直接运行,但是在进入每一个<script>标签,或者js文件的时候,这样的情况下,浏览器会给js一个预编译的过程。

    这样就有必要讨论一下预编译了。

      解析的状态是首先引入一个代码段,也就是之前提到的标签或者文件。读入整个代码段,进行解析,解析的方式是遇到变量就声明,

    对变量声明为undefined,对函数做标记,这个就是预解析,但是如果声明了同名的函数,使用最后一个。变量都是undefied,只有触发的时候,才会激活。

     

    首先举一个例子:

    var a;
    alert(a);
    a = 10;
    alert(a);
    

      预编译的时候,将a设定为undefined。当执行第一个alert的是,会弹出undefined,因为此时a并没有被赋值。

      运行到第二个的时候,弹出10.

    alert(a);
    

       直接一句,浏览器会报错。Uncaught ReferenceError: a is not defined。因为a并没有被定义。这是肯定的,

    但是:

    alert(a);
    a = 10;
    

      同样是:Uncaught ReferenceError: a is not defined。这里能证明 如果不是var,那么a=10;虽然js也是定义了一个全局变量,

    但是并没有什么用,在预编译阶段,js无法在a=11之前引用它。并不知道a是什么,所以alert(a),并不能识别出来a的存在。证明js

    解析是根据字符匹配来解析的,find到var的时候,才会定变量。尽管不是强类型的与语言,但是也无法在预编译的阶段,处理好不带

    var 关键字的全局变量。

      

    在看函数的例子:

    console.log(test);
    
    function test() {
    	console.log('haige');
    }
    

      oK,没有问题,会把函数打印出。

    但是在看这个例子:

    console.log(test);
    
    var hg = function test() {
    	console.log('haige');
    }
    

      Uncaught ReferenceError: test is not defined。证明,你声明了一个函数,给hg这个变量赋值,但是没什么用,这是什么,是函数表达式。不是函数声明!!!!

     修改一下,在看。

    console.log(test);
    
    var test = function test() {
    	console.log('haige');
    }
    

      undefined 为什么呢?因为test此时是个变量,不是函数。OK,比如这样来看。

    console.log(typeof test);
    
    var test = function test() {
    	console.log('haige');
    }
    

      打印的是undefined。因为预编译的时候,只是声明了一个test变量,证明有,而不知道他是什么。所以无法判断类型。

    在举一个例子:

    var foo = 1;      
    function bar() {    
      console.log(foo);  
        if (!foo) {      
            var foo = 10;   
        }      
        console.log(foo);      
    }      
    
    bar();
    

      猜猜看,还是挺有意思的, 第一个console.log()打印的是 undefined。为什么呢?在bar的这个函数作用域中,用var 声明了一个foo的对象,但是,第一次使用时候,由于没有赋值,

    所以就出现了undefined的情况,在第二次打印的时候,就已经初始化了,函数执行,是触发式执行方式,从上到下。

    在举一个更酷的例子

    var a = 1;      
    function b() {      
      console.log(a);  
        a = 10;      
      console.log(a);  
        return;      
        function a() {}  
    }  
    
    b();      
    console.log(a);  
    

      思考一下,这个怎么玩出来,

     第一个打印,a 是一个 function a () {}

     第二个肯定就是10了。

     思考一下为什么,预编译的时候,首先声明了一个全局的a,这个a是一个对象,但是值是undefined,

    执行b()函数的时候,给b做预编译。此时,a是function,虽然有return,但是,编译的时候肯定不是看到return就返回了,肯定都编译了。

    这样a就变成了一个指向函数的变量。那么执行b()的时候,第一个打印就成function a() {}

    执行第二打印的时候,a=10; 所以打印出10.

              变量内的赋值,实在执行的时候完成的,而不是声明的时候。

    这里在举一个例子证明变量的声明和赋值之间的关系。

    a();
    var a = function() {};
    console.log(a);
    

      Uncaught TypeError: a is not a function.

    在var声明的变量中,在预编译的过程中,都是undefined,当你执行var声明的变量时,才开始触发它所对应的值。

    这里的a是变量,虽然给他赋值了函数的指针,但是并没有什么用。因此,在var a = function 之前是无法解析的。

    这个浏览器内核,按照变量的声明方式解析,不按照类型解析。

     

     之后在思考一下函数之间的预编译问题。

    function hg(){   
      alert('hg');   
    };   
      
    hg();   
    function hg(){   alert('wj'); }; hg();

      思考一下应该如何弹出,结果是两个都是 wj。为什么呢?

    很简单,因为函数的解析第二个hg,将第一个覆盖了,而hg是函数名,其实就是一个指针,那么hg将指针的指向,转移到了第二个函数,导致的结果就是,

    两次执行,都执行的一个函数,这再次证明了预编译的存在,因为预编译,更改了第一个hg函数的指向。

     在看一个例子:

    var ys = function(){
    	alert('hg');
    };   
    ys();
    ys = function(){ alert('wj'); }; ys();

      ys ()这个函数,其实是在预编译的时候,是个变量,为什么呢?因为var,让编译器知道,他是一个变量,而类型,不是预编译阶段所关心的问题,

    在执行第一个ys的时候,OK,根据上下文,ys被赋值为第一个函数。那么就是打印hg,

    当执行第二个ys的是,这个时候,ys被赋值为第二个函数,就执行 wj。

     还有个例子,很酷的例子。两段代码,做个对比。

    (1)

    console.log(ys);    //function hg
    
    function ys(){
    	console.log('hg');  
    }
    ys();     // hg
    
     
    var ys = function (){
    	console.log('wj');
    }   
    ys();   //wj
    

      思考一下,很酷的,在看第二个。

    (2)

    console.log(ys);    //function hg
    
    var ys = function (){
    	console.log('wj');
    }   
    ys();   //wj
    
    function ys(){
    	console.log('hg');  
    }
    ys();    // wj
    

      这两个例子做了对比,产生了几个很有意思的观点。

    首先,如果函数和变量同名,那么,打印出来的就是一个函数,而不变量,这个跟你是否是var定义无关。即使是var定义的变量,依旧,把这个变量,类型变为函数。这个,下一个例子,会看得更清楚。

    其次,由于变量的存在,所以是存在运行时动态的赋值的。所以,第一个才会出现ys更改的情况。

    但是这里要注意一点,为什么两次的第一个console.log,都打印hg呢?因为var a = function A() {}; 这个在预编译的时候,是不执行的。所以,根本达不到更改ys指针的情况。

    上面提到的下一个例子:

    console.log(ys);    //function
    
    function ys(){
    	console.log('hg');  
    }
    console.log(ys);    //function   
    var ys = 1;
    

      

      打印的是function 和 function 。为什么? 证明:上面提到的,当变量与函数同名的时候,预编译的时候,函数会覆盖变量。

    console.log(ys);    //function
    
    function ys(){
    	console.log('hg');  
    }
    var ys = 1;
    console.log(ys);    //1
    

      这种情况了,是因为ys在运行到ys=1是,被重新赋值了。

    在变量实例化的过程中出现同名,优先级的关系是,声明式函数》函数参数》变量

  • 相关阅读:
    vue doubleclick 鼠标双击事件
    我是如何通过CSRF拿到Shell的
    js生成一个不重复的ID的函数的进化之路
    浅谈企业内部安全漏洞的运营(一):规范化
    如何让微信丢骰子永远只出“666”
    全能无线渗透测试工具,一个LAZY就搞定了
    关于8月31日维基解密被攻击的观察与分析
    VS2013 单元测试(使用VS2013自带的单元测试)
    解决WCF部署到IIS出现“证书必须具有能够进行密钥交换的私钥,该进程必须具有访问私钥的权限”
    VS2013 MVC Web项目使用内置的IISExpress支持局域网内部机器(手机、PC)访问、调试
  • 原文地址:https://www.cnblogs.com/hgonlywj/p/4979632.html
Copyright © 2011-2022 走看看