原型和原型链

作者: simon_李玉兵 | 来源:发表于2019-01-20 23:15 被阅读46次

    函数也是对象。每个函数都有一个属性prototype,指向函数的原型对象。所有原型对象都会自动获得一个constructor属性,这个属性是一个 指向prototype属性所在函数的指针。


    构造函数模式

    function Person (name, age, job) { // 构造函数
      this.name = name
      this.age = age
      this.job = job
      this.sayName = function () {
        console.log(this.name)
      }
    }
    
    var person1 = new Person('jose', 18, 'Doctor') // 实例
    var person2 = new Person('jack', 20, 'programer')  // 实例
    

    创建Person实例,必须使用new操作符。以上方式调用构造函数将经历一下4步
    1)创建一个新对象;
    2)将构造函数的作用域给新对象(因此this就指向这个新对象)
    3)执行构造函数中的代码(为这个新对象添加属性)
    4)返回新对象


    构造函数的问题

    就是每个方法都要在每个实例上重新创建一遍。就像上述的person1person2sayName函数。这样子就会非常消耗内存。因为每次执行 function () {},都要在heap(堆内存)中开辟一个新的空间来存储。但是上述的两个实例,sayName方法都是一样的。


    原型模式

    利用构造函数的prototype(原型)。prototype属性指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。

    function Person () {} // 构造函数
    Person.prototype.name = 'jose'
    Person.prototype.age = 12
    Person.prototype.job = doctor
    Person.sayName = function () {
      console.log(this.name)
    }
    var person1 = new Person () // 实例 有一个属性__proto__指向构造函数的原型对象
    person1.name // "jose"
    var person2 = new Person() // 实例 有一个属性__proto__指向构造函数的原型对象
    person2.name // "jose"
    console.log(person1.sayName === person2.sayName) // true
    

    当调用构造函数创建函数后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。这个属性叫[[prototype]]__proto__

    关系

    实例如何读取属性

    执行person.sayName时,首先会搜索实例中是否含有该属性,如果在实例中找到了,就返回该返回该属性的值,如果没有找到则继续搜索原型对象。
    实例中的属性会屏蔽原型对象中的同名属性 。


    更简单的原型语法

    function Person () {}
    Person.prototype = {
      constructor: Person,
      name: "jose",
      age: 12,
      job: 'doctor',
      sayName: function () {
        console.log(this.name)
      }
    }
    

    此时将prototype属性指向另一个对象了。constructor将显式赋值。

    原型模式的问题

    function Person () {}
    Person.prototype = {
      constructor: Person,
      name: 'jose',
      age: 12,
      job: 'doctor',
      friends: ['jack', 'tom', 'ming'],
      sayName: function () {
        console.log(this.name)
      }
    }
    var person1 = new Person ()
    var person2 = new Person ()
    person1.friends.push('van')
    console.log(person2.friends) // "jack, tom, ming, van"
    console.log(person1.friends === person2.friends) //true
    

    组合使用构造函数和原型模式

    function Person (name, age, job) {
      this.name = name
      this.age = age
      this.job = job
      this.friends = ['jack', 'tom']
    }
    Person.prototype = {
      constructor: Person,
      sayName: function () {
        console.log(this.name)
      }
    }
    var person1 = new Person('jose', 12, 'doctor')
    var person1 = new Person('van', 22, 'teacher')
    person1.friends.push('count')
    console.log(person1.friends) // "jack, tom, count"
    console.log(person2.friends) // "jack, tom"
    console.log(person1.friends === person2.friends) // false
    console.log(person1.sayName === person2.sayName) // true
    

    继承

    让原型对象等于另一个类型的实例

    function SuperType(){ 
        this.property = true; 
    } 
    SuperType.prototype.getSuperValue = function(){
        return this.property; 
    }; 
     --------------------
    function SubType(){ 
        this.subproperty = false; 
    } 
     
    //继承了 SuperType 
    SubType.prototype = new SuperType(); 
     
    SubType.prototype.getSubValue = function (){ 
        return this.subproperty; 
    }; 
     -----------------------
    var instance = new SubType(); 
    console.log(instance.getSuperValue());      //true 
    
    image.png

    还有默认的原型

    image.png

    原型链的问题

    function SuperType(){ 
        this.colors = ["red", "blue", "green"];
    }
    function SubType(){             
    } 
     
    //继承了 SuperType 
    SubType.prototype = new SuperType();  // 此时colors数组被放进了prototype中实现了共享
     
    var instance1 = new SubType(); 
    instance1.colors.push("black"); 
    console.log(instance1.colors);     //"red,blue,green,black"
     
    var instance2 = new SubType(); 
    console.log(instance2.colors);      //"red,blue,green,black" 
    

    组合继承

    function SuperType(name){ 
        this.name = name; 
        this.colors = ["red", "blue", "green"]; 
    } 
     
    SuperType.prototype.sayName = function(){ 
        alert(this.name); 
    }
    function SubType(name, age){   
     
        //继承属性 
        SuperType.call(this, name); 
         
        this.age = age; 
    } 
     
    //继承方法 
    SubType.prototype = new SuperType();  // 此时SubType.prototype中也含有colors:["red", "blue", "green"]和name: undefined。但是将被实例中的同名属性覆盖
    SubType.prototype.constructor = SubType; 
    SubType.prototype.sayAge = function(){ 
        alert(this.age); 
    }; 
     
    var instance1 = new SubType("Nicholas", 29); 
    instance1.colors.push("black"); 
    alert(instance1.colors);      //"red,blue,green,black" 
    instance1.sayName();          //"Nicholas"; 
    instance1.sayAge();           //29 
     
    var instance2 = new SubType("Greg", 27); 
    alert(instance2.colors);      //"red,blue,green" 
    instance2.sayName();          //"Greg"; 
    instance2.sayAge();           //27 
    

    201.png

    当没有代码时,原始的构造函数将被初始化。


    image.png

    JavaScript高级程序设计(第3版)

    相关文章

      网友评论

        本文标题:原型和原型链

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