彻底理解js的原型链

作者: csRyan | 来源:发表于2017-02-28 15:37 被阅读312次

    本文主要参考了MDN文档知乎讨论

    在js中,大部分东西都是对象,数组是对象,函数也是对象,对象更加是对象。不管我们给数组和函数定义什么内容,它们总是有一些相同的方法和属性。比如说hasOwnProperty(),toString()等:

    chrome的控制台是很好的学习工具!

    这说明一个对象所拥有的属性不仅仅是它本身拥有的属性,它还会从其他对象中继承一些属性。当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类推,这就构成了对象的原型链。理解js的原型链对使用js的对象非常有帮助。

    chrome强大的控制台可以显示出每一个对象所有的属性!包括prototype、__proto__、constructor等,你可以自己试试!

    让我们通过一个例子由浅到深地理解原型链:

    function Foo(_name) {
      this.name = _name;
    }
    Foo.prototype.show = function() {
      console.log('I am ', this.name);
    };
    var f1 = new Foo('obj1');
    var f2 = new Foo('obj2');
    
    f1.show();  //  I am obj1
    f2.show();  //  I am obj2
    

    这是我们经常使用的创建对象的方式,将共同的方法放到Foo.prototype中,所有实例都共有这个方法了。

    这是怎么实现的呢?我们看下面这张图的第一行:


    jsobj_full.jpg

    我们先只用看第一行。

    我们定义的show函数在Foo.prototype中,当我们执行f1.show()时,js发现f1本身没有show这个属性,所以它就到f1的原型(也就是__proto__指向的对象)去找,找到了就可以调用。

    注:每个对象都有一个方法hasOwnProperty()来检查对象本身是否有某个属性,如果有则返回true;如果这个属性在它的原型链上或原型链上都没有,则返回false;

    图片第一行告诉了我们4点:

    1. 所有函数都有一个prototype指针,指向原型对象,如图中的Foo的prototype指针。prototype指针的意义是,当我们使用这个构造函数new出新对象的时候,新对象的原型是谁
    2. 构造函数的prototype所指向的原型对象有一个constructor指针,指回构造函数。如图中Foo.prototype的constructor指针指向Foo。constructor指针有助于我们找到一个对象的构造函数是谁。
    3. __proto__每个对象都有,js在new一个对象的时候,会将它的__proto__指向构造函数的prototype指向的那个对象。在上图中,f1、f2这些实例对象的__proto__都指向了Foo.prototype。
    4. 如果一个对象的__proto__指向了另一个对象,那么前者就继承了后者的所有属性。

    请注意__proto__与prototype的区别!__proto__才是真正连接原型链的东西,而prototype只是构造函数的一个指针属性而已。

    理解了这个小例子我们就可以往图片的下面看了,它展示了js原生对象的继承关系是怎么样的。

    我们先看看Foo的原型吧!Foo是一个函数,它的构造函数是js内部的function Function(),Function的prototype指向了一个对象Function.prototype,因此Foo的__proto__就指向了Function.prototype,如图。

    所有的函数都以function Function()为构造函数,因此,所有函数(包括function Function()和function Object())的__proto__都指向Function.prototype这个对象,这个对象中定义了所有函数都共有的方法,比如call()、apply()等。

    我们继续深入下去,Function.prototype这个对象,它就是一个普通的对象,它的构造函数是js内置的function Object(),function Object()的prototype指向Object.prototype,因此Function.prototype.__proto__就指向Object.prototype,这个对象中定义了所有对象共有的属性,比如我们之前说的hasOwnProperty()和toString()等。

    同理,Foo.prototype和其他自定义的对象也是__proto__指向Object.prototype对象,就不需要说明了。

    Object.prototype就是原型链的终点了,它的__proto__是null,js查找属性时,如果到这里还没有找到,那就是undefined了。

    到这里就不难理解为什么我们说在js中,函数也是对象了,它就是继承自对象的!

    如果如有疑问,欢迎指出!

    相关文章

      网友评论

      • 宽广宁静:"所有函数都有一个prototype指针,指向原型对象,如图中的Foo的prototype指针。prototype指针的意义是,当我们使用这个构造函数new出新对象的时候,新对象的原型是谁。" ,这句话有误。新对象的__proto__才是Foo的prototype 。 不知道对不对?
        csRyan:新对象的__proto__是Foo的prototype 。你说的是对的。原文也是这个意思呀。

      本文标题:彻底理解js的原型链

      本文链接:https://www.haomeiwen.com/subject/apqxgttx.html