js 继承的简单理解

什么是继承

  • js中的继承就是获取存在对象已有属性和方法的一种方式.

继承一 属性拷贝

就是将对象的成员复制一份给需要继承的对象.

 1 // 创建父对象
 2 var superObj = {
 3     name:'liyajie',
 4     age:25,
 5     friends:['小名','小丽','二蛋'],
 6     showName:function(){
 7         console.log(this.name);
 8     }
 9 }
10 
11 // 创建需要继承的子对象
12 var subObj = {};
13 // 开始拷贝属性(使用for...in...循环)
14 for(var i in superObj){
15     subObj[i] = superObj[i];
16 }
17 // 这里我们打印下subObj看下
18 console.log(subObj);
19 // 打印superObj(父对象)
20 console.log(superObj);

 

上述代码打印结果是一样的, 但是存在几点问题

属性拷贝继承的问题
如果继承过来的成员是引用类型的话,
那么这个引用类型的成员在父对象和子对象之间是共享的,
也就是说修改了之后, 父子对象都会受到影响.

继承二 原型式继承

原型式继承就是借用构造函数的原型对象实现继承. 即 子构造函数.prototype = 父构造函数.prototype

 1 // 创建父构造函数
 2 function SuperClass(name){
 3     this.name = name;
 4     this.showName = function(){
 5         console.log(this.name);
 6     }
 7 }
 8 // 设置父构造器的原型对象
 9 SuperClass.prototype.age = 25;
10 SuperClass.prototype.friends = ['小名','小丽'];
11 SuperClass.prototype.showAge = function(){
12     console.log(this.age);
13 }
14 
15 // 创建子构造函数, 刚开始没有任何成员
16 function SubClass(){
17 }
18 // 设置子构造器的原型对象实现继承
19 SubClass.prototype = SuperClass.prototype;
20 // 因为子构造函数的原型被覆盖了, 所以现在子构造函数的原型的构造器属性已经不在指向SubClass,
21 // 而是SuperClass,我们需要修正
22 console.log(SubClass.prototype.constructor == SuperClass);// true
23 console.log(SuperClass.prototype.constructor == SuperClass);// true
24 SuperClass.prototype.constructor = SubClass;
25 // 上面这行代码之后, 就实现了继承
26 var child = new SubClass();
27 console.log(child.age);// 25
28 console.log(child.friends);// ['小名','小丽']
29 child.showAge();// 25

 

!> 只能继承父构造函数的原型对象上的成员, 不能继承父构造函数的实例对象的成员, 同时父构造函数的原型对象和子构造函数的原型对象上的成员有共享问题

继承三 原型链继承

原型链继承 即 子构造函数.prototype = new 父构造函数();

 1 // 创建父构造函数
 2 function SuperClass(){
 3     this.name = 'liyajie';
 4     this.age = 25;
 5     this.showName = function(){
 6         console.log(this.name);
 7     }
 8 }
 9 // 设置父构造函数的原型
10 SuperClass.prototype.friends = ['小名', '小强'];
11 SuperClass.prototype.showAge = function(){
12     console.log(this.age);
13 }
14 // 创建子构造函数
15 function SubClass(){
16 
17 }
18 // 实现继承
19 SubClass.prototype = new SuperClass();
20 // 修改子构造函数的原型的构造器属性
21 SubClass.prototype.constructor = SubClass;
22 
23 var child = new SubClass();
24 console.log(child.name); // liyajie
25 console.log(child.age);// 25
26 child.showName();// liyajie
27 child.showAge();// 25
28 console.log(child.friends); // ['小名','小强']
29 
30 // 当我们改变friends的时候, 父构造函数的原型对象的也会变化
31 child.friends.push('小王八');
32 console.log(child.friends);["小名", "小强", "小王八"]
33 var father = new SuperClass();
34 console.log(father.friends);["小名", "小强", "小王八"]

 

问题是不能给父构造函数传递参数, 父子构造函数的原型对象之间有共享问题.

继承四 借用构造函数

使用callapply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题.

 1 // 创建父构造函数
 2 function Person(name){
 3     this.name = name;
 4     this.friends = ['小王','小强'];
 5     this.showName = function(){
 6         console.log(this.name);
 7     }
 8 }
 9 // 创建子构造函数
10 function Student(name){
11     // 使用call借用Person的构造函数
12     Person.call(this,name);
13 }
14 // 测试是否有了Person的成员
15 var stu = new Student('liyajie');
16 stu.showName(); // liyajie
17 console.log(stu.friends); // ['小王','小强']

 

继承五 组合继承

借用构造函数 + 原型式继承

 1 // 创建父构造函数
 2 function Person(name,age){
 3     this.name = name;
 4     this.age = age;
 5     this.showName = function(){
 6         console.log(this.name);
 7     }
 8 }
 9 // 设置父构造函数的原型对象
10 Person.prototype.showAge = function(){
11     console.log(this.age);
12 }
13 // 创建子构造函数
14 function Student(name){
15     Person.call(this,name);
16 }
17 // 设置继承
18 Student.prototype = Person.prototype;
19 Student.prototype.constructor = Student;
20 // 上面代码解决了 父构造函数的属性继承到了子构造函数的实例对象上了, 
21 // 并且继承了父构造函数原型对象上的成员, 
22 // 解决了给父构造函数传递参数问题
23 // 但是还有共享的问题

 

问题: 还有共享的问题

继承六 借用构造函数 + 深拷贝

前往深拷贝

 1 function Person(name,age){
 2     this.name = name;
 3     this.age = age;
 4     this.showName = function(){
 5         console.log(this.name);
 6     }
 7 }
 8 Person.prototype.friends = ['小王','小强','小王八'];
 9 
10 function Student(name,25){
11     // 借用构造函数(Person)
12     Person.call(this,name,25);
13 }
14 // 使用深拷贝实现继承
15 deepCopy(Student.prototype,Person.prototype);
16 Student.prototype.constructor = Student;
17 // 这样就将Person的原型对象上的成员拷贝到了Student的原型上了, 这种方式没有属性共享的问题.

 

推荐使用这种方式.

深拷贝(递归)

使用递归实现, 主要是为了解决对象中引用类型的成员的共享问题.

好处是不管是值类型的属性还是引用类型的成员都不会有共享问题.

 1 // 将obj2的成员拷贝到obj1中, 只拷贝实例成员
 2 function deepCopy(obj1, obj2) {
 3     for (var key in obj2) {
 4         // 判断是否是obj2上的实例成员
 5         if (obj2.hasOwnProperty(key)) {
 6             // 判断是否是引用类型的成员变量
 7             if (typeof obj2[key] == 'object') {
 8                 obj1[key] = Array.isArray(obj2[key]) ? [] : {};
 9                 deepCopy(obj1[key], obj2[key]);
10             } else {
11                 obj1[key] = obj2[key];
12             }
13         }
14     }
15 }
16 
17 var person = {
18     name: 'liyajie',
19     age: 25,
20     showName: function() {
21         console.log(this.name);
22     },
23     friends: [1, 2, 3, 4],
24     family: {
25         father: 'ligang',
26         mather: 'sizhongzhen',
27         wife: 'dan',
28         baby: 'weijun'
29     }
30 }
31 var student = {};
32 // 将person的成员拷贝到student对象上.
33 deepCopy(student, person);

 

Array.isArray()

此方法主要是来判断某个对象是否是数组, 因为是ES5的新特性, 所有有兼容性问题.

1 // 检查是否是数组对象
2 function checkIsArray(obj){
3     if(Array.isArray){// 如果有这个属性
4         return Array.isArray(obj);
5     } else {
6         return Object.prototype.toString.call(obj) == '[object Array]';
7     }
8 }

 

instanceof

简单来说用来判断某个对象是否是由某个构造函数创建的.
严谨一点: 用来检查某个对象的构造函数的原型对象是否在当前对象的原型链上, 因为原型链可以任意由我们修改

示例代码如下:

1 function Person(){}
2 var person = new Person();
3 console.log(person instanceof Person); // true
4 Person.prototype = {};
5 console.log(person instanceof Person); // false

 



作者:LiYajie
链接:https://www.jianshu.com/p/1016160e91fe
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/xfcao/p/11177073.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值