ES5 继承

112 阅读1分钟

继承

原型链继承

    <script>
        function SuperType() {
            this.property = true
            this.color=["color",'red','blue']
        }
        SuperType.prototype.getSuperValue = function () {
            return this.property
        }
​
        function SubType() {
            this.subproperty = false
        }
        SubType.prototype = new SuperType()
​
        SubType.prototype.getSubValue = function () {
            return this.subproperty;
        };
        var instance = new SubType();
        const supertype = new SuperType()
        instance.color.push('yellow')
        console.log(supertype)
        console.log(instance.getSuperValue());
        console.log(instance.property);
        console.log(instance)
        //instance指向SubType的原型,SubType的原型指向SuperType的原型,getSuperValue方  法仍然在SuperType.prototype中。但是property则位于SubType的prototype中,这是因为property是一个实例属性,而getSuperValue是一个原型方法,此时instance.constructor指向的是SuperType
        //注意事项:
​
        // 别忘记默认的原型,所有的引用类型都继承自Object,所有函数的默认原型都是Object的实例,因此默认原型里都有一个指针,指向object.prototype
​
        // 谨慎地定义方法,给原型添加方法的代码一定要放在替换原型的语句之后,不能使用对象字面量添加原型方法,这样会重写原型链
​
        // 原型链继承的问题
​
        // 最主要的问题来自包含引用类型值的原型,它会被所有实例共享
​
        // 第二个问题是,创造子类型的实例时,不能向超类型的构造函数中传递参数
    </script>

借用构造函数继承

    <script>
        function SuperType(name) {
            this.name = name
            this.colors=['red','blue']
        }
        SuperType.prototype.getColor = function () {
            return this.colors
        }
​
        function SubType() {
            SuperType.call(this, '张三')
            this.age = 18
        }
        const instancel = new SubType()
        const parent = new SuperType("李四")
        console.log(instancel)
        console.log(parent)
        //通过call或者apply方法,我们实际上是在将来新创建的SubType实例的环境下调用了SuperType构造函数。这样一来,就会在新SubType对象上执行SuperType函数中定义的所有对象初始化代码,因此,每一个SubType的实例都会有自己的对象的副本
        //优势:可以传递参数
        //缺点:方法都在构造函数中定义,函数无法复用。在超类型中定义的方法,子类型不可见,结果所有类型都只能使用构造函数模式。
    </script>

组合继承

    <script>
        function Person(name,age){
            this.name=name
            this.age=age
            this.color=["color",'red','blue']
        }
        Person.prototype.getName=function(){
            console.log(this.name)
        }
        function Son(name,age,sex){
            Person.call(this,name,age)
            this.sex=sex
        }
        Son.prototype=new Person()
        Son.prototype.constructor=Son
        Son.prototype.getSex=function(){
            console.log(this.sex)
        }
        const son=new Son('张三',18,"男")
        console.log(son)
        son.getSex()
        son.getName()
        //基本思想:将原型链和借用构造函数技术组合到一起。使用原型链实现对原型属性和方法的继承,用借用构造函数模式实现对实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
        //缺点:无论在什么情况下,都会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部
    </script>

原型继承

    <script>
        // function object(o) {
        //     function F() {}
        //     F.prototype = o
        //     return new F()
        // }
        // //从本质上讲,object()对传入其中的对象执行了一次浅复制
        // const person = {
        //     name: 'Annike',
        //     friendes: ['Alice', 'Joyce']
        // }
        // const anotherPerson = object(person)
        // anotherPerson.name = "Greg"
        // anotherPerson.friendes.push('Rob')
        // console.log(anotherPerson)
        // const yetAnotherPerson = object(person);
        // yetAnotherPerson.name = 'Linda';
        // yetAnotherPerson.friendes.push('Sophia');
        // console.log(person.friendes);
        //用处:创造两个相似的对象,但是包含引用类型的值的属性始终会共享响应的值,原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。无法传递参数
​
        const Person={
            name:'张三',
            list:['aa','bb','cc','dd']
        }
        const son=Object.create(Person,{name:{value:'李四'}})
        console.log(son)
        son.list.push('ee')
        console.log(Person)
    </script>

寄生式继承

    <script>
        // function object(o) {
        //     function F() {}
        //     F.prototype = o
        //     return new F()
        // }
        // function createAnother(original) {
        //     var clone = object(original)
        //     clone.sayHi = function () {
        //         alert("Hi");
        //     };
        //     return clone
        // }
        // const Person={
        //     name:'张三',
        //     list:['aa','bb']
        // }
        // const son=createAnother(Person)
        // console.log(son)
        // son.sayHi()
        // console.log(Person)
        function createAnother(obj) {
            const clone = Object.create(obj)
            clone.getName = function () {
                console.log(this.name)
            }
            return clone
        }
        const Person = {
            name: '张三',
            list: ['aa', 'bb']
        }
        const son = createAnother(Person)
        son.list.push('cc')
        console.log(son)
        son.getName()
        console.log(Person)
​
        // 基本思想:寄生式继承是与原型式继承紧密相关的一种思路,它创造一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后再返回对象。
        // 缺点:使用寄生式继承来为对象添加函数,会因为做不到函数复用而降低效率,这个与构造函数模式类似,原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
    </script>

寄生组合式继承

    <script>
        // 最好的方法,最理想的方法 寄生组合式继承
        // 解决了两次调用父类构造函数问题
        function Person(name, age) {
            this.name = name
            this.age = age
            this.colors = ['red', 'green']
        }
        Person.prototype.getName = function () {
            console.log(this.name)
        }
​
        function Son(name, age, sex) {
            Person.call(this, name, age) // 借用构造函数, 第一次调用父类构造函数
            this.sex = sex
        }
        Son.prototype = Object.create(Person.prototype)
        Son.prototype.constructor = Son
        Son.prototype.getAge = function () {
            console.log(this.age)
        }
        const son = new Son('张三', 18, '男')
        son.colors.push('yello')
        const person = new Person('李四', 25)
        console.log(son)
        console.log(person)
        son.getAge()
        son.getName()
    </script>

\