美文网首页
类的封装、继承

类的封装、继承

作者: 田成力 | 来源:发表于2019-10-11 17:14 被阅读0次

    类的继承:封装和多态

    [封装]:把实现一个功能的js代码进行封装主要目的:低耦合高内聚
    [多态]:重载:方法名相同,参数的个数或者类型不同,此时名字相同的方法叫做方法的重载(后台语言的重载),js中不存在重载的
    重写:子类重写父类的方法
    [继承]:子类继承父类的方法和属性

    继承方法

    原型继承

    原型继承:让子类原型指向父类的一个实例。
    原型继承方式:B.prototype=new A();
    A的实例本身具备父类A的私有属性和公有方法,子类B的原型指向它,那么子类的B的实例就可以找到这些属性和方法了.
    和传统后台语言的继承不一样,子类继承父类并不是把父类的属性方法克隆一份给子类的(这样处理子类和父类就没有直接关系了)js中的原型继承是让子类和父类建立原型链接方式,子类的实例调取父类原型上的方法都是基于原型链的查找机制完成的。存在问题是:子类可以重写父类原型上的方法(重写),子类和父类还有关系的

    B.prototype.\__proto__.getX=null;//把父类A的原型上的getX重写为null,A的其他实例会受到影响
    

    原型继承存在的问题
    1.父类实例私有的属性以及公有的属性都变为子类实例的共有属性
    2.如果子类B的原型上之前有属性方法,重新执行A的实例后,之前的方法都没用了。

    function A(){
    this.x=100;
    }
    A.prototype={
    constructor=A;
    getX:function(){
    console.log(this.x)}};
    function B(){
    this.y=200}
    B.prototype=new A();
    let f=new B();
    //原型继承:方式:B.prototype=new A();A的实例本身具备父类A的私有属性和公有方法,子类B的原型指向它,那么子类的B的实例就可以找到这些属性和方法了
    //和传统后台语言的继承不一样,子类继承父类并不是把父类的属性方法克隆一份给子类的(这样处理子类和父类就没有直接关系了)js中的原型继承是让子类和父类建立原型链接方式,子类的实例调取父类原型上的方法都是基于原型链的查找机制完成的。存在问题是:子类可以重写父类原型上的方法(重写),子类和父类还有关系的
    B.prototype.__proto__.getX=null;//把父类A的原型上的getX重写为null,A的其他实例会受到影响
    `原型继承存在的问题`:
    1.父类实例私有的属性以及公有的属性都变为子类实例的共有属性
    2.如果子类B的原型上之前有属性方法,重新执行A的实例后,之前的方法都没用了。
    
    
    call继承

    call继承:把父类A作为普通函数执行,让A中的this变为B的实例,相当于给B的实例增加一些属性和方法
    new A()把A作为类创建它的实例this:实例。
    A()把A当做普通函数执行this:window
    弊端:把父类A当做普通函数执行,和父类原型没有关系了,仅仅是把A中的私有属性变为子类B实例的私有属性而已,A原型上的公有属性和B及它的实例没啥关系.

    function A(){
    this.x=100;
    }
    A.prototype={
    constructor=A;
    getX:function(){
    console.log(this.x)}};
    function B(){
    A.call(this);//call继承,把A执行,让A中的this变为f;
    this.y=200}
    
    let f=new B();
    
    弊端:把父类A当做普通函数执行,和父类原型没有关系了,仅仅是把A中的私有属性变为子类B实例的私有属性而已,A原型上的公有属性和B及它的实例没啥关系
    
    寄生组合继承

    寄生组合继承:A的私有变为B的私有,A的公有变为B的公有
    和原型继承的唯一区别:B.prototype=new A();创建的A的实例虽然指向了A的原型但是实例中不是空的,存放了A的私有属性,这些属性变为B的公有属性,B.prototype=Object.create(A.prototype):好处在于我们是创建一个没有任何私有属性的空对象,指向A的原型,这样B的公有属性中就不会存在A的私有属性。

    function A(){
    this.x=100;
    }
    A.prototype={
    constructor=A;
    getX:function(){
    console.log(this.x)}};
    function B(){
    A.call(this);//call继承,把A执行,让A中的this变为f;
    this.y=200}
    //B.prototype=A.prototype;//这是组合继承,一般都不这样处理,容易修改父类A原型上的东西,导致A的其他实例也受到影响。
    B.prototype=Object.create(A.prototype)
    let f=new B();
    //Object.create:内置Object类天生自带的方法
    1.创建一个空对象
    2。让新创建的空对象__proto__指向第一个传递进来的对象(把OBJ作为新创建空对象的原型)
    let obj={name:'haha'};
    Object.create(obj)
    
    ES6class类实现继承

    ES6class类实现继承:创建类是有标准的语法的(这种语法创建出来的类只能new执行,不能当做普通函数执行)

    class Fn{
    constructor(n,m){
    //等价于构造体,代表函数
    this.x=n;
    this.y=m;}
    //直接给Fn的原型上设置方法(只能设置方法不能设置属性):
    getX(){}
    //把Fn当做一个普通对象设置的私有方法(和实例没有关系),同样只能设置方法不能写属性:
    static AA(){}
    } 
    //属性可以添加在外面
    //Fn.prototype.bb=100;
    let f=new Fn(10,20)
    
    
    class A{
    construtor(){this.x=100;}
    getX(){console.log(this.x)}
    }
    class B extends A{//extends类似于实现了原型继承。
    construtor(){super();//类似于call继承,在这里super相当于把A的constructor给执行了并且让方法中的this是B的实例,super当中传递的实参都是在给A的constructor传递
    this.y=200;}
    getY(){console.log(this.y)}
    }
    let f= new B();
    
    //public void fn(int n,int m)
    //public void fn(string n,string m){}
    //public void fn(int n,int m,int z){}
    根据传递参数的不同执行不同的方法
    
    function fn(n,m){};
    function fn(n,m,x){
    //后面的方法会把前面的方法覆盖掉,不管传递多少实参,执行的都是后面的这个方法(js中的重载值得是:同一个方法根据传参不一样,实现不同的功能)
    };
    fn(1,2);
    fn(1,2,3)
    
    

    函数的三种角色

    第一种角色:普通函数
    堆栈内存释放、
    作用域链、
    ...

    第二种角色:类
    实例
    prototype原型
    _proto_原型链
    ...
    第三种角色:普通对象
    键值对的增删改查
    ...
    [图片上传失败...(image-156c62-1570785283723)]
    [图片上传失败...(image-88ee42-1570785283723)]
    JQ这个类库中提供了很多方法其中一部分是写在原型上的有一部分是把他当做普通对象来设置的。

    对象
    普通对象、数组、正则、math、json、arguments...
    实例是对象类型的(除了基础数据类型的字面量创建的值)
    prototype的值也是对象类型
    函数也是对象类型的。

    函数三种角色之间没有直接的关系

    function Fn(){
        var name='田大力';
        this.age=8;
    }
    Fn.prototype.say=function(){}
    Fn.eat=function(){}
    var f = new Fn();
    

    [图片上传失败...(image-800be8-1570785283723)]

    [图片上传失败...(image-a12add-1570785283723)]

    阿里超经典面试题(有难度)

    function Foo() {
        getName = function () {
            console.log(1);
        };
        return this;
    }
    Foo.getName = function () {
        console.log(2);
    };
    Foo.prototype.getName = function () {
        console.log(3);
    };
    var getName = function () {
        console.log(4);
    };
    function getName() {
        console.log(5);
    }
    
    Foo.getName();//=>2 把FOO作为对象,找其私有属性
    getName();//=>4 执行全局下的GET-NAME
    Foo().getName();//=>1 先把FOO作为普通函数执行,把执行的结果window调取GET-NAME在执行
    window.getName();//=>1
    new Foo.getName();//=>先获取Foo.getName的值(假设B),然后再new B()相当于创建B的实例 =>2  (new Foo.getName;一样的)
    new Foo().getName();//=>new Foo()当做一个整体获取实例,把得到的实例在调取GET-NAME  =>3
    new new Foo().getName();
    //=>var f=new Foo()//=>实例是this这是空的
    //=>new f.getName();  =>new (f.getName)(); =>3
    
    //obj.getX();//=>先获取obj的getX的属性值,然后把获取的值执行
    

    [图片上传失败...(image-a60ebf-1570785283723)]

    相关文章

      网友评论

          本文标题:类的封装、继承

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