zoukankan      html  css  js  c++  java
  • 变量申明的提升,闭包,作用域,this,运算符优先级详细举例及讲解

    function Foo() {
    getName = function () { alert (1); };
    return this;
    }
    Foo.getName = function () { alert (2);};
    Foo.prototype.getName = function () { alert (3);};
    var getName = function () { alert (4);};
    function getName() { alert (5);}
    //请写出以下输出结果:
    Foo.getName();
    getName();
    Foo().getName();
    getName();
    new Foo.getName();
    new Foo().getName();
    new new Foo().getName(); 

    整个题目涉及到很多知识:首先我们要理解执行上下文:http://blog.163.com/no_404/blog/static/2412460752014102683438277/

    我们可以知道在第一问之前js已经做了哪些事:   

    function Foo(){};
    var getName;//变量申明的提升:即所有申明变量或者申明函数都会被提升到当前函数的顶部
    /*
    例如:console.log('x' in window);//true
             var x; x = 0; 
    此代码执行的时候js引擎会将申明语句提升至代码最上方变为:
    var x;
    console.log('x' in window);//true
    x=0;
    
    函数表达式的申明也会提升:
    console.log(x);//输出:function x(){}
    var x=1;
    function x(){} 
    
    实际执行的代码先将 var x=1 拆分为 var x; 和 x = 1; 两行,再将 var x; 和 function x(){} 两行提升至最上方变成:
    var x;
    function x(){}
    console.log(x);
    x=1; 
    
    */
    function getName(){};
    Foo.prototype.getName;
    Foo.getName = function () {};
    Foo.prototype.getName = function () {};
    getName = function () {};

    执行第一问Foo.getName();的时候相当于激活了Foo.getName;也就是:

    Foo.getName = function () { alert (2);};//所以答案是2

    执行第二问的时候getName();相当于激活对全局getName函数的调用,因为有两次对getName方法的书写,所以后面一次会覆盖第一次的方法,也就是对函数变量getName赋值的方法会覆盖掉直接申明函数getName时候对方法的实现,即执行getName=function(){alert(4);}所以答案是4;

    执行第三问Foo().getName();先执行了Foo()函数function Foo(){getName=function(){alert(1);};return this;},这个函数执行时返回一个this,this此时为当前对象Foo函数,然后再调用返回值对象的getName函数,此时激活Foo()的变量函数getName=function(){alert(1);}也就是Foo函数的属性:getName函数,所以此时返回1;

    执行第四问的时候因为第三问激活并执行了Foo().getName();此处foo()函数里面的getName函数因为没有加var命令,所以里面的getName()函数是一个全局变量,所以第三问执行之后,之前第二问时候全局变量为alert(4)的getName()被重写了,所以此时getName()函数运行结果为1;

    第五问,new Foo.getName();此处需要知道js运算符优先级:

    我们先看看运算符分优先级:

    可以知道.的优先级高于new,圆括号优先级高于.;所以此式子正确打开方式是:new (Foo.( getName() ));注意此时的Foo没有加括号 也就是说只是调用它的属性,前面加上了new 相当于将Foo的成员getName函数作为了构造函数执行,所以答案是2;

    第六问:正确打开方式:new (Foo().getName()) ;new Foo() 返回this,this在构造函数中代表一个当前实例化对象,所以最终返回的是实例化对象,再调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,所以到当前对象的原型对象(prototype)中寻找getName,找到了,执行,alert 3;

     第七问:new new Foo().getName(); 正确打开方式:new (new (Foo().getName());跟第六问一样,先初始化Foo的实例化对象,然后对其原型上的getName函数作为构造函数再次new,最终结果是3。

  • 相关阅读:
    币值转换
    抓老鼠啊~亏了还是赚了?
    第十二周作业
    第十一周作业
    第十周作业
    第九周作业
    第八周作业
    第七周作业
    第五周实验报告和总结
    第四次实验报告及总结
  • 原文地址:https://www.cnblogs.com/Decmber/p/5280600.html
Copyright © 2011-2022 走看看