一道前端面试题

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(); //

代码如上,都可以复制到F12执行看下,等大佬作答,实在懵逼### 题目描述

阅读 4.2k
2 个回答

把你上面的代码分为两部分:

  • 代码部分
  • 问题部分

先看代码部分

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); }

基于以下原因:

  • 函数提升变量提升
  • 函数提升优先级高于变量提升
  • 函数提升不会被变量提升的声明覆盖

改造上面的代码:

function Foo() {
  getName = function(){ console.log(1); };
  return this;
}

function getName(){ console.log(5); } // 注意这里

var getName; // 这里

Foo.getName = function() { console.log(2); };
Foo.prototype.getName = function(){ console.log(3); };

getName = function() { console.log(4); };  // 这里

然后再看问题部分

  1. Foo.getName()
    这个没有什么好说的,执行下面的代码:

    Foo.getName = function() { console.log(2); };

    所以输出2

  2. getName()
    这个再看上面的代码,getName被赋值为function() { console.log(4); };
    所以输出4
  3. Foo().getName()
    这个分两部分:Foo().getName():

    function Foo() {
      getName = function(){ console.log(1); };
      return this;
    }

    执行这个代码之后,getName被重新赋值为function(){ console.log(1); },然后返回this
    这个this指的是谁?Foo()函数调用,没有使用new,所以这个this指的是全局this
    所以现在这个代码变成了全局的getName()的调用,就是赋值的那个getName的函数的调用。
    所以输出1

  4. getName()
    这个现在跟【3】中的getName是一样的。
    所以输出1
  5. new Foo.getName()
    这个写法比较迷惑人,转换一下,就是new (Foo.getName)(),什么意思呢,就是相当于:

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

    这样写是不是清楚一些,所以答案就清楚了。
    输出2

  6. new Foo().getName()
    这个比较简单,简单拆分一下吧:

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

    obj原型链上存在一个getName函数,Foo.prototype.getName = function(){ console.log(3); };
    所以输出3

所以答案就是:2 4 1 1 2 3

参考链接:https://juejin.im/post/5d8d82...

Foo.getName(); // 2,调用 Foo.getName 函数

getName(); // 4
// 原因
// var getName = function() { console.log(4); };
// function getName(){ console.log(5); }
// 这两句都声明 getName 函数,因为变量提升原则,变成了下面的执行顺序:
// var getName;
// function getName(){ console.log(5); }
// getName = function() { console.log(4); } 所以最后执行结果为4

Foo().getName(); //1
// 先执行 Foo(),⚠️ Foo 函数里的 getName 函数前面没有 var/let,所以是个全局变量
// 重写了全局函数 getName,Foo返回的结果是 this,
// 根据默认绑定原则,this 代表全局作用域

getName(); // 1,调用的也是全局函数 getName()

new Foo.getName(); //2
// 等效于 new (Foo.getName()),执行 Foo.getName()

new Foo().getName(); //3
// 等效于 (new Foo()).getName(),先执行 Foo(),得到 this
// 此时 this 是新建的对象,此对象上没有 getName 方法,就去原型链上找
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题