美文网首页
深入理解js中实现继承的原理和方法

深入理解js中实现继承的原理和方法

作者: 龙旗飘扬的舰队 | 来源:发表于2019-01-29 15:09 被阅读11次

    原型对象继承

    • ==原理:原型对象的属性可以经由对象实例访问==
    • 下面的例子,所含【对象继承】和【构造函数继承】,用于理解【原型属性经由对象实例访问】
    //对象继承
    var person = {
      name:"gs",
      age:19
    }
    console.log(person.prototype === undefined );
    function Student(){}
    Student.prototype = person;//原型属性经由对象实例访问
    console.log(new Student());
    //构造函数继承
    function Person(){
      this.name = "gs";
      this.age = 19;
    }
    function Student(){
      this.name = "zk"
    }
    Student.prototype = new Person();//原型属性经由对象实例访问
    var zk = new Student();
    console.log(zk);
    

    Object是顶层对象

    • 所有对象都继承自 Object.prototype,除非显示指定
    • 以对象字面量定义的对象,其 prototype 的值都被设为 Object.prototype

    定义在 Object.prototype 上的方法

    • hasOwnProperty
    • propertyIsEnumerable
    • isPrototypeOf
    • valueOf | 返回对象的值表达
    • toString | 返回对象的字符串表达

    valueOf

    • 每当一个操作符被用于一个对象时(自动)调用

    toString

    • 在进行运算时,有可能发生类型转换
    let obj = { name:"gs" };
    console.log(obj+111)//;[object Object]111
    console.log(obj.toString());//[object Object]
    console.log(obj.valueOf());//{ "name": "gs" }
    

    最好不要去修改 Object.prototype

    最简单的一个对象继承

    • 声明一个字面量对象,相当于自动继承自 Object
    • 声明字面量对象,可以用 Object.create 方法替代,它的继承作用更加明显
    • ==注意:Object.prototype 实际上值是 null==
    var student1 = {
      name:"gs"
    }
    var student2 = Object.create(Object.prototype,{
      name:{
        configurable:true,
        enumerable:true,
        value:"gs",
        writable:true,
      }
    })
    

    实现一个基本的对象继承

    //对象继承
    var person = {
      name:"gs",
      age:19
    }
    console.log(person.prototype === undefined );
    function Student(){}
    Student.prototype = person;//原型属性经由对象实例访问
    console.log(new Student());
    

    实现一个稍复杂的构造函数继承

    • 因为js中的继承是通过原型对象链来实现的,因此没有调用对象父类的构造函数
    • 所以,要注意!最好重写构造器属性,否则将被设为父类的值
    function Person(school,name,age){
      this.school = "beijing univercity";
      this.name = name;
      this.age = age;
    }
    Person.prototype.sayName = function(){
      console.log(this.name);
    }
    Person.prototype.sayAge = function(){
      console.log(this.age);
    }
    
    function Student(name,age){
      this.name = name;
      this.age = age;
    }
    Student.prototype = new Person();
    var gs = new Student("gs",19);
    console.log(gs.constructor);//Person
    Student.prototype.constructor = Student;//注意!要重写构造器属性,否则将被设为父类的值
    console.log(gs.constructor);//Student
    Student.prototype.sayName = function(){
      console.log("student is "+this.name);
    }
    console.log(gs.sayName());
    console.log(gs.sayAge());
    

    实现一个伪类继承(构造函数窃取)

    • 实际上就是使用 call 的方式,将父类的属性“拷贝”到子类中,同时还包括了constructor属性
    • 仍然需要用prototype方式继承方法,同时还要设置constructor
    function Person(school,name,age){
      this.school = "beijing univercity";
      this.name = name;
      this.age = age;
    }
    Person.prototype.sayName = function(){
      console.log(this.name);
    }
    Person.prototype.sayAge = function(){
      console.log(this.age);
    }
    
    function Teacher(school){
      Person.call(this,...arguments);//因为this指向Teacher,所以constructor属性仍将是Teacher
      this.school = school;//注意,新的属性,应置于继承发生之后,以做覆盖
    }
    var zk = new Teacher("haver","zk",23);
    console.log(zk.constructor);//constructor属性正确,为Teacher
    console.log(zk.sayName === undefined);//true,但是,没有继承原型方法和属性
    Teacher.prototype = new Person();
    var zk_2 = new Teacher("haver","zk_2",23);//没有继承原型方法
    console.log(zk_2.sayName());//拿到方法了
    console.log(zk_2.constructor);//Person。不是吧,constructor属性又不对了
    Teacher.prototype.constructor = Teacher;
    console.log(zk_2.constructor);//Teacher。使用call方式继承属性,仍然需要用prototype方式继承方法,同时还要设置constructor
    

    父类方法被子类覆盖,如何仍然可以调用?

    function Person(name,age){
      this.name = name;
      this.age = age;
    }
    Person.prototype.sayName = function(){
      console.log("father method " + this.name);
    }
    Person.prototype.sayAge = function(){
      console.log(this.age);
    }
    
    function Student(){
      Person.call(this,...arguments);
    }
    Student.prototype = Object.create(Person.prototype,{
      constructor:{
        configurable:true,
        enumerable:true,
        value:Student,
        writable:true,
      }
    })
    Student.prototype.sayName = function(){
      console.log("child method");
    }
    Student.prototype.sayName_1 = function(){
      Person.prototype.sayName.call(this);//这是唯一的访问父类的方法
    }
    var gs = new Student("gs",20);
    console.log(gs);
    
    console.log(gs.sayName_1());
    

    创建一个没有原型对象的对象

    • 它不会发生和继承来的属性名相冲突的问题,所以它是一个完美的【哈希容器】
    • 哈希容器也可以理解为是一种映射容器,采用哈希算法(映射算法,散列算法),将不定长的数据压缩成定长的数据,这串定长值我们称为 哈希值
    var obj = Object.create(null);
    console.log(obj.prototype === undefined);
    console.log( valueOf in obj);
    console.log( toString in obj);
    

    相关文章

      网友评论

          本文标题:深入理解js中实现继承的原理和方法

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