面向对象——原型与原型链、继承

版权声明:欢迎各位斧正,转载请标明出处 https://blog.csdn.net/qq_41649879/article/details/83443501

本文代码及内容来自于博览网课程——WEB前端养成计划的归纳总结,有兴趣的小伙伴可以移步(以前没有购买过的现在好像无法观看了)


目录

一、运用构造函数的方式来创建特定类型的对象

二、理解原型对象

三、原型的动态性

四、原型链

五、继承


一、运用构造函数的方式来创建特定类型的对象

此方式调用构造函数会经历以下4步:

(1)创建一个实例

(2)将构造函数的作用域赋给实例

(3)执行构造函数中的代码,为实例添加属性

(4)返回实例(不需要return语句,默认返回)

问题:实例calendar1和calendar2的show()方法是不同的,会造成内存空间的浪费

解决方法:

(1)将show()方法设置为全局方法??              X

非Calender对象的实例也能访问到show()方法,不合理

(2)运用原型模式                                                

我们创建的每个函数都有一个prototype(原型)属性,将方法定义在prototype中,当然,不要把属性放在prototype中,否则实例会共享一个属性

二、理解原型对象

只要创建了一个新的构造函数,就会为其创建一个prototype属性,此属性指向函数的prototype原型对象。默认情况下,原型对象会有一个constructor属性指向所在函数。(函数原型有隐式原型和显式原型,想要进一步了解可参考文章:__proto__(隐式原型)与prototype(显式原型)

alert(Calendar.prototype.constructor == Calendar)     //true

当调用构造函数创建一个实例后,该实例包含一个内部属性(无法通过属性名访问),ECMAScript5将其命名为[[prototype]], ECMASript5可通过Object.gettPrototypeOf(obj)方法返回实例的原型对象,具体关系可看如下图示:

将方法定义到prototype中有一个问题,即每次都要写一遍Calendar.prototype。改进做法:用对象字面量来重写prototype原型对象。

与之前的方法不同,此时Calendar.prototype是一个新的对象,constructor不再指向Calendar,可以这样调整:

三、原型的动态性

对象的属性访问实际上是在作用域链里执行搜索的过程,所以先创建了实例再修改原型也可正确执行,但用对象字面量重写prototype原型对象的方法则会报错。

           // ✔

重写原型对象:

 → 

四、原型链

ECMAScript的继承主要是依靠原型链来实现的,原型链的基本思想是利用原型让一个类型继承另一个类型的属性和方法,把子类的原型对象设置为父类的实例,就形成了原型链。

// 父类
function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
}
// 子类
function SubType() {
    this.subProperty = false;
}
SubbType.property = new SuperType();            // 注意顺序
SubType.property.getSubValue = function() {     // 不能颠倒
    return this.subProperty;
}
// 实例
var instance = new SubType();

SuperType

SuperType + SubType

我们没有使用SubType默认提供的原型,而是将SuperType的实例作为它的新原型。

注:

1.通过原型链实现继承时,不能使用对象字面量创建原型方法,这样会重写原型链

// 父类
function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
}
// 子类
function SubType() {
    this.subProperty = false;
}
SubbType.property = new SuperType();           
SubType.property = function() {             // 重写了原型链,断开了与父类的连接
    getSubValue: function() {
        return this.subProperty;
    }
}
// 实例
var instance = new SubType();

2.所有引用类型默认都通过原型链实现了对Object的继承

五、继承

1.借用构造函数:在子类的构造函数中调用父类的构造函数,eg:

function SubType() {
    SuperType.call(this, attr1, attr2, ...);       // 运用call方法改变作用域
    ......
}

2.组合继承:将原型链和借用构造函数的技术组合到一起实现继承。

但组合继承会调用两次父类的构造函数,存在一定隐患。

3.原型式继承:

function object(O) {
    function F() {}        // (1)创建一个临时性的构造函数,将传入的对象作为构造函数的原型
    F.prototype = o;
    return new F();        // (2)返回临时类型的实例
}    

ECMAScript5新增了Object.create()方法规范原型式继承,传一个参数时与自定义的object()方法相同

4.寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

function inheritPrototype(SubType, SuperType) {
// 创建父类原型的一个副本
    var prototype = Object.create(SuperType.prototype); 
// 重写了原型的constructor属性的指向已经不正确了,需为其添加constructor属性
    prototype.constructor = subType;
// 将新建的对象赋给子类的原型
    subType.prototype = prototype;
}

猜你喜欢

转载自blog.csdn.net/qq_41649879/article/details/83443501