• 预解析-案例


    js预解析

    js引擎在代码正式执行之前会做一个与处理的工作:

      1、收集变量

      2、收集函数

      依据:

        将变量通过var提前到当前作用域最前面声明但不赋值var username = undefined

        函数提前到当前作用域最前面定义

    1 console.log(username);  //undefined,不会报错,因为会提前声明
    2 var username = 'shelly'; 
    3 console.log(username)  //shelly
    4 
    5 fun(); //输出fun(),不会报错,因为函数会被就提前定义
    6 function fun(){
    7     console.log('fun()');
    8 }

    上边的代码经过预解析之后就是这样

    1 var username;
    2 function fun(){
    3     console.log('fun()');
    4 }
    5 console.log(username);  //undefined,不会报错,因为会提前声明
    6 username = 'shelly'; 
    7 console.log(username)  //shelly
    8 fun(); //输出fun(),不会报错,因为函数会被就提前定义

    案例一:

     1 function Foo(){
     2     getName = function(){ alert(1);};
     3     return this;
     4 }
     5 Foo.getName = function(){ alert(2);};
     6 Foo.prototype.getName = function(){ alert(3);};
     7 var getName = function(){ alert(4);};
     8 function getName(){ alert(5);};
     9 
    10 // 请写出下列的输出结果
    11 Foo.getName();
    12 getName();
    13 Foo().getName();
    14 getName();
    15 new Foo.getName();
    16 new Foo().getName();
    17 new new Foo().getName();

    按代码执行顺序,先进行预解析,即变量和函数的提升。

    1 function Foo(){
    2     getName = function(){ alert(1);};
    3     return this;
    4 }
    5 var getName; //该getName会被第六行的getName覆盖
    6 function getName(){ alert(5);}; //该getName会被第9行的getName覆盖
    7 Foo.getName = function(){ alert(2);};
    8 Foo.prototype.getName = function(){ alert(3);};
    9 getName = function(){ alert(4);};

    解析完后的代码

    1 function Foo(){
    2     getName = function(){ alert(1);};
    3     return this;
    4 }
    5 Foo.getName = function(){ alert(2);};
    6 Foo.prototype.getName = function(){ alert(3);};
    7 getName = function(){ alert(4);};
    第一问:Foo.getName();  //2  
    找到Foo这个构造函数(也是个对象),调用它的静态方法
    第二问:getName();   //4   
    预解析后 getName = function(){ alert(4);};

    第三问:Foo().getName(); //1
    调用Foo这个构造函数,调用就会执行Foo内部的代码,该局部作用域也会进行预解析,执行到getName时,发现他没有进行声明,就会去全局下找有没有这个getName,
    如果没有就声明一个,如果有就会重新赋值。所以此时,getName = function(){ alert(1);};
    return this, 函数内部的this具体指谁,要看调用它的是谁就是看.前面是谁。Foo()其实省略了window.Foo();因此this指向window
    最后变成了window.getName(); 也就是被重新赋值后的getName 。是1

    第四问: getName(); //1
    经过第三问的分析,此时window.getName = function(){ alert(1);};

    第五问: new Foo.getName(); //2

    整理下优先级:new (Foo.getName()); 先调用Foo的静态方法,就变成 new (function(){ alert(2);};)()

    了解下new过程会做些什么
    1、创建空对象;var obj = {};
    2、设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象;
      obj.__proto__ = ClassA.prototype;
    3、使用新对象调用函数,函数中的this被指向新实例对象:

      ClassA.call(obj);  //{}.构造函数(); 执行构造函数内的代码,并把this指向obj  
    4、返回新对象obj
    总而言之,new的过程会执行一次函数内的代码,也就是弹出个2

    第六问: new Foo().getName(); //3
    整理下优先级 (new Foo()).getName(); new Foo()会得到一个Foo的实例对象,再调用实例对象上的getName方法,
    实例对象上的方法会先搜索实例本身看有没有该方法,没有则搜索原型上有没有,没有才会搜索构造函数本身。明显,原型上有,所以会弹出3

    第七问: new new Foo().getName(); //3
    整理下优先级:new ((new Foo()).getName());参照第五问和第六问的原理,会弹出3


     
    奔跑的蜗牛
  • 相关阅读:
    数据不须要自由,但须要做爱
    编程算法基础-3.2自底向上风格
    Linux管道符
    阿里云 oss python3 样例
    6. Laravel5学习笔记:IOC/DI的理解
    LNMP环境搭建——MySQL篇
    在奋斗的日子里,傻笑出来(三)
    捕获海康威视IPCamera图像,转成OpenCV能够处理的图像(一)
    vs 默认的INC和LIB
    一款DIY移动电源的性能
  • 原文地址:https://www.cnblogs.com/xiaoyue-/p/10653949.html
Copyright © 2020-2023  润新知