• new new Foo().getName() 一道前端面试题引发的思考


    今天想着邻近毕业季,估计又会有很多稀奇古怪的面试题,看掘金社区的时候看到一道贼有意思的题,一开始看的十分懵逼,后来捋了捋,将心得总结一下。

    function Foo() {
        getName = function () {
            console.log(1);
        }
        return this;
    }
    
    Foo.getName = function () {
        console.log(2);
    }
    
    Foo.prototype.getName = function () {
        console.log(3);
    }
    
    var getName = function () {
        console.log(4);
    }
    
    function getName() {
        console.log(5);
    }
    
    Foo.getName();
    getName();
    Foo().getName();
    getName();
    new Foo.getName();
    new Foo().getName();
    new new Foo().getName();
    

      ok,下面我来一点一点分析一下这段代码到底要做个啥。首先第一个

    Foo.getName(); //2
    

      第一个是2这肯定是没问题的。

    我们继续往下

    getName(); //4
    

      第二个为4的原因为啥不是5呢,这就涉及到变量提升的问题了,因为函数声明会提升到执行环境的顶部,而函数表达式只有变量var getName会提升看起来就像是这样

    function getName(){
       console.log(5);
    }
    var getName;
    
    getName = function(){
      console.log(4);    
    }
    

      所以函数声明getName会被盖掉,所以这里是4;

    ok,继续往下看

    Foo().getName(); //1
    

      这。。。。其实仔细看的话也是可以看出来的,我们在执行Foo()函数的时候getName这个变量提升到外部的全局作用域中了,因为在js中,如果对于一个变量没用用var 或者 let等声明的话,他就默认是全局属性,就是window对象的一个属性。所以在这里我们的全局的getName又被改了

    因为我们Foo()执行的时候返回了this而这里的this就是window对象,关于为什么是window这里不再展开讲,不然就写不完了。。。。

    我们需要知道的是在浏览器中所有全局的声明都是window对象的属性和方法,所以这里我们调用this.getName()就会返回1了。

    这里需要注意的是如果你是在node环境下打印这些值的话,这里是会报错的,因为在node环境下全局对象为global对象,而它区别window对象一个重要区别是,声明的函数,变量不是global的属性,所以你就找不到getName这个方法;而且会影响下一个的取值,下一个就会是4了。

    接下来我们再一次执行

    getName(); // 1
    

      因为已经被修改了,所以不难看出来。接下来

    new Foo.getName(); //2
    

      在这里我们通过new 来返回一个 Foo.getName 的实例。因为new的过程中一步很重要的操作是通过call将this绑定到实例对象上,并将实例对象返回,ok,既然有call的过程那么就很容易明白他这里输出了2;

    我们可以验证一下结果

    var bar = new Foo.getName();
    bar.__proto__.constructor === Foo.getName //true
    

      这样就能更直观的看出,我们这样通过原型链看出他是Foo.getName的实例;

    接下来

    new Foo().getName(); //3
    

      在这里我们通过new Foo()操作返回一个实例对象,这样我们就可以通过原型链__proto__找到getName这个方法并执行他。

    最后

    new new Foo().getName(); //3
    

      这就是最让人懵逼的地方,他到底在干啥呢,其实他和倒数第三个很像,他其实是对Foo().getName这个函数进行了实例化,具体可以看倒数第三个,所以这里会输出3

    而且我们可以在控制台上打印一下

    var bar = new new Foo().getName();

    打印这个bar看下结果吧。

    这道题大致就是这样,如果本人有写错的地方,还望指出,毕竟功力尚浅,欢迎留言进行交流。

  • 相关阅读:
    laravel 5.5 仓库模式 文件之间接口与实现操作
    php 无线分类 根据子级找父级
    php 无限极分类,根据父级 找子级
    laravel5.4 中 dd和dump的区别。
    laravel hash密码生成和密码验证
    oracle建表详细信息
    关于组件的认识
    java的Thread Dump诊断工具
    weblogic连接池
    详解Oracle数据字典
  • 原文地址:https://www.cnblogs.com/petterguo/p/9152956.html
Copyright © 2020-2023  润新知