new new Foo().getName()面试题解析

经典面试题 Foo().getName() 解析

题目如下,写出输出内容(注释:abcde为步骤标号,便于下边分析定位)

// a.
function Foo () {
 getName = function () {
   console.log(1);
 }
 return this;
}
// b.
Foo.getName = function () {
 console.log(2);
}
// c.
Foo.prototype.getName = function () {
 console.log(3);
}
// d.
var getName = function () {
 console.log(4);
}
// e.
function getName () {
 console.log(5);
}

Foo.getName(); 
getName(); 
Foo().getName(); 
getName(); 
new Foo.getName(); 
new Foo().getName(); 
new new Foo().getName();

解析:

1. Foo.getName();  // 2

Foo为一个函数对象,对象都可以有属性,题目 b 处定义Foo的getName属性为函数,输出2


2. getName(); // 4

这里看d、e处,d为函数表达式,e为函数声明,两者区别在于变量提升,这两处可以等价于

var getName = undefined;
// e处提升到顶部
getName = function () {
 console.log(5);
}

...
// d. 重新赋值
getName = function () {
 console.log(4);
}
// e.

...

可见函数声明的 5 会被后边函数表达式的 4 覆盖。


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

这里要看a处,在Foo内部将全局的getName重新赋值为 console.log(1) 的函数,执行Foo()返回 this,这个this指向window,Foo().getName() 即为window.getName(),输出 1。


4. getName();  //  1

上述3中,全局的getName已经被重新赋值,所以这里依然输出 1。


5. new Foo.getName();  // 2

这里等价于 new (Foo.getName()),先执行 Foo.getName(),输出 2,然后new一个实例;


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

这里等价于 (new Foo()).getName(), 先new一个Foo的实例,再执行这个实例的getName方法,但是这个实例本身没有这个方法,所以去原型链__protot__上边找,实例.__protot__ === Foo.prototype,所以输出 3。


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

这里等价于new (new Foo().getName()),如上述6,先输出 3,然后new 一个 new Foo().getName() 的实例。

补充:

关于上述 5中 new Foo.getName()先执行 Foo.getName(),而6中 new Foo().getName() 先执行 new Foo(),是因为

  • new Foo() 属于new(带参数列表)
  • new Foo属于new(无参数列表)

无参数列表的优先级为18,而成员访问的优先级为19,高于无参数列表。因此new Foo.getName()先执行Foo.getName()

带参数列表的优先级为19,而成员访问的优先级也为19,按照运算符规则(同一优先级,按照从左向右的执行顺序),new Foo().getName()先执行new Foo(),再对new之后的实例进行成员访问.getName()操作。
这是js运算符的优先级链接,可查看每个运算符的优先级。

猜你喜欢

转载自blog.csdn.net/RedaTao/article/details/107955687
new