js知识梳理4.继承的模式探究
写在前面
注:这个系列是本人对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.继承的模式探究的更多相关文章
- js知识梳理3:创建对象的模式探究
写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...
- js知识梳理5:关于函数的要点梳理(1)
写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...
- js知识梳理6:关于函数的要点梳理(2)(作用域链和闭包)
写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...
- js知识梳理2:对象属性的操作
1.属性的查询和设置 ①基本语法 这个简单,可以通过点(.)或方括号([])运算来获取属性的值,注意点运算符后的标识符不能是保留字,方括号内的表达式必须返回字符串或返回一个可以转换成字符串的值. va ...
- js知识梳理1:理解对象的属性特性
1.数据属性 数据属性的4个特性: Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为访问器属性.对象直接量里默认值true. Enum ...
- JS知识梳理--图表
- Vue.js 2.x API 知识梳理(一) 全局配置
Vue.js 2.x API 知识梳理(一) 全局配置 Vue.config是一个对象,包含Vue的全局配置.可以在启动应用之前修改指定属性. 这里不是指的@vue/cli的vue.config.js ...
- js基础知识梳理(最简版)
基础的JavaScript知识,只放XMind截图.小白 JS01 JS02 JS03 最基础的js知识--!
- solr DIH 知识梳理
solr DIH 知识梳理 web.xml中listener配置 <listener> <listener-class>org.apache.solr.handler.data ...
随机推荐
- tp 防止xss攻击
跨站脚本攻击(Cross Site Scripting),攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的. ...
- 图解|用好MySQL索引,你需要知道的一些事情
我是蝉沐风. 这一篇文章来聊一聊如何用好MySQL索引. 为了更好地进行解释,我创建了一个存储引擎为InnoDB的表user_innodb,并批量初始化了500W+条数据.包含主键id.姓名字段(na ...
- CSS学习Day01
1.什么是CSS 如何学习 CSS是什么 CSS怎么用 CSS选择器(重点+难点) 美化网页(文字.阴影.超链接.列表.渐变) 盒子模型 浮动 定位 网页动画(特效效果) 1.1什么是CSS Casc ...
- LGP6146题解
思维僵化了,习惯按照右端点排序,没想到是按照左端点排序... 考虑从左到右依次加入线段,考虑贡献. 设前 \(i\) 条线段的答案为 \(dp[i]\). 考虑两种情况: 不加,贡献为 \(dp[i- ...
- Tomcat高级配置(应用场景总结及示例)
前言 本文将解决以下问题: 如何将Linux下任意位置的项目(虚拟目录)部署到tomcat? 如何将项目部署到服务器特定端口? 如何在一个服务器上部署多个web应用? 本例中 系统:Linux ver ...
- kubernetes内yaml格式
yaml格式的pod定义文件完整内容: apiVersion: v1 #必选,版本号,例如v1 可通过 kubectl api-versions 获取 kind: Pod #必选,Pod metada ...
- 自动化运维之SaltStack初探
1.1.基础环境 linux-node1(master服务端) 192.168.31.46 CentOS 6.6 X86_64 linux-node2(minion客户端) 192.168.31.47 ...
- Linux内核升级修复系统漏洞-RHSA-2017:2930-Important: kernel security and bug fix update
公司使用的阿里云服务器(Centos7.4 x86_64bit)内核版本为:3.10.0-693.21.1.el7.x86_64, 2019年3月4日 02:07:58通过云盾安骑士-->漏洞管 ...
- K8S原来如此简单(五)Metrics Server与HPA
什么是HPA https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/ 我们前面有通过kubectl ...
- Python_Learn,Python背景的介绍
一.计算机程序的运行方式 机器语言编写的程序可以在计算机上直接运行,而汇编语言和高级余语言写的程序(通常称为源程序)则需要"翻译"成机器语言才能运行.源程序"翻译&quo ...