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

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会被盖掉,所以这里是5;

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看下结果吧。

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

版权声明:本文为petterguo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/petterguo/p/9152956.html