最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScrip继承方案

    正文概述 掘金(清欢辞)   2021-04-13   507

    JavaScrip继承方案

    1、原型链继承

    JavaScrip继承方案 构造函数、原型和实例之间的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个原型对象的指针。

    原型链继承核心: 将父类的实例作为子类的原型。

    继承的本质就是复制,即重写原型对象,代之以一个新类型的实例,

    function Foo(name){
        this.color = ['red','blue','black']
        this.name = name
    };
    Foo.prototype.sayName = function () {
         return ('my name is '+this.name)
    }
    function Car(age){
        this.age = age
    }
    Car.prototype = new Foo('jack')
    
    a = new Car(16)
    b = new Car()
    b.color.push('white') // 在Car的实例b的color属性上添加了一个white
    console.log(a.name,a.age)
    console.log(a.color,a.sayName())
    

    JavaScrip继承方案 我们在打印实例a的color属性意外的发现多出来一个白色,这是因为在原型链的继承中,引用类型会被所有的实例所共享,多个实例对引用类型的操作会被篡改。而不是单独属于自己的一份,

    这也是原型链继承存在的问题:

    问题1:原型中包含的引用类型属性将被所有实例共享;

    问题2:子类在实例化的时候不能给父类构造函数传参;

    为此我们想出来构造函数式继承方法

    2、借用构造函数继承

    基本思想:

    借用构造函数的基本思想就是利用call或者apply把父类中通过this指定的属性和方法复制(借用)到子类创建的实例中。 因为this对象是在运行时基于函数的执行环境绑定的。也就是说,在全局中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。 call、apply 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

    不知道this的指向的话可以仔细看看这篇关于this的完整讲解

    This指向问题的超详解

    function SuperType(){
        this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.getColor = function () {
        return  this.colors
    }
    function SubType(){
        // 继承了 SuperType
        SuperType.call(this);
    }
    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"
    instance2.getColor() // 报错  TypeError: instance2.getColor is not a function
    

    当我们想要使用父类原型上的方法时报错,发现顺着原型链上去查找,找不到getColor这个方法, 这是因为子类的实例不能继承原型属性/方法

    核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

    缺点: 方法都在构造函数中定义, 只能继承父类的实例属性和方法,不能继承原型属性/方法, 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

    3、组合继承

    原理:使用原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承。 结合原型继承和构造函数的继承方法,对之进行优化,达到即可继承原型的方法,引用类型也不会被所有实例所共享。

    
            function Person  (name) {
                 this.name = name;
                 this.friends = ['小李','小红'];
             };
    
             Person.prototype.getName = function () {
                 return this.name;
             };
    
            function Parent (age) {
                Person.call(this,'老明');  //第二次调用构造函数
                this.age = age;
            };
    
            Parent.prototype = new Person('老明');  //这一步也很关键
            var result = new Parent(24);   // 第一次调用构造函数
                console.log(result.name);    //老明
            result.friends.push("小智");  //
            console.log(result.friends);  //['小李','小红','小智']
            console.log(result.getName());  //老明
            console.log(result.age);    //24
    
            var result1 = new Parent(25);   //通过借用构造函数都有自己的属性,通过原型享用公共的方法
            console.log(result1.name);  //老明
            console.log(result1.friends);  //['小李','小红']
    

    优点:

    结合原型链和借用构造函数继承两种方法,取长补短。实现了函数复用,又能够保证每个子类不会共享父类的引用类型属性。

    缺点:

    调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

    四. 寄生组合式继承

    function inheritPrototype(subType, superType){
      var prototype = Object.create(superType.prototype,{}); // 创建对象,创建父类原型的一个副本
      prototype.constructor = subType;                    // 增强对象,弥补因重写原型而失去的默认的constructor 属性
      subType.prototype = prototype;                      // 指定对象,将新创建的对象赋值给子类的原型
    }
    
    // 父类初始化实例属性和原型属性
    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;
    }
    
    // 将父类原型指向子类
    inheritPrototype(SubType, SuperType);
    
    // 新增子类原型属性
    SubType.prototype.sayAge = function(){
      alert(this.age);
    }
    
    var instance1 = new SubType("xyc", 23);
    var instance2 = new SubType("lxy", 23);
    
    instance1.colors.push("2"); // ["red", "blue", "green", "2"]
    instance1.colors.push("3"); // ["red", "blue", "green", "3"]
    
    

    这个例子的高效率体现在它只调用了一次SuperType 构造函数,并且因此避免了在SubType.prototype 上创建不必要的、多余的属性。于此同时,原型链还能保持不变; 因此,还能够正常使用instanceof 和isPrototypeOf() 这是最成熟的方法,也是现在库实现的方法

    五、class

    在 es6 中,官方给出了 class 关键字来实现面向对象风格的写法,但本质上是寄生组合式继承的语法糖。

    class Person {
        constructor(age) {
            this.age_ = age;
        }
        sayAge() {
            console.log(this.age_);
        }
        // 静态方法
        static create() {
            // 使用随机年龄创建并返回一个 Person 实例
            return new Person(Math.floor(Math.random()*100));
        }
    }
    // 继承普通构造函数
    class Doctor extends Person {}
    
    const doctor = new Doctor(32);
    doctor.sayAge(); // 32
    

    总结

    1.ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this)).

    2.ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。

    3.ES5的继承时通过原型或构造函数机制来实现。

    4.ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。


    起源地下载网 » JavaScrip继承方案

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元