实现继承主要依靠原型链来实现的,寄生组合继

作者: 前端开发  发布:2019-11-02

风华正茂篇作品精通JS承袭——原型链/构造函数/组合/原型式/寄生式/寄生组合/Class extends

2018/08/02 · JavaScript · 继承

原稿出处: 那是您的玩具车吗   

说实在话,从前笔者只要求知道“寄生组合承接”是最佳的,有个祖传代码模版用就行。近年来因为某个政工,多少个星期以来直接念兹在兹想整理出来。本文以《JavaScript高等程序设计》上的原委为骨架,补充了ES6 Class的连带内容,从自己以为更易于明白的角度将持续这事汇报出来,希望大家能抱有收获。

JavaScript 各类持续情势

2017/06/20 · JavaScript · 继承

初藳出处: Xuthus Blog   

持续是面向对象编制程序中又豆蔻年华特别首要的定义,JavaScript辅助落到实处三番三遍,不帮助接口承接,实现持续首要依据原型链来完毕的。

豆蔻梢头、理解对象
    1.创建
        ①构造函数   new Object
        ②对象字面量  var o = {};
    2.属性类型
        ①多少属性,对象属性有4个属性特征,暗中同意都为true,可以透过Object.defineProperty()来改革属性特征
            a.[[Configurable]]  代表是还是不是通过delete删除重新定义,能或不能够更改属性的特色,能还是无法改正为访谈权属性
            b.[[Enumerable]]    表示能或无法通过for-in枚举
            c.[[Writable]]      表示能不能够修改属性的值
            d.[[Value]]         表示属性值
            eg:
                var o = {
                    name : [1, 2, 3]
                }
                Object.defineProperty(o, "name", {
                    configurable : false,       // 不可能delete,不能够改革,不可能安装为访谈器属性
                    enumerable : false,         // 不能够枚举
                    writable :  false,          // 不能够改良
                    value :     [100, 200]      // 把值形成[100, 200]
                });
                // for(var v in o.name) {
                    // alert(o.name[v]); // 100, 200, 能枚举
                // }
                alert(o.propertyIsEnumerable("name"));      // false
                // o.name = "li";
                // alert(o.name); // 100, 200 不可能改改
                // delete o.name;
                // alert(o.name); // 100, 200 无法去除
        ②做客器属性,4个访谈器属性特征,能够经过Object.defineProperty()来改良属性特征
            a.[[Configurable]]  表示是还是不是通过delete删除重新定义,能还是不能够改进属性的特征,能还是不能够改正为访问权属性
            b.[[Enumerable]]    表示是还是不是通过for-in枚举
            c.[[Get]]           表示在读取属性时调用的函数,默感到undefined
            d.[[Set]]           表示在安装属性时调用的函数,默许为undefined
            eg:
                var o = {
                    name : [1, 2, 3]
                }
                Object.defineProperty(o, "name", {
                    get : function () {
                        alert("get");
                    },
                    set : function() {
                        alert("set");
                    }
                });
                o.name = "li";      // set,设置name值时,自动调用o.set()
                o.name;             // get,读取name时,自动调用o.get()
        ③定义四日性格 Object.defineProperties()来还要定义几性情子
            eg:
                var o = {}
                Object.defineProperties(o, {
                    name : {
                        configurable : false,
                        value : "zhang"
                    },
                    age : {
                        get : function () {
                            alert("get");
                        },
                        set : function() {
                            alert("set");
                        }
                    }
                });
                alert(o.name);          // zhang
                o.age;                  // get
                o.age = "li";           // set
        ④读取属性的风味    Object.getOwnPropertyDescriptor(objectName, propertyName)
            eg:
                var o = {}
                Object.defineProperties(o, {
                    age : {
                        get : function () {
                            alert("get");
                        },
                        set : function() {
                            alert("set");
                        }
                    }
                });
                var descriptor = Object.getOwnPropertyDescriptor(o, "age");
                for(var v in descriptor) {
                    alert(v " = " descriptor[v]);       // 弹出国访问谈器属性的4个属性特征
                }
二、创设对象
    1.厂子格局         
        ①虚无了创设对象的切实可行过程
            eg:
                function createObject (name, age) {
                var object = new Object();
                object.name = name;
                object.age = age;
                object.sayName = function () {
                    return object.name;
                }
                return object;
            }
            var p1 = createObject("zhang", 23);
            var p2 = createObject("li", 33);
            alert(p1.sayName());        // zhang
            alert(p2.sayName());        // li
            // 不能够辨识p1和p2
            alert(p1);                  // [object Object]
            alert(p2);                  // [object Object]
        ②缺陷     未有化解对象识别的难题
        ③缓和情势   构造函数模型
    2.构造函数格局
        ①开立情势
            eg:
                function Person(name, age) {
                    this.name = name;
                    this.age = age;
                    this.getName = function () {
                        return this.name;
                    }
                }
                var p1 = new Person("zhang", 34);
                var p2 = new Person("li", 23);
                alert(p1.getName());        // zhang
                alert(p2.getName());        // li
                alert(p1 instanceof Person);        // true
                alert(p2 instanceof Person);        // true, 解决了工厂格局的靶子识别难题
        ②难点每一个方法都要在各种实例上创制一次,进而产生分歧的效果域链,从而变成不相像
            eg: alert(p1.getName == p2.getName);        // false
            大家也可以将艺术有个别提取到构造函数之外,但诸有此类就不曾什么封装性可言了。
            eg:
                function Person(name, age) {
                    this.name = name;
                    this.age = age;
                    this.getName = getName;
                }
                function getName () {
                    return this.name;
                }
        ③化解措施   原型模型
    3.原型方式
        ①创设情势   原型对象(构造函数的prototype属性指向它)的补益:能够让具备目标实例分享它包罗属性和方法
            eg:
                function Person(name, age) {
                    this.name = name;
                    this.age = age;
                }
                Person.prototype.getName = function () {
                    return this.name;
                }
                var p1 = new Person("zhang", 34);
                var p2 = new Person("li", 23);
                alert(p1.getName == p2.getName);    // true,解除了主意大利共产党享的标题
        ②领悟原型  
                a.函数Person.prototype指向原型
                b.Person.prototype.constructor指回构造函数
                c.p1、p2的prototype指向原型,且可调用原型中的方法,用Person.prototype.isPrototypeOf(p1)决断,也能够用Object.getPrototypeOf(p1)来赢得原型
                d.我们能够用原型访谈属性的值,但是不可能由此实例重写原型的值,因为对象实例的值会屏蔽原型属性的值。当我们用实例对象重写了原型中的值,独有删除实例对象的值,手艺访谈原型属性的值。
                e.相近大家得以因此[实例.hasOwnProperty(propertyName)]来检查测验实例是还是不是定义了和睦的属性值
                    eg:
                        function Person() {}
                        Person.prototype.name = "zhang";
                        Person.prototype.getName = function () {
                            return this.name;
                        }
                        var p1 = new Person();
                        alert(p1.name);     // zhang
                        p1.name = "li";
                        alert(p1.name);     // li,实例中的值覆盖了原型中的值
                        alert(p1.hasOwnProperty("name"));   // 决断实例p1是不是定义了和睦的习性name的值,true
                        delete p1.name;     // 删除实例对象中的属性值
                        alert(p1.name);     // zhang
        ③原型与in操作符      
            a.不论是属性值存在于原型中,依旧实例对象中都回到true
                eg:
                    function Person() {}
                    Person.prototype.name = "zhang";
                    Person.prototype.getName = function () {
                        return this.name;
                    }
                    // 决断是不是为原型中的属性
                    function hasPrototypeProperty(object, propertyName) {
                        return propertyName in object && !object.hasOwnProperty(propertyName);
                    }
                    var p1 = new Person();
                    p1.name = "li";
                    alert(hasPrototypeProperty(p1, "name"));    // false
                    delete p1.name;
                    alert(hasPrototypeProperty(p1, "name"));    // true
            b.枚举全体可枚举的性质和方法,用Object.key(原型/实例)
                eg:
                    function Person() {}
                    Person.prototype.name = "zhang";
                    Person.prototype.age = 11;
                    Person.prototype.getName = function () {
                        return this.name;
                    }
                    alert(Object.keys(Person.prototype));   // 枚举原型中的属性和艺术
                    var p1 = new Person();
                    p1.name = "li";
                    p1.getName = function () {}             // 枚举实例对象中的属性和措施
                    alert(Object.keys(p1));
            c.枚举全部的属性和方法,无论是或不是隐身,用hasOwnPropertyNames(原型);
                eg: alert(Object.getOwnPropertyNames(Person));  // prototype,length,name
        ④更简明的原型方法
            a.源码
            eg: function Person() {}
                Person.prototype = {
                    constructor : Person,
                    name : "zhang",
                    getName : function () {}
                }
            b.难题    那样做或然会促成原型中的constructor属性的[Enumerable]为true,默认为false
            c.消灭办法  用Object.defineProperty()方法重复定义
                eg: Object.defineProperty(Person.prototype, constructor, { enumerable : false});
            e.实例化对象自然要后于对象的定义完成
        ⑤原型对象的难题        分享性,针对方法很好,针对属性也说的身故,然则针对那多少个带有了援用类型则不得
            eg:
                function Person() {}
                Person.prototype = {
                    constructor : Person,
                    friends : [1, 2]        // 援引类型
                }
                var p1 = new Person();
                var p2 = new Person();
                p1.friends.push(3);
                alert(p1.friends);
                alert(p2.friends);      // 相同的时候重回1,2,3
        ⑥杀绝措施   扬长避短,用构造函数格局定义属性,用原型格局定义方法
    3.组合构造格局和原型方式
        ①方式 断长续短,用构造函数形式定义属性,用原型格局定义方法
        eg:
            function Person(name) {
                this.name = name;
                this.friends = [1, 2]       // 援用类型
            }
            Person.prototype = {
                constructor : Person,
                name : "zhang",
            }
            var p1 = new Person("li");
            var p2 = new Person("wang");
            p1.friends.push(3);
            alert(p1.friends);      // 1,2,3
            alert(p2.friends);      // 1,2
        ②小题目        觉得构造函数和原型抽离,破坏了封装性
        ③消除办法   使用动态原型情势
    4.动态原型情势(基本完善)      将原型中方法封装到构造函数中去
        eg:
            function Person(name) {
                this.name = name;
                this.friends = [1, 2];      // 援引类型
                if (typeof this.getName != "function") {
                    Person.prototype.getName = {
                        return this.name;
                    }
                }
            }
    5.寄生组织格局
        ①中坚观念:创造四个函数(对象),该函数用来封装代码,然后回到函数(对象)
        ②模式
            eg:
                function Person(name, age) {
                    var o = new Object();
                    o.name = name;
                    o.age = age;
                    o.getName = function () {
                        return o.name;
                    };
                    return o;
                }
                var p1 = new Person("zhang", 34);
                alert(p1.getName());        // zhang
                alert(p1 instanceof Person);// false
        ③主题材料:由于实例对象和构造函数完全分开,由此不能够辨认对象
        ④案例:对于Array类型,大家或许在奇特情况在,对它实行增加属性和措施
            eg:
                function NewArray() {
                    var array = new Array();
                    array.push.apply(array, arguments);
                    array.addFun = function () {
                        return this.join("|");
                    }
                    return array;
                }
                var a1 = new NewArray("zhang", 22);
                alert(a1.addFun());     // zhang|22
    6.稳妥构造函数模型      未有国有属性,不应用this和new,只好定义获取值的情势
        ①用途:安全性
        ②源码
            eg:
                function Person(name, age) {
                    var o = new Object();
                    o.getName = function () {
                        return name;
                    }
                    return o;
                }
                var p = Person("zhang", 3);
                p.name = 'li';          // 无效
                alert(p.getName());     // zhang
        ③表征 函数名首字母大写、对象里只定义方法且毫无this、实例化时毫不new
        ④标题:由于实例对象和构造函数完全分开,因而不能够辨识对象
三、继承
    1.原型链
        ①将父类的实例赋值给子类的原型。因为父类的实例指向父类的原型,由此子类的原型也本着父类的原型。
        ②主导源码:
            eg:
                function SuperType(){
                    this.property = true;
                }
                SuperType.prototype.getSuperValue = function(){
                    return this.property;
                };
                function SubType(){
                    this.subproperty = false;
                }
                //继承了SuperType
                SubType.prototype = new SuperType();    // 将父类的实例赋值给子类的原型
                SubType.prototype.getSubValue = function (){
                    return this.subproperty;
                };
                var instance = new SubType();
                alert(instance.getSuperValue()); //true,调用父类SuperType的办法getSuperValue()
        ③别忘记了父类相仿基础了祖类Object
        ③明确原型和实例的关联 用instanceof和对象.isPrototypeOf(实例)
        ④在子类重新可能增多父类的法龙时,一定要在父类定义之后
        ⑤原型链的难题 原型链中不能存在引用类型
            eg:
                function SuperType(){
                    this.friends = [1,2];
                }
                function SubType(){}
                //继承了SuperType
                SubType.prototype = new SuperType();
                var s1 = new SubType();
                var s2 = new SubType();
                s1.friends.push(3);
                alert(s1.friends);      // 1, 2, 3
                alert(s2.friends);      // 同上
        ⑥消除方法   借用构造函数
    2.借出构造函数    对于原型链中富含援引类型,大家得以在子类的构造函中调用父类的构造函数
        ①源码案例, 即能够行使引用类型,还足以传递参数
        eg:
            function SuperType(name){
                this.name = name;
                this.friends = [1,2];
            }
            function SubType(){
                SuperType.call(this, "abc");        // 传递参数
            }
            //继承了SuperType
            SubType.prototype = new SuperType();
            var s1 = new SubType();
            var s2 = new SubType();
            s1.friends.push(3);
            alert(s1.friends);      // 1, 2, 3
            alert(s2.friends);      // 1, 2
            alert(s1.name);         // abc
        ③难点 由于是在构造函数中定义,所以艺术不可以知道分享
        ④解决方法   组合承袭
    3.重新整合承继(尽管三回调用了父类,然则基本ok)
        ①为主思考   将借用构造和原型链结合起来,借用构造定义属性,原型链定义方法
            eg:
                function SuperType(name){
                    this.name = name;
                    this.friends = [1,2];
                    if (typeof this.getName != "function") {
                        SuperType.prototype.getName = function () {
                            return this.name;
                        }
                    }
                }
                function SubType(name, age){
                    SuperType.call(this, name);             // 第二遍调用父类
                    this.age = age;
                    if (typeof this.getAge != "function") {
                        SuperType.prototype.getAge = function () {
                            return this.age;
                        }
                    }  
                }
                //继承了SuperType
                SubType.prototype = new SuperType();        // 第三遍调用父类
                var s1 = new SubType("zhang", 23);
                var s2 = new SubType("li", 24);
                s1.friends.push(3);
                alert(s1.friends);      // 1, 2, 3
                alert(s2.friends);      // 1, 2
                alert(s1.getName());    // zhang
                alert(s2.getAge());     // 24
    4.原型式承继
        ①中坚思考   依赖原型能够依据原来就有的对象创制新目的,进而不供给自定义对象
            eg:
                function object(o) {
                    function F() {};
                    F.prototype = o;
                    return new F();
                }
                var person = {
                    name : "zhang",
                    friends : [1, 2]
                }
                var p1 = object(person);
                p1.name = "li";
                p1.friends.push(3);
                alert(p1.name);     // li
                alert(p1.friends);  // 1,2,3
                var p2 = object(person);
                p1.name = "wang";
                p1.friends.push(4);
                alert(p2.name);     // wang
                alert(p2.friends);  // 1,2,3,4
        ②ECMAScript 5升高了DougRuss·克罗克福德的原型链承袭,用Object.create()方法
            eg: 在那之中第1个参数和defineProperty()方法相通
                var person = {
                    name : "zhang",
                    friends : [1, 2]
                }
                var p1 = Object.create(person, {
                    name : {
                        value : "zhang"
                    }
                });
                p1.friends.push(3);
                alert(p1.name);     // li
                alert(p1.friends);  // 1,2,3
                var p2 = Object.create(person, {
                    name : {
                        value : "wang"
                    }
                });
                p1.friends.push(4);
                alert(p2.name);     // wang
                alert(p2.friends);  // 1,2,3,4
        ③难题:    原型链分享难题,援用类型
    5.寄生式继承
        ①思维 基于原型式承袭,成立三个新函数对象,加多新点子
        eg:
            function object(o) {
                function F() {};
                F.prototype = o;
                return new F();
            }
            function createAnother(original) {
                // 承继原本的对象原型
                var clone = object(original);
                // 增加新章程
                clone.newFun = function () {
                    return "new function";
                }
                return clone;
            }
            var person = {
                name : "zhang",
                friends : [1, 2]
            }
            var p = createAnother(person);
            alert(p.name);      // zhang
            alert(p.newFun());  // new function
        ②主题材料 原型链分享难点,援用类型
    6.寄生组合式承接
        ①研究在组合承接和原型式传承的底子上,不在子类的里边调用父类的构造函数,而是制造父类原型的别本
        eg:
            function object(o) {
                function F() {};
                F.prototype = o;
                return new F();
            }
            function inheritPrototype(subType, superType) {
                // 赋值proto为superType的原型
                var proto = object(superType.prototype);
                // 原型的contructor属性指向构造函数
                proto.contructor = subType;
                // superType的构造函数指向原型
                subType.prototype = proto;
            }
            function SuperType(name){
巴黎人游戏官网,                this.name = name;
                this.friends = [1,2];
                if (typeof this.getName != "function") {
                    SuperType.prototype.getName = function () {
                        return this.name;
                    }
                }
            }
            inheritPrototype(SubType, SuperType);
            function SubType(name, age){
                SuperType.call(this, name);
                this.age = age;
                if (typeof this.getAge != "function") {
                    SuperType.prototype.getAge = function () {
                        return this.age;
                    }
                }  
            }
            var s1 = new SubType("zhang", 23);
            var s2 = new SubType("li", 24);
            s1.friends.push(3);
            alert(s1.friends);      // 1, 2, 3
            alert(s2.friends);      // 1, 2
            alert(s1.getName());    // zhang
            alert(s2.getAge());     // 24

1. 三番一回分类

先来个完整影象。如图所示,JS中继续能够依据是不是选取object函数(在下文中会提到),将一连分成两有的(Object.create是ES5新扩充的办法,用来标准化那几个函数)。

里面,原型链承袭和原型式承继有平等的优弱点,构造函数承袭与寄生式承袭也互相关照。寄生组合承继基于Object.create, 同一时候优化了咬合承继,成为了到家的三回九转方式。ES6 Class Extends的结果与寄生组合继承基本风度翩翩致,然则完毕方案又略有不一致。

上边立即步入正题。

巴黎人游戏官网 1

原型链

率先得要了解怎么样是原型链,在风姿洒脱篇文章看懂proto和prototype的关系及界别中讲得卓绝详尽

原型链承袭基本观念正是让一个原型对象指向另二个门类的实例

function SuperType() { this.property = true } 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() console.log(instance.getSuperValue()) // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function SuperType() {
  this.property = true
}
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()
console.log(instance.getSuperValue()) // true

代码定义了五个体系SuperType和SubType,每种门类分别有贰个个性和二个主意,SubType承继了SuperType,而三番五回是因此创制SuperType的实例,并将该实例赋给SubType.prototype实现的。

兑现的本质是重写原型对象,代之以八个新类型的实例,那么存在SuperType的实例中的全体属性和情势,将来也设有于SubType.prototype中了。

咱俩知道,在开立贰个实例的时候,实例对象中会有叁个之中指针指向创设它的原型,进行关联起来,在那地代码SubType.prototype = new SuperType(),也会在SubType.prototype创造一个内部指针,将SubType.prototype与SuperType关联起来。

故而instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会顺着那条链一爱慕上找。

拉长形式

在给SubType原型增多方法的时候,假如,父类上也许有同生机勃勃的名字,SubType将会覆盖那几个主意,达到重新的指标。 然而其生机勃勃措施依然存在于父类中。

切记不能以字面量的花样丰硕,因为,下面说过通超过实际例承继本质上正是重写,再使用字面量情势,又是一回重写了,但本次重写未有跟父类有任何关系,所以就能变成原型链截断。

function SuperType() { this.property = true } 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() console.log(instance.getSuperValue()) // error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType() {
  this.property = true
}
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()
console.log(instance.getSuperValue())  // error

问题

唯有的选拔原型链继承,首要难题来自包含援引类型值的原型。

function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { } SubType.prototype = new SuperType() var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green", "black"]

1
2
3
4
5
6
7
8
9
10
11
function SuperType() {
  this.colors = ['red', 'blue', 'green']
}
function SubType() {
}
SubType.prototype = new SuperType()
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green", "black"]

在SuperType构造函数定义了多少个colors属性,当SubType通过原型链承继后,那天性格就可以产出SubType.prototype中,就跟特地创立了SubType.prototype.colors同样,所以会产生SubType的兼具实例都会分享那脾性子,所以instance1改善colors这些引用类型值,也会反映到instance第22中学。

2. 再三再四方式

上海教室上半区的原型链承继,构造函数承袭,组合承继,网络内容超级多,本文不作详细描述,只提出重视。这里给出了自个儿觉着最轻松明白的风流倜傥篇《JS中的承袭(上)》。即使对上半区的内容不熟谙,能够先看那篇作品,再回到继续阅读;假若已经相比较熟谙,那有个别能够飞速略过。另,上半区大气借出了yq前端的豆蔻梢头篇一连文章[1]。

借用构造函数

此方法为精晓决原型中包蕴援引类型值所带来的难点。

这种办法的思量就是在子类构造函数的中间调用父类构造函数,能够依赖apply()和call()方法来改换目标的实行上下文

function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { // 继承SuperType SuperType.call(this) } var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green"]

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType() {
  this.colors = ['red', 'blue', 'green']
}
function SubType() {
  // 继承SuperType
  SuperType.call(this)
}
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green"]

在新建SubType实例是调用了SuperType构造函数,那样的话,就能够在新SubType指标上进行SuperType函数中定义的享有指标开始化代码。

结果,SubType的各类实例就能够具备友好的colors属性的别本了。

传送参数

依傍构造函数还应该有二个优势就是可以传递参数

function SuperType(name) { this.name = name } function SubType() { // 继承SuperType SuperType.call(this, 'Jiang') this.job = 'student' } var instance = new SubType() console.log(instance.name) // Jiang console.log(instance.job) // student

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType(name) {
  this.name = name
}
function SubType() {
  // 继承SuperType
  SuperType.call(this, 'Jiang')
 
  this.job = 'student'
}
var instance = new SubType()
console.log(instance.name)  // Jiang
console.log(instance.job)   // student

问题

倘若唯有依附构造函数,方法都在构造函数中定义,因而函数不能达到规定的标准复用

2.1 原型式承继

主导:将父类的实例作为子类的原型

SubType.prototype = new SuperType() // 全数涉及到原型链承袭的接续格局都要改正子类构造函数的针对,不然子类实例的结构函数会指向SuperType。 SubType.prototype.constructor = SubType;

1
2
3
SubType.prototype = new SuperType()
// 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。
SubType.prototype.constructor = SubType;

可取:父类方法可以复用

缺点:

  • 父类的引用属性会被有着子类实例分享
  • 子类营造实例时不能够向父类传递参数

结缘传承(原型链 构造函数)

结合承接是将原型链承接和构造函数结合起来,进而发挥两方之长的黄金年代种形式。

思路正是行使原型链达成对原型属性和方法的后续,而经过借用构造函数来促成对实例属性的存在延续。

诸如此比,既通过在原型上定义方法完结了函数复用,又能够保险各样实例都有它自身的性质。

function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name) } function SubType(name, job) { // 承接属性 SuperType.call(this, name) this.job = job } // 承继方法 SubType.prototype = new SuperType() SubType.prototype.constructor = SuperType SubType.prototype.sayJob = function() { console.log(this.job) } var instance1 = new SubType('Jiang', 'student') instance1.colors.push('black') console.log(instance1.colors) //["red", "blue", "green", "black"] instance1.sayName() // 'Jiang' instance1.sayJob() // 'student' var instance2 = new SubType('J', 'doctor') console.log(instance2.colors) // //["red", "blue", "green"] instance2.sayName() // 'J' instance2.sayJob() // 'doctor'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function SuperType(name) {
  this.name = name
  this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
  console.log(this.name)
}
function SubType(name, job) {
  // 继承属性
  SuperType.call(this, name)
 
  this.job = job
}
// 继承方法
SubType.prototype = new SuperType()
SubType.prototype.constructor = SuperType
SubType.prototype.sayJob = function() {
  console.log(this.job)
}
var instance1 = new SubType('Jiang', 'student')
instance1.colors.push('black')
console.log(instance1.colors) //["red", "blue", "green", "black"]
instance1.sayName() // 'Jiang'
instance1.sayJob()  // 'student'
var instance2 = new SubType('J', 'doctor')
console.log(instance2.colors) // //["red", "blue", "green"]
instance2.sayName()  // 'J'
instance2.sayJob()  // 'doctor'

这种格局制止了原型链和构造函数承继的弱项,融入了他们的优点,是最常用的大器晚成种持续方式。

本文由巴黎人游戏官网发布于前端开发,转载请注明出处:实现继承主要依靠原型链来实现的,寄生组合继

关键词: