文章目录

  • 前言
  • 原型链继承
    • 实现
    • 优点
    • 缺点
  • 借用构造函数继承
    • 实现
    • 优点
    • 缺点
  • 实例继承
    • 实现
    • 优点
    • 缺点
  • 组合式继承
    • 实现
    • 缺点
    • 优点
  • 寄生组合继承
    • 实现
  • es6语法实现继承
  • 原型工厂
  • 对象工厂
  • 总结
  • 参考资料

前言

建议先弄懂了原型链机制,再来观看本片笔记,这样收获更丰富哟。

首先,执行以下两句代码后,最终形成了这样的原型链。记住这张图!

function Foo() {};
var f1 = new Foo();

首先定义一个父类,为后面做铺垫。

// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology(){this.type = 'Biology';this.sex = "m"// 实例方法this.sleep = function(){console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function(){console.log("生物在叫:别骂了别骂了")console.log(this.superType);
}

原型链继承

实现

父类的实例作为子类的原型

// ----------------------------父类-----------------------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology() {this.type = 'Biology';this.sex = "m"// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("当前类型:" + this.type);
}// ------------------------子类---------------------------------------
function Person(name) {this.name = name;this.type = 'Person';
}// 继承实现关键代码:改变Person的protype指针,指向一个Biology实例
Person.prototype = new Biology()Person.prototype.yygq = function () {console.log("不会吧不会吧就这?")
}let sxc = new Person("孙笑川")
sxc.yygq()
sxc.superYygq()
console.log(sxc.type)
sxc.sleep()

输出

不会吧不会吧就这?
生物在叫:别骂了别骂了
当前类型:Person
Person

使用了原型链继承后,指针改变如下

优点

  • 简单易于实现,父类的新增的实例与属性子类都能访问

  • 实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。

缺点

  • 新实例不会继承父类实例的属性

  • 可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面

  • 无法实现多继承

  • 创建子类实例时,不能向父类构造函数中传参数


借用构造函数继承

实现

(伪造对象、经典继承)

复制父类的实例属性给子类


// -----------------父类----------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology() {this.type = 'Biology';this.sex = "m"this.name = ""// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("当前类型:" + this.type);
}// ------------------------子类---------------------------------------
function Person(name) {// 继承实现关键代码:在子类中call一个父类Biology.call(this)this.name = name;this.type = 'Person';
}Person.prototype.yygq = function () {console.log(this.name + "说:不会吧不会吧就这?")
}let sxc = new Person("孙笑川")
sxc.yygq()
// sxc.superYygq() 会报错
console.log(sxc.type)
sxc.sleep()

输出

优点

  • 子类构造函数可以向父类构造函数中传递参数

  • 可以实现多继承(call或者apply多个父类)

缺点

  • 方法都在构造函数中定义,无法复用

  • 不能继承父类的原型属性/方法

  • 只能继承父类的实例属性和方法


实例继承

实现

是一种原型式的继承


// -----------------父类----------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology() {this.superType = 'Biology';this.sex = "m"this.name = "生物"// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("当前类型:" + this.superType);
}// ------------------------子类---------------------------------------
function Person(name) {// 关键代码let instance = new Biology();instance.name = name || '人物';instance.type = 'Person';return instance;
}Person.prototype.yygq = function () {console.log("不会吧不会吧就这?")
}let sxc = new Person("孙笑川")
//sxc.yygq()
sxc.superYygq()
console.log("能否访问到父类中的属性:" + sxc.superType)
console.log(sxc.type)
sxc.sleep()
console.log(sxc instanceof Person)
console.log(sxc instanceof Biology)

输出如下

生物在叫:别骂了别骂了
当前类型:Biology
能否访问到父类中的属性:Biology
Person
孙笑川正在睡觉
false
true

优点

  • 不限制调用方式

  • 简单,易实现

缺点

  • 不能多次继承
  • 实例只是父类的实例,不是子类的实例
  • 不能通过改写子类的prototype来改变实例

组合式继承

实现

调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用


// -----------------父类----------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology(name, sex) {this.type = 'Biology';this.sex = sex || "m"this.name = name || "某生物"// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("type:" + this.type);
}// ------------------------子类---------------------------------------
function Person(name,sex) {Biology.call(this, name, sex)this.type = "日本天皇"this.money = 100
}Person.prototype = new Biology();
//  组合继承需要修复构造函数指向的。
Person.prototype.constructor = Person;// 要注意顺序
Person.prototype.yygq = function () {console.log(this.name + "说:不会吧不会吧就这?")
}
Person.prototype.getMoney = function(){console.log("剩下的钱:" + this.money)
}// ---------------------------------------------------------------let sxc = new Person("孙笑川")
sxc.yygq()
sxc.getMoney()sxc.superYygq()
console.log(sxc.type)
sxc.sleep()
console.log(sxc instanceof Person)
console.log(sxc instanceof Biology)

输出如下

孙笑川说:不会吧不会吧就这?
剩下的钱:100
生物在叫:别骂了别骂了
type:日本天皇
日本天皇
孙笑川正在睡觉
true
true

可以认为,这就是原型链继承和借用构造函数继承的组合体

缺点

  • 调用了两次父类,所以产生了两份实例

优点

  • 函数可以复用

  • 不存在引用属性问题

  • 可以继承属性和方法,并且可以继承原型的属性和方法

寄生组合继承

实现

通过寄生的方式来修复组合式继承的不足,完美的实现继承


// -----------------父类----------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology(name, sex) {this.type = 'Biology';this.sex = sex || "m"this.name = name || "某生物"// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("type:" + this.type);
}// ------------------------子类---------------------------------------
function Person(name, sex, money) {// 继承父类属性Biology.call(this, name, sex)this.type = "日本天皇"this.money = sex || 100
}// 继承父类方法
// 创建空类
let Super = function(){};
Super.prototype = Biology.prototype;// 父类的实例作为子类的原型
Person.prototype = new Super()// 修复构造函数指向问题
Person.prototype.constructor = Person;// 要注意顺序,先完成继承实现后,再进行该操作
Person.prototype.yygq = function () {console.log(this.name + "说:不会吧不会吧就这?")
}
Person.prototype.getMoney = function () {console.log("剩下的钱:" + this.money)
}// ---------------------------------------------------------------let sxc = new Person("孙笑川")
sxc.yygq()
sxc.getMoney()sxc.superYygq()
console.log(sxc.type)
sxc.sleep()
console.log(sxc instanceof Person)
console.log(sxc instanceof Biology)

输出

孙笑川说:不会吧不会吧就这?
剩下的钱:100
生物在叫:别骂了别骂了
type:日本天皇
日本天皇
孙笑川正在睡觉
true
true

原理浅析

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

执行完上述的继承代码后,所得结果如图所示。

这样就不会生成两份父类实例了,而是用一个空类来寄生在父类的原型链上。

写成一个函数,如下。这里要注意一下object.create和new的差别。

  • Object.create 是创建一个新对象,使用现有的对象来提供新创建对象的 proto。意思就是生成一个新对象,该新对象的 proto(原型) 指向现有对象。

  • new 生成的是构造函数的一个实例,实例继承了构造函数及其 prototype(原型属性)上的属性和方法。

// -----------------父类----------------------
// 定义一个Biology(生物)构造函数,作为 Person的父类
function Biology(name, sex) {this.type = 'Biology';this.sex = sex || "m"this.name = name || "某生物"// 实例方法this.sleep = function () {console.log(this.name + '正在睡觉')}
}// 原型方法
Biology.prototype.superYygq = function () {console.log("生物在叫:别骂了别骂了")console.log("type:" + this.type);
}// -----------------子类---------------------
function Person(name, sex) {Biology.call(this, name, sex)  // 继承第一次this.type = "日本天皇"this.money = 100
}/* 普通组合继承 */
// Person.prototype = new Biology();   //继承第二次/* 组合寄生 */
function inherit(son, father) {let prototype = Object.create(father.prototype);    //不发生第二次继承prototype.constructor = son;son.prototype = prototype;}
inherit(Person, Biology)// 子类原型方法
Person.prototype.yygq = function () {console.log("就这?")
};// 测试
let sxc = new Person("孙笑川")
sxc.yygq()sxc.superYygq()
console.log(sxc.type)
sxc.sleep()
console.log(sxc instanceof Person)
console.log(sxc instanceof Biology)

es6语法实现继承

代码量少,易懂

//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class Biology{constructor(name='某生物',sex='m'){this.name = name;this.age = age;this.type="生物"}eat(){console.log(`${this.name} ${this.age} eat food`)}
}//继承父类
class Person extends Biology{ constructor(name='某人类',sex='m', money){ //继承父类属性super(name, sex); this.money = money || 100} eat(){ //继承父类方法super.eat() console.log("就这?")}
} // 测试
let sxc = new Person("孙笑川")
sxc.eat()console.log(sxc.type)
sxc.sleep()
console.log(sxc instanceof Person)
console.log(sxc instanceof Biology)

原型工厂

原型工厂是将继承的过程封装,使用继承业务简单化。

function extend(sub, sup) {sub.prototype = Object.create(sup.prototype);sub.prototype.constructor = sub;
}function Access() {}
function User() {}
function Admin() {}
function Member() {}extend(User, Access); //User继承Access
extend(Admin, User); //Admin继承User
extend(Member, Access); //Member继承AccessAccess.prototype.rules = function() {};
User.prototype.getName = function() {};console.log(new Admin()); // 继承关系: Admin>User>Access>Object
console.log(new Member()); //继承关系:Member>Access>Object

对象工厂

在原型继承基础上,将对象的生成使用函数完成,并在函数内部为对象添加属性或方法。

function User(name, age) {this.name = name;this.age = age;
}
User.prototype.show = function() {console.log(this.name, this.age);
};function Admin(name, age) {let instance = Object.create(User.prototype);User.call(instance, name, age);instance.role=function(){console.log('admin.role');}return instance;
}let hd = Admin("管理员", 19);
hd.show();function member(name, age) {let instance = Object.create(User.prototype);User.call(instance, name, age);return instance;
}
let lisi = member("李四", 28);
lisi.show();

总结

这块就是链来链去的,多画图就悟了。

参考资料

js继承的几种方式

Object.create 和 new 区别与原理

前端进阶之道

图解js中继承的几种方式相关推荐

  1. js中继承的几种用法总结(apply,call,prototype)

    本篇文章主要介绍了js中继承的几种用法总结(apply,call,prototype) 需要的朋友可以过来参考下,希望对大家有所帮助 一,js中对象继承 js中有三种继承方式 1.js原型(proto ...

  2. Js中自定义对象四种方式

    Js中自定义对象四种方式 1 类似JAVA有参构造方式: 1.定义对象: function 对象(属性[age]){追加属性:如(this.age = age)[this代表当前对象的地址值的引用]追 ...

  3. (转)js实现继承的5种方式

    js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式 1.使用对象冒充实现继承(该种实 ...

  4. js中数组排序的五种方式

    下面主要介绍了数组排序的五种方式--sort()方法.选择排序.冒泡排序.插入排序和快速排序, 刚兴趣的朋友,可以往下看哦. 1.js中的sort()方法 基本思想:根据提供的排序规则,对数组元素进行 ...

  5. JS中创建对象:三种方式(pink)

    在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object): (1)利用字面量创建对象 (2)利用new Object创建对象 (3)利用构造函数创建对象

  6. JS 实现继承的 5 种方式

    文章目录 继承 原型链继承 原型链继承的优缺点 构造继承 构造继承的优缺点 复制继承 复制继承的优缺点 组合继承 组合继承的优缺点 寄生组合继承 参考 继承 继承作为面向对象语言的三大特性之一(继承. ...

  7. JavaScript(js)实现继承的几种方式

    1.原型链继承 核心:将父类的实例做为子类的原型对象 //动物类function Animal(name,sex) {this.name = name || 'Animal';this.sex = s ...

  8. 面试--js实现继承的几种方式

    基于原型的继承 function father() {this.faName = 'father';this.names=['11','22']}father.prototype.getfaName ...

  9. JS 总结之原型继承的几种方式

    在之前的总结中,我们详细分析了原型<JS 总结之原型>,原型很大作用用于模拟继承,这一次,我们来聊原型继承的几种方式. function Person (age) {this.age = ...

  10. Django中Model继承的三种方式

    Django中Model继承的三种方式 Django中Model的继承有三种: 1.抽象继承 2.多表继承 3.proxy model(代理model) 1.抽象继承 第一种抽象继承,创建一个通用父类 ...

最新文章

  1. Windows 2008 R2 X64 安装WebsitePanel(WSP虚拟主机管理面板)
  2. centos7安装git_【DevOps】centos7 下的 gitlab托管服务器的介绍与安装
  3. sqlserver循环like变量_numba从入门到精通(6)—numba与循环与并行
  4. java包装项目_项目包装组织
  5. java创建临时文件_用Java创建一个临时文件
  6. 转:如何用EXCEL表运用FV函数
  7. UI素材|标签页 Tab实用案例,可临摹学习
  8. Scala学习笔记(1)-环境搭建
  9. win11联网不能打开网页怎么办 windows11联网不能打开网页的解决方法
  10. 问答| 四轮驱动移动机器人(SSMR)简化模型的虚拟轮间距dLR具体是多少
  11. html5之Canvas坐标变换应用-时钟实例
  12. mven2 + androMDA 初探
  13. 音乐彩灯控制器C语言程序,基于单片机的LED彩灯控制器
  14. 眼袋、眼袋、眼袋!眼袋一直有~~~~ 肿么办啊
  15. 均衡负载集群(LBC)-2
  16. c语言 日志滚动 大小,Logrotate 日志滚动 解决日志占用空间过大
  17. 养QQ宠物不花Q币?完全可以!(转)
  18. 动力节点面试题mysql真的难_动力节点整理120道面试问题集锦
  19. java arcgis envi_ArcGIS三维入门(2-15)使用ENVI基于立体影像提取DEM
  20. Vim 编辑器的使用

热门文章

  1. bat批处理的注释语句
  2. 【pdanet】免流热点共享 破解pdanet
  3. VC中CDockablePane使用心得
  4. 大概都能懂的Eviews教程:二(转载)
  5. 内网渗透(抓取明文密码)
  6. 计算机硬盘数据存满如何开机,清理磁盘方法 让电脑开机速度加快(3-1)
  7. xpose使用教程 hook java层的代码 (一 公司取名.apk)
  8. WebView复制粘贴文本
  9. Sublime快捷键大全
  10. 第六章 软件项目质量管理