美文网首页
最详尽的 JS 原型与原型链终极详解记录

最详尽的 JS 原型与原型链终极详解记录

作者: 安静的牛蛙 | 来源:发表于2018-12-16 16:59 被阅读0次

    该文章来自于最详尽的 JS 原型与原型链终极详解,没有「可能是」的学习总结

    一:对象的分类

    • JS中对象分为两种,函数对象普通对象。也称为Function Object和Object。通过typeof 可以查看具体的对象类型。
    • JS中的函数对象,在和new结合的时候,可以创建新的对象。JS提供了两个最基本的函数对象 FunctionObject。其他所有的对象都由这两个函数对象演进而来
    • JS中的函数对象,有两个方法可以创建,一个是通过new Function(),一个是通过function() {}声明。
    • JS中的普通对象,也有两个方法可以创建,一个是通过 new (非Function函数对象/**Object**) ,一个是通过 { }等各类语法声明。Array也可视为一个普通对象,可以通过new Array(),也可以通过[]
    • 另外,还有一个特殊的Object.create()方法,可以由一个普通对象创建一个新的普通对象。此时第一个普通对象起到类似函数对象的作用,不同之处在于,新建对象的__proto__指向第二个普通对象自身。因为普通函数没有prototype属性(这个可以看完下面的回头再理解下)。
    var o1 = {}; 
    var o2 =new Object();
    var o3 = new f1();
    var o4 = Object.create(o2)
    
    function f1(){}; 
    var f2 = function(){};
    var f3 = new Function('str','console.log(str)');
    
    console.log(typeof Object); //function 
    console.log(typeof Function); //function  
    
    console.log(typeof f1); //function 
    console.log(typeof f2); //function 
    console.log(typeof f3); //function   
    
    console.log(typeof o1); //object 
    console.log(typeof o2); //object 
    console.log(typeof o3); //object
    console.log(typeof o4); //object
    

    二:prototype 和 __proto__

    • JS中的任意一个对象都包括一个 __proto__属性。该属性在ES2015之前,并没有在标准中明确定义,而是一个大多数浏览器默认支持的一个属性,也称为[[prototype]]
    • JS中的任意一个函数对象都包括了一个prototype属性。该属性相当于是当前函数对象的一个特殊实例。一般为普通对象。
    • JS中任意一个对象的__proto__属性,根据new的特性,都指向创建该对象的函数对象的prototype属性。即
    (普通对象).__proto__ == (创建它的函数对象).prototype
    (函数对象).__proto__ == Function.prototype  // 函数对象都由 new Function()创建
    

    FunctionObject都是函数对象,都是通过new Function()创建,所以

    Function.__proto__ == Function.prototype
    Object.__proto__ == Function.prototype
    
    • JS中的函数对象的prototype一般都为普通对象即
    typeof A.prototype == 'Object'  // A
    

    Function除外,因为Function的新建实例还是一个函数对象,所以

    typeof Function.prototype == 'function'
    

    但是该prototype是一个特殊的函数对象。它没有prototype,另外,它的__proto__指向了Object.prototype,而不是Function的prototype,即

    typeof Function.prototype == 'function'
    Function.prototype.__proto__ == Object.prototype
    
    • JS中的所有函数对象的prototype都有一个constructor函数,称为构建函数,该构建函数指向当前函数对象。即
    function f1() {}
    f1.prototype.constructor == f1
    Function.prototype.constructor == Function
    
    • prototype,__proto__以及constructor的关系图


      image.png

      其中的person1.constructor其实是通过原型链继承在Person.prototype中寻得。

    三:原型链继承

    JS中的原生继承是通过原型链完成的。以下面的代码为例子

    var Person = function(name){
      this.name = name; 
    };
    Person.prototype.getName = function(){
      return this.name;  // tip: 当函数执行时这个 this 指的是谁?
    }
    var person1 = new person('Mick');
    person1.getName(); //Mick
    person1.name; //Mick
    person1.toString(); // [object Object]
    
    • 当person1执行getName方法的时候,先在person1的自身属性中寻找。此时自有属性只有name属性,未找到,则继续在person1的__proto__属性中寻找
    • 因为person1.__proto__ = Person.prototype。此时在Person.prototype中寻找getName属性,此时寻找得到,将Person.prototype.getName返回作为person1.getName,进行执行。
    • 当person1执行toString方法的时候,在Person.prototype中未能找到,则继续在Person.prototype.__proto__中寻找。
    • Person.prototype作为Person的一个特殊实例,它是普通对象。普通对象都由new Object创建。因此Person.prototype.__proto__ = Object.prototype。因此继续在Object.prototype中寻找,发现了toString方法,将Object.prototype.toString返回作为person1.toString,进行执行。
    • 需要注意,JS中的原型链继承,指的是新建对象和创建函数对象的prototype之间的关系,而不是和创建函数的关系。能够在原型链继承上传递下去的只有原型对象prototype上的函数。比如Object拥有geOwnPropertyNames方法,但Object.prototype却不包含,所以person1也无法拥有getOwnPropertyNames 方法。同样的,如果新建一个函数对象Student,让它继承Person函数对象,那么new Stuednet()新建的对象也只能继承Person.prototype.getName,而不能继承person.name属性

    四:JS中原型链继承链路

    • Function函数对象
    Function.__proto__ == Function.prototype
    Function.prototype.__proto__ == Object.prototype
    Object.prototype.__proto__ == null
    
    • Object函数对象
    Object.__proto__ == Function.prototype
    Function.prototype.__proto__ == Object.prototype
    Object.prototype.__proto__ == null
    
    • 自定义函数对象
    function f1() {}
    f1.__proto__ == Function.prototype
    Function.prototype.__proto__ == Object.prototype
    Object.prototype.__proto__ == null
    
    • 自定义函数对象实例--也是普通对象
    function f1() {}
    o1 = new f1()
    o1.__proto__ = f1.prototype
    f1.prototype__proto__ == Object.prototype
    Object.prototype.__proto__ == null
    
    • 自定义函数对象继承--继承自某一个自定义对象
    function f1() {}
    function f2() {} // 设定f2继承自f1,具体如何实现继承,可以查看另一篇文章
    o2 = new f2()
    o2.__proto__ = f2.prototype
    f2.prototype.__proto__ = f1.prototype
    f1.prototype__proto__ == Object.prototype
    Object.prototype.__proto__ == null
    

    五:总结

    • 所有的普通对象,都会继承(1)创建它的函数对象的prototype上的属性(2)函数对象继承自其它函数对象prototype上的属性(3)Object函数对象的prototype上的属性
    • 所有的函数对象,都会继承(1)Function.prototype上的属性(2)Object函数对象的prototype上的属性
    • 最后所有的对象的原型链都会追溯到null标识符上

    六:Function和Object自带属性

    参考链接

    https://www.jianshu.com/p/dee9f8b14771
    https://www.jianshu.com/p/652991a67186
    https://www.jianshu.com/p/a4e1e7b6f4f8

    相关文章

      网友评论

          本文标题:最详尽的 JS 原型与原型链终极详解记录

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