写在前面

注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者。有发现什么问题的,欢迎留言指出。

1.原型链

将原型链作为实现继承的方法,基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法:

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();
console.log(instance.getSuperValue());//true

原型链实现继承的问题:①问题来自包含引用类型值的原型,因为原来的实例属性变成现在的原型属性,会被共享,②在创建子类时,不能向超类型的构造函数中传递参数。

function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {}
//继承了SuperType
SubType.prototype = new SuperType(); 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", "black"]

2.借用构造函数

即是在子类型构造函数的内部调用超类型构造函数(还可以传递参数):

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

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

3.组合继承

即使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性:

function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function () {
console.log(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 () {
console.log(this.age);
} var instance1 = new SubType('jaychou',34);
instance1.colors.push("black");
console.log(instance1.colors);//["red", "blue", "green", "black"]
instance1.sayName();//jaychou
instance1.sayAge();//34 var instance2 = new SubType('xiaoming',15);
console.log(instance2.colors);//["red", "blue", "green"]
instance2.sayName();//xiaoming
instance2.sayAge();//15

4.原型式继承

没有使用严格意义上的构造函数,借助原型可以基于已有的对象创建新对象的特点。同时还不必因此创建自定义类型:

function inherit(p) {
if(p==null) throw TypeError();
if(Object.create) return Object.create(p);
var t = typeof p;
if(t !== "object" && t !== "funtion") throw TypeError();
function f() {};
f.prototype = p;
return new f();
}

好处:简单直接方便,只是简单地想一个对象与另一个对象保持类似的情况下,原型式继承是很不错的做法。注意点:包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样,如:

var person = {
name:'jaychou',
friends:[1,2]
}
var anotherP = inherit(person);
anotherP.friends.push(3);
console.log(person.friends);//[1, 2, 3]
anotherP.name = "xiaoming";
console.log(anotherP.name);//xiaoming
console.log(person.name);//jaychou

所以从本质上讲,原型式继承就是对传过来的对象执行了一次浅复制。

5.寄生式继承

即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象(接上):

function createAnother(original) {
var clone = inherit(original);
clone.sayHi = function () {
console.log("hi");
}
return clone;
}
var person = {
name:'jaychou',
friends:[1,2]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

在例子里给传进来的对象增加了方法sayHi,增强了对象。在主要考虑对象而不是自定义类型和构造函数的情况下,这个模式也不错。缺点:不能做到函数复用而降低效率了

6.寄生组合式继承

组合继承的问题就是调用了两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。解决方案就是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型:

//寄生组合式继承
function inheritPrototype(subType, superType) {
var prototype = inherit(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
}
function SubType(name,age) {
//借用超类型的构造函数继承了超类型的实例属性
SuperType.call(this,name);
this.age = age;
}
//寄生式继承了超类型的原型方法
inheritPrototype(SubType,SuperType); SubType.prototype.sayAge = function () {
console.log(this.age);
} var instance1 = new SubType("jaychou",34);
instance1.sayName();//jaychou
instance1.sayAge();//34 console.log(SuperType.prototype.isPrototypeOf(instance1));//true
console.log(instance1 instanceof SuperType);//true

好处:①只调用了一处SuperType构造函数,②避免了在SubType.prototype上面创建不必要的、多余的属性。综上,寄生组合式继承是继承的最理想方式。

js知识梳理4.继承的模式探究的更多相关文章

  1. js知识梳理3:创建对象的模式探究

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  2. js知识梳理5:关于函数的要点梳理(1)

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  3. js知识梳理6:关于函数的要点梳理(2)(作用域链和闭包)

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  4. js知识梳理2:对象属性的操作

    1.属性的查询和设置 ①基本语法 这个简单,可以通过点(.)或方括号([])运算来获取属性的值,注意点运算符后的标识符不能是保留字,方括号内的表达式必须返回字符串或返回一个可以转换成字符串的值. va ...

  5. js知识梳理1:理解对象的属性特性

    1.数据属性 数据属性的4个特性: Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为访问器属性.对象直接量里默认值true. Enum ...

  6. JS知识梳理--图表

  7. Vue.js 2.x API 知识梳理(一) 全局配置

    Vue.js 2.x API 知识梳理(一) 全局配置 Vue.config是一个对象,包含Vue的全局配置.可以在启动应用之前修改指定属性. 这里不是指的@vue/cli的vue.config.js ...

  8. js基础知识梳理(最简版)

    基础的JavaScript知识,只放XMind截图.小白 JS01 JS02 JS03 最基础的js知识--!

  9. solr DIH 知识梳理

    solr DIH 知识梳理 web.xml中listener配置 <listener> <listener-class>org.apache.solr.handler.data ...

随机推荐

  1. KDT入门小讲

    KDT入门小讲 为了搞讲课两天搞出来的PPT,质量不高,随便看看 附:讲课用PPT 链接: https://pan.baidu.com/s/1qHea0fEhscAsQh8-Yu_j_A 提取码: 4 ...

  2. CF1385G口胡

    只能说很神秘??? 首先观察题面,假设给出的第一个序列为 \(a\),第二个序列为 \(b\).对于 \((a_i,b_i)\) 我们连一条边. 得到的是一个 \(n\) 个点 \(n\) 条边的不一 ...

  3. SQL学习日记

    目录 SQL学习日记 1. 常见的数据库对象 2. DDL 定义语句 3. DML 操作语句 4. DQL 查询语句 5. DCL 控制语句 SQL学习日记 1. 常见的数据库对象 对象名 关键字 描 ...

  4. JavaWeb 07_创建web项目连接MySQL实现注册登录功能

    一.创建一个web项目,参照JW/01_创建web项目及部署 二.在NAVICat 里建数据库 db_01,建表tb_user ,字段UName .Pwd 三.在web下创建一个Directory, ...

  5. oracle 中有数据但是sql查询不出来结果(中文)

    如 select * from user where name like '%王%': 无数据: 而数据库中确实有姓王的用户. 配置环境变量 NLS_LANG = AMERICAN_AMERICA.A ...

  6. LINUX系统、磁盘与进程的相关命令

    ps ef:完整显示当前系统中所有运行的进程 kill 停止或杀死进程.9表示强制杀掉进程或任务 df 显示磁盘空间使用情况 du 用于显示指定目录下的文件以及子目录所占磁盘空间的大小. 与磁盘有关的 ...

  7. Netty之DefaultAttributeMap与AttributeKey的机制和原理

    一.介绍和原理分析 1.什么是 DefaultAttributeMap? DefaultAttributeMap 是一个 数组 + 链表 结构的线程安全Map. 2.什么是 AttributeKey? ...

  8. 如何在vscode中编写.net core 项目(vscode)

    1.下载拓展  .NET Core Extension Pack  (作者:保哥) 这个里面将需要的插件都打包了小白一键下载就好了 2.下载扩展   vscode-solution-explorer ...

  9. 为什么Java不支持运算符重载?

    另一个类似棘手的Java问题.为什么 C++ 支持运算符重载而 Java 不支持? 有人可能会说+运算符在 Java 中已被重载用于字符串连接,不要被这些论据所欺骗.与 C++ 不同,Java 不支持 ...

  10. MySQL 支持事务吗?

    在缺省模式下,MySQL 是 autocommit 模式的,所有的数据库更新操作都会即时 提交,所以在缺省情况下,MySQL 是不支持事务的. 但是如果你的 MySQL 表类型是使用 InnoDB T ...