原型链以及继承

原型链

原型链类似关系链,几乎所有的js对象都会有通过原型链prototype继承过来的方法或者属性,
javac#中也存在一个默认继承的对象。js通过原型链给父类增加方法和属性,
子类就会产生对应的方法和属性,类似c#的扩展方法。改变某个对象的原型链可以改变其继承的父类。

  1. 当存在创建一个Object.prototype.test=function(){}的时候,几乎所有的js对象都会存在一个test的方法。
  2. 当存在创建一个Number.prototype.test=function(){}的时候,几乎所有的js数字对象都会存在一个test的方法。
  3. 当存在创建一个String.prototype.test=function(){}的时候,几乎所有的js字符串对象都会存在一个test的方法。

其中__proto__不一定相等于prototype,
只有函数才有prototype__proto__属性,对象只有__proto__
每个对象都会在其内部初始化一个属性,就是__proto__
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,
那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__
于是就这样一直找下去

关于继承的方式

  1. 通过实例化父类设置prototype方法来继承对象的方法

    function p(){this.log=function(){}}
    function c(){}    
    c.prototype=new p //会继承p的方法
    Object.getPrototypeOf(new c);//输出 c.__proto__ 对象
    
  2. 通过实例化父类设置prototype方法来继承对象的prototype方法

    function p(){}
    p.prototype.log=function(){}
    function c(){}    
    c.prototype=new p //会继承p的方法
    Object.getPrototypeOf(new c);//输出 c.__proto__ 对象   
    
  3. 通过父类的prototype设置prototype方法来继承对象的prototype方法

    function p(){this.logp=function(){}}
    p.prototype.log=function(){}
    function c(){}    
    c.prototype=p.prototype //会继承p的prototype里面方法,不会继承logp
    c.prototype.test=function(){}
    Object.getPrototypeOf(new c);//输出 c.__proto__ 对象     
    
  4. 通过实例化父类设置子类实例化的__proto__方法来继承对象的方法

    function p(){this.logp=function(){}}
    p.prototype.log=function(){}
    function c(){}    
    var obj=new c;
    obj.__proto__=new p; //会继承p的prototype里面方法以及logp方法
    Object.getPrototypeOf(obj);//输出 c.__proto__ 对象   
    
  5. 通过改变在改变父类this的作用域的方式来执行父类方法继承父类的方法

    function p(){this.logp=function(){}}
    p.prototype.log=function(){}
    function c(){p.call(this)}    
    var obj=new c;  //只会继承logp方法
    

原型链相关的方法

  • hasOwnProperty
 Array.prototype.log=function(){}
 Array.prototype.hasOwnProperty('log') //true
 for(key in []){console.log(key)} //log

如果没有判断就会导致遍历出扩展的方法

  • defineProperty
  Object.defineProperty(object, propertyname, descriptor)

参数

object: 定义的对象
propertyname:参数名称
descriptor:定义的描述信息

descriptor

参数的键 描述 默认值
configurable 属性能否被删除或者重新定义 false
enumerable 遍历对象的时候属性是否可见 false
value 属性值,当设置后不能设置getset undefind
writable 属性能否改变
get 当获取属性的时候触发 undefind
set 当设置属性的时候触发 undefind

资料说writable默认值为false,但是当不设置这个参数的时候,value是可以改变的,持怀疑态度,求解

  var user={};
  Object.defineProperty(user, 'name', {
        get:()=>{
            console.log(`get value:${this.name}`)
            return this.name;
        },
        set:value=>{
            console.log(`set value:${value}`)
            this.name=value;
        }
  });

注:下面设置会抛出异常

  var user={};
  Object.defineProperty(user, 'name', {
        value:'johe',
        get:()=>{
            console.log(`get value:${this.name}`)
            return this.name;
        },
        set:value=>{
            console.log(`set value:${value}`)
            this.name=value;
        }
  });
  //Uncaught TypeError: Invalid property descriptor. 
  //Cannot both specify accessors and a value or writable attribute, #
 
 
  • defineProperties
    Object.defineProperties(object, props)

参数

object: 定义的对象
props: 添加的属性, keyvalue 分别Object.defineProperty 中的第二和第三个参数。

  • getPrototypeOf
    Object.getPrototypeOf("test") //String {length: 0, [[PrimitiveValue]]: ""}

返回当前对象的原型链对象

__proto__prototype的区别

  1. __proto__prototype相等的时候

     function c(){}
     c==c.prototype.constructor //true
     c==(new c).constructor //true
     (new c).__proto__===c.prototype //true
    

(new c).__proto__c.prototype,(new c).constructor.prototype都是恒等的。
一旦prototype被赋予属性和方法,那么函数创建的实例会继承prototype上的属性和方法

  1. __proto__prototype存在不相等的时候

     function c(){}
     c.prototype={
         log:function(){}
     }
     c==c.prototype.constructor //false
     c==(new c).constructor //false
     (new c).__proto__===c.prototype //true
     (new c).constructor===Object //true;
    

重写了c.prototype后,(new c).__proto__c.prototype还是恒等的,
但是c.prototype.constructor指向了Object,而不是c,因为{}默认是Object

你可能感兴趣的:(原型链以及继承)