IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Js继承上篇 -> 正文阅读

[JavaScript知识库]Js继承上篇

继承分为六部分:原型链、借用构造函数、组合继承、原型式继承、寄生式继承、寄生组合式继承。
今天时间有限,先整理下前3个,稍后再给各位粉丝和看客们分享后3个。如有遗漏或失误之处,欢迎各位积极指正。话不多说,进入正题:
很多语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名。实现继承则继承实际方法。由于函数没有签名,在ECMAScript中无法实现接口继承。ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。

一.原型链:利用原型让一个引用类型继承另一个引用类型的属性和方法。

使用原型链有一种基本模式,如下:

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}

//继承了SuperType()
SubType.prototype = new SuperType();
SubType.prototype.getSuperValue = function(){
    return this.subproperty;
}

var instance = new SubType();
alert(instance.getSuperValue());//true
//instance.getSuperValue()经历了三个搜索步骤:
//(1)搜索实例
//(2)搜索SubType.prototype
// (3)搜索SuperType.prototype,最后一步才会找到该方法。
//搜索过程总是要一环一环地前行,到原型链末端才会停下来。

1.默认的原型

所有函数都有默认原型Object实例,默认原型都包含一个内部指针,指向Object.prototype。这也是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。
上述案例:SubType继承了SuperType,而SuperType继承了Object。当调用instance.toString()时,实际上调用的是保存在Object.prototype中的那个方法。

2.确定原型和实例的关系

可以通过两种方式确定原型和实例之间的关系:(1)使用instanceof()操作符,用它来检测实例与原型链中出现过的构造函数,结果就会返回true。(2)使用isPrototypeOf()方法,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型,isPrototypeOf()方法也会返回true。
(1)instanceof()

alert(instance instanceof Object);//true
alert(instance instanceof SuperType);//true
alert(instance instanceof SubType);//true

由于原型链的关系,我们可以说instance是Object、SuperType或SubType中任何一个类型的实例。

(2)isPrototypeOf()

alert(Object.prototype.isPrototypeOf(instance));//true
alert(SuperType.prototype.isPrototypeOf(instance));//true
alert(SubType.prototype.isPrototypeOf(instance));//true

3.谨慎定义方法

子类型有时候需要覆盖超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但无论如何,给原型添加方法的代码一定要放在替换原型的语句之后。

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;
};

//重写超类型中的方法   通过SubType的实例调用会屏蔽最前面定义的getSuperValue
SubType.prototype.getSuperValue = function(){
    return false;
};

var instance = new SubType();
alert(instance.getSuperValue());//false

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

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
//继承了SuperType
SuperType.prototype = new SuperType();
//使用字面量添加新方法,会导致上一行代码无效
SubType.prototype = {
    getSubValue:function(){
        return this.subproperty;
    },
    someOtherMethod:function(){
        return false;
    }
};
var instance = new SubType();
alert(instance.getSuperValue());//error

以上代码展示了刚刚把SuperType的实例赋值给原型,紧接着又将原型替换成啦一个对象字面量而导致的问题。由于现在的原型包含了一个Object的实例,而非SuperType的实例,因此我们设想中的原型链已经被切断------SubType和SuperType之间已经没有关系了。

4.原型链的问题

原型链的问题有两个:
(1)最主要的来自包含引用类型值的原型。引用类型值的原型属性会被所有实例共享,而这也是为什么要在构造函数中,而不是原型对象中定义属性的原因。

SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("yellow");
alert(instance1.colors);//red,pink,green,yellow
var instance2 = new SubType();
alert(instance2.colors);//red,pink,green,yellow

(2)在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。由于原型中包含引用类型值所带来的问题,实践中很少会单独使用原型链。

二.借用构造函数

在解决原型中包含引用类型值所带来问题的过程中,开始使用一种叫做“借用构造函数”coustructor stealing的技术(有是也叫伪造对象或者经典继承)。
基本思想:在子类型构造函数的内部调用超类型构造函数。函数只不过是在特定环境中执行代码的对象,因此使用apply()和call()方法也可以在新创建的对象上执行构造函数。

function SuperType(){
    this.colors = ["red","yellow","green"];
}
function SubType(){
    //继承了SuperType
    SuperType.call(this);//重点“借调”了超类型的构造函数
}
var instance1 = new SubType();
instance1.colors.push("violet");
alert(instance1.colors);//red,yellow,green,violet

var instance2 = new SubType();
alert(instance2.colors);//red,yellow,green

使用call()方法,在新创建的SubType实例的环境下调用了SuperType构造函数。就会在新的SubType对象上执行SuperType()函数中定义的所有对象初始化代码。结果SubType的每个实例都会具有自己的colors属性的副本了。

1.传递参数

相对于原型链而言,借用构造函数有一个很大的优势。可以在子类型构造函数中向超类型的构造函数传递参数。

function SuperType(name){
   this.name = name;
}
function SubType(){
    //继承了SuperType,同时还传递了参数
    SuperType.call(this,"Nicholas");
    //实例属性
    this.age = 29;
}
var instance = new SubType();
alert(instance.name);//"Nicholas";
alert(instance.age);//29

SuperType只接受了一个参数name,该参数会直接赋给一个属性。在SubType构造函数内部调用SuperType构造函数时,实际上是为SubType的实例设置了name属性。为了确保SuperType构造函数不会重写子类型的属性,可以在调用超类型构造函数后,再添加应该在子类型中定义的属性。

2.借用构造函数的问题。

方法都在构造函数中定义,因此函数复用就无从谈起。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。考虑到这些问题,借用构造函数的技术也很少单独使用。

三.组合继承(combination inheritance)

也称伪经典继承,是指将原型链和借用构造函数的技术组合在一块,发挥二者之长的一种继承模式。思路:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性。

function SuperType(name){
    this.name = name;
    this.colors = ["red","yellow","violet"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name,age){
    //继承属性
    SuperType.call(this,name);
    this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    alert(this.age);
};
var instance1 = new SubType("Nicholas",29);
instance1.colors.push("orange");
alert(instance1.colors);//red,yellow,violet,orange
instance1.sayName();//"Nicholas"
instance1.sayAge();//29

var instance2 = new SubType("Greg",27);
alert(instance2.colors);//red,yellow,violet
alert(instance2.sayName());//Greg
alert(insatnce2.sayAge());//27

组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为了JavaScript中最常用的继承模式。instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-29 16:13:51  更:2021-11-29 16:16:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:17:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码