继承再理解(6中继承方式利弊)

今天听了学长的分享会,感觉加深了自己对原型的理解,所以写个小作文记录一下。

原型基础知识:
1.prototype 属性

function Person(name,age){
        this.name = name;
        this.age = age;
        this.sayname = function(){
            alert(this.name);
        }
    }

    var person1 = new Person('kang','90');

1.解析:
这里的person1为Person的一个实例,每个实例都有一个constructor属性,该属性
是一个指针指向Person

 console.log(person1.constructor == Person);  //true

事实上每个函数对象都会有一个prototype属性,这个属性指向函数的原型对象。
实际上换一种写法或许更加明白

Person.prototype = {
        name:"kang",
        age:29,
        sayname:function(){
            console.log("...");
        }
    }

所以原型对象就是Person.peorototype而原型对象回又一个constructor属性,该属性指向构造函数

//console.log(Person.prototype.constructor == Person);  //true

2.proto 属性
JS 在创建对象(不论是普通对象还是函数对象)的时候,
都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。

以上述例子为例
    function Person(name,age){
         this.name = name;
         this.age = age;
         this.sayname = function(){
             alert(this.name);
         }
     }
     var person1 = new Person('kang','90');

解析1: 实例person1有一个__proto__属性,创建它的构造函数时Person,
构造函数的原型对象是Person.prototype,所以有

  console.log(person1.__proto__ == Person.prototype)  //true

而继承就是以原型链为基础进行引申,废话不多说开始继承

/第一种继承方式:原型式继承/

   Father.prototype.qq = "861918672";
    function Father(name,age){
        this.name = "kang"|| name;
        this.age = "100" || age;
        this.car = ["bmw","lanbo","masha"];
    }
    Son.prototype = new Father();
    function Son(){

    }
    var son1 = new Son();
    var son2 = new Son();
    console.log(son1.name)  // kang
    console.log(son1.age)   //100
    console.log(son1.car)  //["bmw", "lanbo", "masha"]
    console.log(son1.qq);//861918672
 //第一个缺点: 不能传参
    // var son3 = new Father("tom","29");
    // console.log(son3.name);  //kang
    // console.log(son3.age);   //100
    //解析:可以看出虽然添加了参数,但是做了无用功
//第二个缺点:引用值共享
    // son1.car.push("dazhong");
    // console.log(son1.car);  //["bmw", "lanbo", "masha", "dazhong"]
    // console.log(son2.car);  //["bmw", "lanbo", "masha", "dazhong"]
    //解析:可以看出实例son1和son2都可以共享car属性

** 第二种继承方式:借用构造函数实现继承 (伪造对象或者经典继承)**

Father.prototype.qq = "861918672";
    function Father(name,age,car){
        this.name = name;
        this.age = age;
        this.car = car;
    }
    function Son(name,age,car){
        Father.call(this,name,age,car);
    }
    var grandson1 = new Son("kang","99",["baoma"]);
    var grandson2 = new Son("jiahao","98",["benchi"]);

    console.log(grandson1.name);  //kang
    console.log(grandson1.age);   //99
    console.log(grandson1.car);   //["baoma"]

    优点:解决了引用值共享和传参的问题
    缺点:不能继承父亲原型链上的属性:
    console.log(grandson1.qq);  //undefined

** 3.组合继承 通过上面两种继承方式,我们可以发现,原型链式继承不能传递参数,
而经典继承不能继承父类原型链上的方法,所以组合继承就时由这两种继承方式组成。**

  Father.prototype.qq = "861918672";
    function Father(name,age,car){
        this.name = name;
        this.age = age;
        this.car = car;
    }
    Son.prototype = new Father();
    Son.prototype.constructor = Son;
    function Son(name,age,car){
        Father.call(this,name,age,car);
    }   
    var son1 = new Son("kang","29","baoma");  
    
    console.log(son1.name)  // kang
    console.log(son1.age)   //29
    console.log(son1.car)  //baoma
    console.log(son1.qq);//861918672

可以看见,组合继承完美弥补了上面两种继承方式的缺点,也是用的最多的一种继承方式。先使用原型继承方式,使得子类可以继承到父类原型上的方法,之后使用经典继承使得子类可以继承父亲身上的方法。为保证 son和 son2 拥有各自的父类属性副本,我们在 Son 构造函数中,还是使用了 Person.call ( this ) 方法,这样他们可以有属于自己的属性,也可以使用相同的方法了。如此,结合原型链继承和借用构造函数继承,就完美地解决了之前这二者各自表现出来的缺点。

缺点:两次调用构造函数,效率低。
     改变了子类的construcotr指向

** //第四种继承:4.原型式继承**

     function Object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    var obj = {
        name:'kang',
        sex:'man',
        saymymessage:function(){
            return this.name + this.sex;
        },
        skills:['唱','跳','rap']
    }
    var obj2 = Object(obj);
    var obj3 = Object(obj);
    console.log(obj2.name)  //"kang"
    console.log(obj2.sex)   //"man"
    console.log(obj2.saymymessage())  //"kangman"
    console.log(obj2.skills);  //(3) ["唱", "跳", "rap"]

    //缺点和原型链继承一样:不能传参,并且引用值共享
    obj2.skills.push("篮球");
    console.log(obj2.skills);  //(4) ["唱", "跳", "rap", "篮球"]
    console.log(obj3.skills);  //(4) ["唱", "跳", "rap", "篮球"]
    

** /第五种继承:.寄生式继承。寄生式继承就是把原型式继承再次封装,
然后在对象上扩展新的方法,再把新对象返回
/

//寄生式继承
    // function object(o){
    //     function F(){}    //创建了一个对象
    //     F.prototype = o;  //将这个对象原型指向传入的函数 
    //     return new F();   //返回一个对象的新实例  其实就是 传入对象的一个实例
    // }
    // function createAnother(original){
    //     var clone = object(original);  // clone是original的一个实例
    //     clone.sayHi = function(){      //增强这个对象
    //         alert("Hi");
    //     }
    //     return clone;                  //返回这个对象
    // }

    // var obj = {
    //     name:'kang',
    //     age:'19'
    // }
    // var obj2 = createAnother(obj);

    //缺点:无法实现函数的复用

** /第六种继承:6.寄生组合式继承(目前最完美的继承方式)/**

 Father.prototype.sayName = function (){ 
    alert(this.name)
    }
    function Father(name,age){
        this.name = name;
        this.age = age;
    }
    function Son(name,age){
        Father.call(this,name,age);
    }

    //继承函数
    function inheritPrototype(Son,Father){
        //中间实例化对象
        var a = Object(Father.prototype);
        //重写该对象的构造函数指针,指向Sub函数
        a.constructor = Son;
        //Sub的原型指向实例化对象a
        Son.prototype = a;
    }
    //调用继承函数,实现原型链构造
    inheritPrototype(Son,Father);

    //测试代码
    var son1 = new Son("lulu",20);
    console.log(son1.name) //lulu
    console.log(son1.age) //20
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值