声明提升+原型+作用域+运算符优先级

问题:

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(); 
Foo().getName(); 
getName(); 
new Foo.getName(); 
new Foo().getName(); 
new new Foo().getName(); 

......

这道题考的知识面非常广,如题,考察到了js的声明提升、作用域、原型、new运算符以及运算符优先级的问题。

......

答案:

image.png
// f1
function Foo() {
  getName = function () {
    console.log(1)
  };
  return this;
}
// f2
Foo.getName = function () {
  console.log(2)
}
// f3
Foo.prototype.getName = function () {
  console.log(3)
}
// f4
var getName = function () {
  console.log(4)
}
// f5
function getName() {
  console.log(5)
}

Foo.getName(); // 2
// 调用Foo构造函数的私有属性getName, 上方执行的代码中f2处为getName属性进行了赋值操作,因此调用打印2。

Foo().getName();  // 1
// 首先调用Foo(),返回this, 全局函数Foo的this指向window,因此相当于window.getName()。调用Foo后运行其内部代码声明了一个全局的getName函数,覆盖掉了之前所有对其的全局声明(覆盖f4, f5)。因此调用打印1。

getName(); // 1
// 由于上面调用过Foo方法,使其内部的getName方法对之前所有挂载在window上的getName方法进行覆盖(覆盖f4, f5),因此调用打印1。

new Foo.getName();  // 2
// 原因同第一题,new运算符只是更改了this指向,但与调用打印结果无关。

new Foo().getName();  // 3
// 根据运算符优先级顺序, new Foo()会优先运算,返回一个this指向Foo本身的实例,而Foo内部并没有直接声明过this.getName的值,根据原型链的调用顺序,如果构造函数或者类自己本身没有这个方法,则通过原型链向上寻找,这里f3在其原型上绑定了getName方法,因此本题会访问到f3方法,调用打印3。

new new Foo().getName();  // 3
// 本题首先考察了运算符优先级的知识,这里首先运算的是new Foo(),返回指向其本身的Foo实例对象,再运算.getName(),此时可以参考上一题,通过原型链调用打印3,最后再计算第一个new,返回实例化后的getName函数。

运算符相关内容,建议访问https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
做详细了解。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。