当前位置:网站首页>ES5写继承的思路
ES5写继承的思路
2022-07-25 15:00:00 【Henry_楠】
在js中,继承的方法有以下几种:
构造函数继承
function Parent() {
this.name = 'parent';
}
function Child(age) {
Parent.call(this);
this.age = age;
}
var c = new Child(12);
console.log(c.name); //输出parent
原理是在Child构造函数中利用call改变了this指向,使得Child对象增加了name属性,值为’parent’,完成了继承。
这种方法的缺点就是:父函数原型链上的东西不能被继承
function Parent() {
this.name = 'parent';
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
Parent.call(this);
this.age = age;
}
var p = new Parent(); //new一个Parent对象用来对比
p.say(); //输出say
var c = new Child(12);
c.say(); //undifined
say是Parent原型链上的方法,Parent对象调用方法时,如果自身不存在就回去原型链上寻找,在原型链上找到了say方法,而Child对象没有继承Parent对象的原型链,所以它在向上寻找时就找不到,输出undifined。
原型链继承
function Parent() {
this.name = 'parent';
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
this.age = age;
}
Child.prototype = new Parent();
var c = new Child(12);
console.log(c.name); //输出parent
c.say() //输出say
原型链继承是直接让Child构造函数的prototype直接指向Parent对象,这样Parent的东西Child对象可以直接从它的原型链上找到。
这种方法的缺点就是:当创建多个实例时,如果不同实例可能互相存在影响,例如:
function Parent() {
this.name = 'parent';
this.arr = [1,2,3,4]
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
this.age = age;
}
Child.prototype = new Parent();
var c1 = new Child(12);
var c2 = new Child(12);
console.log(c1.arr); //[1,2,3,4]
console.log(c2.arr); //[1,2,3,4]
c1.arr.push(5);
console.log(c1.arr); //[1,2,3,4,5]
console.log(c2.arr); //[1,2,3,4,5]
这里只对c1的arr进行了改变,却影响到了c2的arr,原因就是这种继承方式,实例的原型都是同一个对象,即new Parent()出来的Parent实例,当实例寻找arr时在自己这里找不到就会去找原型链上的Parent的属性,找到了arr,而arr又是引用类型,所以c1修改arr时,c2的arr也会发生改变。
构造函数和原型链继承组合方法
function Parent() {
this.name = 'parent';
this.arr = [1,2,3,4]
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
Parent.call(this);
this.age = age;
}
Child.prototype = new Parent();
var c1 = new Child(12);
var c2 = new Child(12);
console.log(c1.arr); //[1,2,3,4]
console.log(c2.arr);//[1,2,3,4]
c1.arr.push(5);
console.log(c1.arr); //[1,2,3,4,5]
console.log(c2.arr); //[1,2,3,4]
这种组合方式与上一种方法的区别就是,实例创建时就有了Parent里的属性,这样就不会去Parent寻找arr,修改的arr就是各自属性中的arr,就不会产生影响,同时也继承了Parent原型链上的东西。
这里优化一下:
之前 Child.prototype = new Parent() 即上面第二种继承方式,是为了继承Parent原型链的同时继承Parent函数里面的东西,现在在Child函数里已经用 Parent.call(this)直接继承了Parent函数里面的东西,那么就直接继承父函数的原型链就完事了即:
function Parent() {
this.name = 'parent';
this.arr = [1,2,3,4];
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
Parent.call(this);
this.age = age;
}
Child.prototype = Parent.prototype;
var c = new Child(12);
console.log(c.name); //输出parent
c.say(); //输出say
优化完之后,还是有缺点:
console.log(c.constructor); //输出Parent() {this.name = 'parent';this.arr = [1,2,3,4];}
在这里找Child的原型的constructor找到的是Parent的constructor,原因就是因为Child.prototype = Parent.prototype这里直接将Parent的prototype直接赋值给Child的prototype,所以它的constructor肯定就是Parent的constructor,这时不能直接这样修改:
Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;
console.log(c.constructor); //输出function Child(age) {Parent.call(this);this.age = age;}
console.log(new Parent().constructor); //输出function Child(age) {Parent.call(this);this.age = age;}
这时因为Parent.prototype(对象)是引用类型,所以修改Child的constructor,Parent的constructor也会改变,于是将Child.prototype = Parent.prototype;修改一下:
function Parent() {
this.name = 'parent';
this.arr = [1,2,3,4];
}
Parent.prototype.say = function () {
console.log('say');
};
function Child(age) {
Parent.call(this);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
var c = new Child(12);
console.log(c.name);
c.say();
console.log(c.constructor); //输出function Child(age) {Parent.call(this);this.age = age;}
console.log(new Parent().constructor); //输出Parent() {this.name = 'parent';this.arr = [1,2,3,4];}
用Object.create(Parent.prototype)这种方法创建一个新对象,赋值给Child.prototype,这样修改Child的constructor 时,Parent的constructor 就不会受到影响。
这是最完美的方法了
ps:es5及以下无法完美继承array,相关内容可自行搜索
边栏推荐
- As methods for viewing and excluding dependencies
- [C题目]力扣88. 合并两个有序数组
- Resource not found: rgbd_ Launch solution
- "Ask every day" reentrantlock locks and unlocks
- Fast-lio: fast and robust laser inertial odometer based on tightly coupled IEKF
- Detailed explanation of lio-sam operation process and code
- "Ask every day" briefly talk about JMM / talk about your understanding of JMM
- How to use the random number function of JMeter
- 流程控制(上)
- [C题目]力扣876. 链表的中间结点
猜你喜欢

Syntax summary of easygui

32 use of chrome debugging tools

"Ask every day" briefly talk about JMM / talk about your understanding of JMM

37 element mode (inline element, block element, inline block element)

6月产品升级观察站

阿里云技术专家邓青琳:云上跨可用区容灾和异地多活最佳实践

Melody + realsense d435i configuration and error resolution

45padding不会撑开盒子的情况

LeetCode-198-打家劫舍

Process control (Part 1)
随机推荐
[Android] recyclerview caching mechanism, is it really difficult to understand? What level of cache is it?
As methods for viewing and excluding dependencies
TypeScript学习2——接口
MySQL sort
阿里云技术专家邓青琳:云上跨可用区容灾和异地多活最佳实践
I2C device driver hierarchy
Universal smart JS form verification
"Ask every day" what is volatile
Deployment and simple use of PostgreSQL learning
[Nacos] what does nacosclient do during service registration
When using jetty to run items, an error is reported: form too large or form too many keys
pl/sql 创建并执行oralce存储过程,并返回结果集
39 简洁版小米侧边栏练习
easygui使用的语法总结
LeetCode_因式分解_简单_263.丑数
006 operator introduction
Gson and fastjson
45padding不会撑开盒子的情况
【JS高级】js之正则相关函数以及正则对象_02
安装EntityFramework方法