函数原型链输出结果

分析函数静态方法、实例方法和原型方法的调用优先级

问题

说说下面代码的输出是什么?

function Foo(){
    Foo.a = function(){
        console.log(1);
    }
    this.a = function(){
        console.log(2)
    }
}

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

Foo.a = function(){
    console.log(4);
}

Foo.a();
let obj = new Foo();
obj.a();

解答

输出结果为:

4
2

执行过程分析:

第一次调用 Foo.a()

此时 Foo.a 是直接定义在函数对象上的静态方法,输出 4

执行 new Foo()

构造函数执行时:

  • Foo.a 被重新赋值为输出 1 的函数(覆盖了原来的静态方法)
  • this.a 被赋值为输出 2 的函数(实例属性)

调用 obj.a()

实例属性 obj.a 存在,直接调用,输出 2。原型上的 Foo.prototype.a 不会被访问。

关键点

  • 静态方法定义在函数对象上,通过 函数名.方法名() 调用
  • 实例属性优先级高于原型属性,会屏蔽原型链上的同名属性
  • 构造函数内部可以修改函数对象的静态方法
  • 属性查找顺序:实例自身 → 原型链