首页 >> js开发 >> js代码详解JavaScript之ES5的继承
js代码详解JavaScript之ES5的继承
发布时间: 2021年1月13日 | 浏览:
| 分类:js开发
自从有了ES6的继承后,ES5的继承也退出了舞台,在实际开发也不会用得着,但在面试或许用的着;先看看ES6的继承
class Father{
constructor(a){
console.log(a);
}
play(){
console.log("aaa");
}
static run(){
console.log("static");
}
}
class Son extends Father{
constructor(){
super();
}
}
var s=new Son();
s.play();
Father.run()
Son.run();
class Father{
constructor(a){
console.log(a);
}
play(){
console.log("aaa");
}
static run(){
console.log("static");
}
}
class Son extends Father{
constructor(){
super();
}
}
var s=new Son();
s.play();
Father.run()
Son.run();在ES6里只需要使用extends和super关键字即可继承父类的方法和属性(包括静态)在ES5里没有这些关键字ES5的继承ES5的五种种继承方式:
对象冒充继承
原型链继承
组合继承
原型式继承
寄生式继承(重要)
对象冒充继承原型链继承组合继承原型式继承寄生式继承(重要)
对象冒充继承对象冒充继承
function Father(_r){
this.r=_r;
console.log("aa");
console.log(this.r);
}
Father.a=3;
Father.run=function(){
console.log(Box.a);
}
function Son(){
Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
}
var b=new Son();//"aa",3
b.run();//TypeError
function Father(_r){
this.r=_r;
console.log("aa");
console.log(this.r);
}
Father.a=3;
Father.run=function(){
console.log(Box.a);
}
function Son(){
Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
}
var b=new Son();//"aa",3
b.run();//TypeError通过call或apply改变this指向,并执行了父类的构造函数缺点:只能继承超类的构造函数,无法继承原型链上的方法原型链继承原型链继承
function Father(){
console.log("aa");
}
Father.prototype.b=10;
Father.prototype.play=function(){
console.log(this.b);
}
Son.prototype=new Father();
function Son(){
}
var b=new Son();
b.play();//10
function Father(){
console.log("aa");
}
Father.prototype.b=10;
Father.prototype.play=function(){
console.log(this.b);
}
Son.prototype=new Father();
function Son(){
}
var b=new Son();
b.play();//10将父类的实例化对象赋值给子类的原型上实现的继承缺点:覆盖子类原有的属性和方法,只能执行父类的属性和方法,无法执行父类的构造函数组合继承组合继承前面的两种继承(冒充,原型链)各有特点,把这两种继承组合起来称为组合继承
function Father(_r){
this.r=_r;
console.log("aa");
}
function Son(_r){
Father.call(this,_r);//冒充,改变父类的this指向子类
}
Son.prototype=new Father(3);//原型链继承
var c=new Son(10);
function Father(_r){
this.r=_r;
console.log("aa");
}
function Son(_r){
Father.call(this,_r);//冒充,改变父类的this指向子类
}
Son.prototype=new Father(3);//原型链继承
var c=new Son(10);使用原型链继承了父类的属性和方法,使用对象冒充继承了父类的构造函数看起来很不错的样子,但这并不是完美的继承方式;缺点:会覆盖子类原有的属性和方法,因为原型链继承会将父类实例化,提前执行了一次父类构造函数;当子类实例化对象后,实际上是执行了两次父类的构造函数。使用场景:子类原本没有属性和方法,父类构造函数没有内容。原型式继承原型式继承为了解决执行两次父类构造函数使用了一个中介,在继承时就不会执行父类的构造函数
function Father(_a){
this.a=_a
}
Father.prototype.play=function(){
console.log("aaa");
}
function Agent(){
}
Agent.prototype=Father.prototype;
function Son(){
}
Son.prototype=new Agent();
var o=new Son();
o.play();//aaa
function Father(_a){
this.a=_a
}
Father.prototype.play=function(){
console.log("aaa");
}
function Agent(){
}
Agent.prototype=Father.prototype;
function Son(){
}
Son.prototype=new Agent();
var o=new Son();
o.play();//aaa使用了Agent的类作为中介,将父类的原型复制后,再进行实例化继承不会执行父类的构造函数;缺点:虽然解决了构造函数执行两次的问题,但是使用该方法继承后,构造函数一次也不会执行。寄生式继承(完美继承)封装了一个extend方法,该方法传入两个参数,分别是父类和子类
function extend(subClass, supClass) {
function Agent() {}
Agent.prototype = supClass.prototype;
var o = subClass.prototype;
subClass.prototype = new Agent();
if (Object.assign) {
Object.assign(subClass.prototype, o);
} else {
if (Object.getOwnPropertyNames) {
var names = Object.getOwnPropertyNames(o);
for (var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(names[i]);
Object.defineProperty(subClass.prototype, names[i], desc);
}
} else {
for (var prop in o) {
subClass.prototype[prop] = o[prop];
}
}
}
subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
if (supClass.prototype.constructor === Object) {
supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
}
// 存储父类,方便继承构造函数调用
subClass.prototype.superClass = supClass;
}
//调用
function Father(_r) {
this.r = _r;
console.log("Father");
}
Father.prototype.play = function () {
console.log("play game");
};
function Ball(_r) {
this.superClass.call(this, _r);
}
var s = new Son(10);//Father
s.play();//play game
function extend(subClass, supClass) {
function Agent() {}
Agent.prototype = supClass.prototype;
var o = subClass.prototype;
subClass.prototype = new Agent();
if (Object.assign) {
Object.assign(subClass.prototype, o);
} else {
if (Object.getOwnPropertyNames) {
var names = Object.getOwnPropertyNames(o);
for (var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(names[i]);
Object.defineProperty(subClass.prototype, names[i], desc);
}
} else {
for (var prop in o) {
subClass.prototype[prop] = o[prop];
}
}
}
subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
if (supClass.prototype.constructor === Object) {
supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
}
// 存储父类,方便继承构造函数调用
subClass.prototype.superClass = supClass;
}
//调用
function Father(_r) {
this.r = _r;
console.log("Father");
}
Father.prototype.play = function () {
console.log("play game");
};
function Ball(_r) {
this.superClass.call(this, _r);
}
var s = new Son(10);//Father
s.play();//play gameextend方法,使用了Object.assgin、Object.getOwnPropertyNames、Object.getOwnPropertyDescriptor、Object.defineProperty都存在兼容问题,所以进行了判断。该方法继承集合了前四种的优点,实现了ES5的完美继承;结语:结语:ES5对比ES6的继承,麻烦太多太多,以后的实际工作也不会使用;但是在面试的时候,面试官可能会问,多学一点总没错。以上就是详解JavaScript之ES5的继承的详细内容,关于JavaScript ES5的继承的资料请关注其它相关文章!
class Father{
constructor(a){
console.log(a);
}
play(){
console.log("aaa");
}
static run(){
console.log("static");
}
}
class Son extends Father{
constructor(){
super();
}
}
var s=new Son();
s.play();
Father.run()
Son.run();
class Father{
constructor(a){
console.log(a);
}
play(){
console.log("aaa");
}
static run(){
console.log("static");
}
}
class Son extends Father{
constructor(){
super();
}
}
var s=new Son();
s.play();
Father.run()
Son.run();在ES6里只需要使用extends和super关键字即可继承父类的方法和属性(包括静态)在ES5里没有这些关键字ES5的继承ES5的五种种继承方式:
对象冒充继承
原型链继承
组合继承
原型式继承
寄生式继承(重要)
对象冒充继承原型链继承组合继承原型式继承寄生式继承(重要)
对象冒充继承对象冒充继承
function Father(_r){
this.r=_r;
console.log("aa");
console.log(this.r);
}
Father.a=3;
Father.run=function(){
console.log(Box.a);
}
function Son(){
Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
}
var b=new Son();//"aa",3
b.run();//TypeError
function Father(_r){
this.r=_r;
console.log("aa");
console.log(this.r);
}
Father.a=3;
Father.run=function(){
console.log(Box.a);
}
function Son(){
Father.call(this,3);//改变this的指向,执行父类构造函数并传参到父类
}
var b=new Son();//"aa",3
b.run();//TypeError通过call或apply改变this指向,并执行了父类的构造函数缺点:只能继承超类的构造函数,无法继承原型链上的方法原型链继承原型链继承
function Father(){
console.log("aa");
}
Father.prototype.b=10;
Father.prototype.play=function(){
console.log(this.b);
}
Son.prototype=new Father();
function Son(){
}
var b=new Son();
b.play();//10
function Father(){
console.log("aa");
}
Father.prototype.b=10;
Father.prototype.play=function(){
console.log(this.b);
}
Son.prototype=new Father();
function Son(){
}
var b=new Son();
b.play();//10将父类的实例化对象赋值给子类的原型上实现的继承缺点:覆盖子类原有的属性和方法,只能执行父类的属性和方法,无法执行父类的构造函数组合继承组合继承前面的两种继承(冒充,原型链)各有特点,把这两种继承组合起来称为组合继承
function Father(_r){
this.r=_r;
console.log("aa");
}
function Son(_r){
Father.call(this,_r);//冒充,改变父类的this指向子类
}
Son.prototype=new Father(3);//原型链继承
var c=new Son(10);
function Father(_r){
this.r=_r;
console.log("aa");
}
function Son(_r){
Father.call(this,_r);//冒充,改变父类的this指向子类
}
Son.prototype=new Father(3);//原型链继承
var c=new Son(10);使用原型链继承了父类的属性和方法,使用对象冒充继承了父类的构造函数看起来很不错的样子,但这并不是完美的继承方式;缺点:会覆盖子类原有的属性和方法,因为原型链继承会将父类实例化,提前执行了一次父类构造函数;当子类实例化对象后,实际上是执行了两次父类的构造函数。使用场景:子类原本没有属性和方法,父类构造函数没有内容。原型式继承原型式继承为了解决执行两次父类构造函数使用了一个中介,在继承时就不会执行父类的构造函数
function Father(_a){
this.a=_a
}
Father.prototype.play=function(){
console.log("aaa");
}
function Agent(){
}
Agent.prototype=Father.prototype;
function Son(){
}
Son.prototype=new Agent();
var o=new Son();
o.play();//aaa
function Father(_a){
this.a=_a
}
Father.prototype.play=function(){
console.log("aaa");
}
function Agent(){
}
Agent.prototype=Father.prototype;
function Son(){
}
Son.prototype=new Agent();
var o=new Son();
o.play();//aaa使用了Agent的类作为中介,将父类的原型复制后,再进行实例化继承不会执行父类的构造函数;缺点:虽然解决了构造函数执行两次的问题,但是使用该方法继承后,构造函数一次也不会执行。寄生式继承(完美继承)封装了一个extend方法,该方法传入两个参数,分别是父类和子类
function extend(subClass, supClass) {
function Agent() {}
Agent.prototype = supClass.prototype;
var o = subClass.prototype;
subClass.prototype = new Agent();
if (Object.assign) {
Object.assign(subClass.prototype, o);
} else {
if (Object.getOwnPropertyNames) {
var names = Object.getOwnPropertyNames(o);
for (var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(names[i]);
Object.defineProperty(subClass.prototype, names[i], desc);
}
} else {
for (var prop in o) {
subClass.prototype[prop] = o[prop];
}
}
}
subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
if (supClass.prototype.constructor === Object) {
supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
}
// 存储父类,方便继承构造函数调用
subClass.prototype.superClass = supClass;
}
//调用
function Father(_r) {
this.r = _r;
console.log("Father");
}
Father.prototype.play = function () {
console.log("play game");
};
function Ball(_r) {
this.superClass.call(this, _r);
}
var s = new Son(10);//Father
s.play();//play game
function extend(subClass, supClass) {
function Agent() {}
Agent.prototype = supClass.prototype;
var o = subClass.prototype;
subClass.prototype = new Agent();
if (Object.assign) {
Object.assign(subClass.prototype, o);
} else {
if (Object.getOwnPropertyNames) {
var names = Object.getOwnPropertyNames(o);
for (var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(names[i]);
Object.defineProperty(subClass.prototype, names[i], desc);
}
} else {
for (var prop in o) {
subClass.prototype[prop] = o[prop];
}
}
}
subClass.prototype.constructor = subClass; //防止子类的构造函数被覆盖
if (supClass.prototype.constructor === Object) {
supClass.prototype.constructor = supClass; //防止父类类的构造函数被覆盖
}
// 存储父类,方便继承构造函数调用
subClass.prototype.superClass = supClass;
}
//调用
function Father(_r) {
this.r = _r;
console.log("Father");
}
Father.prototype.play = function () {
console.log("play game");
};
function Ball(_r) {
this.superClass.call(this, _r);
}
var s = new Son(10);//Father
s.play();//play gameextend方法,使用了Object.assgin、Object.getOwnPropertyNames、Object.getOwnPropertyDescriptor、Object.defineProperty都存在兼容问题,所以进行了判断。该方法继承集合了前四种的优点,实现了ES5的完美继承;结语:结语:ES5对比ES6的继承,麻烦太多太多,以后的实际工作也不会使用;但是在面试的时候,面试官可能会问,多学一点总没错。以上就是详解JavaScript之ES5的继承的详细内容,关于JavaScript ES5的继承的资料请关注其它相关文章!
相关文章:
- js代码浅谈JavaScript中this的指向更改
- jsVue $emit()不能触发父组件方法的原因及解决js大全
- jsVue 解决通过this.$refs来获取DOM或者组件报错问题js大全
- jsJS代码简洁方式之函数方法详解js大全
- js浅谈vue中$bus的使用和涉及到的问题js大全
- jsPostman如何实现参数化执行及断言处理js大全
- JavaScriptjs 数组当前行添加数据方法详解
- jsvue 组件之间事件触发($emit)与event Bus($on)的用法说明js大全
- js解决vue项目获取dom元素宽高总是不准确问题js大全
- JavaScript如何使用three.js 制作一个三维的推箱子游戏