菜鸟请教这个关于js原型链的demo


<script type="text/javascript">
    function Person(name,age) {
        this.name = name;
        this.age = age;
    }
    Person.say = function(){
        alert('Person的say');
    }
    Object.prototype.say = function(){
        alert('Object原型的say');
    }
    Function.prototype.say = function(){
        alert('Function原型的say');
    }    
    Function.say = function(){
        alert('Function的say');
    }
    Person.prototype.say = function() {
        alert(this.name);
    };
    let p = new Person('月初',16);
    p.say();
</script>

这个本站的demo
为什么弹出的是月初而不是“Person的say”,哪位帮忙解释下

这样去说在一个对象实例化之前,这个对象其实也就是一个函数

参照你的问题 为什么弹出的是 月初 而不是 “Person的say” ?

首先你要考虑一个问题,在对象没有被实例化之前,他只是一个首字母大写的函数,那如果给函数直接定义一个 .方法的话找的是谁?

万物不变起源 万物皆对象 抛去其他的一切因素 调用 Person.say() 寻找的层级先滤清 先找 Person.say -> Function.prototype.say -> Object.prototype.say, 你可以先这样去试一下

  <script type="text/javascript">
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }

    Object.prototype.say = function () {
      alert("Object原型的say");
    };
    Function.prototype.say = function () {
      alert("Function原型的say");
    };
    Function.say = function () {
      alert("Function的say");
    };
    Person.prototype.say = function () {
      alert(this.name);
    };
    // Person.say = function () {
    //   alert("Person的say");
    // };
    // let p = new Person("月初", 16);
    Person.say(); // 寻找层级 Person.say -> Function.prototype.say -> Object.prototype.say
  </script>

而如果你的对象实例化之后,这个时候其实他已经被new了,那么他就不再会是一个函数,而是一个对象,如果没有父实例,那么他的上级指向将不再会是 Function,参照下方

<script type="text/javascript">
    function Person(name,age) {
        this.name = name;
        this.age = age;
    }

    Object.prototype.say = function(){
        alert('Object原型的say');
    }
    Function.prototype.say = function(){
        alert('Function原型的say');
    }    
    Function.say = function(){
        alert('Function的say');
    }
    // Person.prototype.say = function() {
    //     alert(this.name);
    // };
    Person.say = function(){
        alert('Person的say');
    }
    let p = new Person('月初',16);
    p.say(); // alert('Object原型的say');
</script>
</html>

简单的说 Person.prototype.say != Person.say 一个是在其对象原型上挂载say方法,一个是在其方法上挂载一个say方法,而原型链查找的是 prototype 所以会出现你所说的找不到的问题

Person.say类似于oo语言的静态方法,需要通过类名称来调用,而不是实例。
Person.prototype.say则是实例方法,p为实例,所以p.save()输出月初。

要输出Person的say,应该是Person.say()

img

  1. Person是p的构造函数而非原型,这是一个三层的关系,实例-构造函数-原型p - Person - Person.prototype,原型链说的是实例会共享对应原型上的方法,因此p.say访问的是Person.prototype.say而不是Person.say。
  2. 同理怎么理解Person的原型是Function.prototype呢?我们可以知道Person是函数,它可以看作是是new Function()来的,因此它的构造函数肯定是Function,同样的也可以理解为三层,实例-构造函数-原型Person - Function - Function.prototype,因此Person.say()原本应该会alert出Function原型的say,但是由于你对Person.say赋值,可以理解为重写了,因此输出的是Person的say,你不妨把Person.say重写的部分删掉,你就看见输出它原型Funtcion的say了。
  3. 另外因为各种原型本身是个对象,因此它是Object的实例,也可以用三层的方式理解,你可以随便用一个原型,比如p.prototype(或者Person.prototype或者Funtion.prototype) - Object - Object.prototype
    如果你能耐心看懂,你就完全掌握原型链了,附上我写的博客,讲的都很通俗:https://blog.csdn.net/weixin_43877799/article/details/120325606
您好,我是有问必答小助手,您的问题已经有小伙伴帮您解答,感谢您对有问必答的支持与关注!
PS:问答VIP年卡 【限时加赠:IT技术图书免费领】,了解详情>>> https://vip.csdn.net/askvip?utm_source=1146287632