写在前面

注:这个系列是本人对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. egg中使用sequelize事务,实现原子性

    let transaction; try { // 建立事务对象 transaction = await this.ctx.model.transaction(); const house = awa ...

  2. Django基础五之Ajax

    Django基础五之Ajax 目录 Django基础五之Ajax 1. Ajax介绍 2. Ajax前后端传值 2.1 方法一HttpResponse直接返回 2.2 方法二使用Json格式返回 2. ...

  3. Fiddler抓包常用功能

    通过上一篇文章Fiddler移动端抓包,我们知道了Fiddler抓包原理以及怎样进行移动端抓包,接下来介绍Fiddler中常用的功能. Fiddler中常用的功能如下: 停止抓包 清空会话窗内容 过滤 ...

  4. ng-messages AngularJs 表单校验方式

    最新研究了一下表单校验,直接上代码. <!DOCTYPE html><html ng-app='app'><head> <meta charset=" ...

  5. sqlmap的使用手册

    0x01. Sqlmap支持的数据库 SQLMap支持的数据库: MySQL Oracle PostgreSQL Microsoft SQL Server Microsoft Access IBM D ...

  6. redis的事件处理机制

    redis的事件处理机制 redis是单进程,单线程模型,与nginx的多进程不同,与golang的多协程也不同,"工作的工人"那么少,可那么为什么redis能这么快呢? epol ...

  7. MySQL&SQL server&Oracle&Access&PostgreSQL数据库sql注入详解

    判断数据库的类型 当我们通过一些测试,发现存在SQL注入之后,首先要做的就是判断数据库的类型. 常用的数据库有MySQL.Access.SQLServer.Oracle.PostgreSQL.虽然绝大 ...

  8. Java常用类笔记(学习尚硅谷java基础教程)

    一.Java根类Object类1.toString()方法 1)以文本对象返回,故toString()的定义为public String toString() {} 2)默认的字符串输出是:包.类名@ ...

  9. 论文翻译:2021_Acoustic Echo Cancellation with Cross-Domain Learning

    论文地址:https://graz.pure.elsevier.com/en/publications/acoustic-echo-cancellation-with-cross-domain-lea ...

  10. flexible如何实现自动判断dpr?

    判断机型, 找出样本机型去适配. 比如iphone以6为样本, 宽度375px, dpr是2