Javascript面向对象(二)

本文详细介绍了JavaScript中的继承机制,包括构造函数继承与原型继承,以及浅拷贝和深拷贝的概念和实现。通过实例展示了如何避免原型继承中的传址问题,强调了深拷贝在处理复杂对象时的重要性,确保了对象属性的独立性。
摘要由CSDN通过智能技术生成

继承

继承是面向对象当中的一个概念,与多态、抽象(封装)共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。

构造函数继承 / 原型继承

构造函数的继承只能用(apply call bind)
而原型的继承主要分为两种,即拷贝继承和原型继承

  • 我们先来看一下构造函数的继承:
//调用父类的构造函数,并且修改 this 指向为当前的实例对象,这样就可以把 父类构造函数中,定义的属性和方法获取过来。
function people(姓名,年龄){
    this.姓名 = 姓名;
    this.年龄 = 年龄;
}
people.prototype.说话 = function(话语){
    console.log(this.姓名+"说"+话语);
}
function HRBP(姓名,年龄){
    // 构造函数的继承 (call apply bind)
    people.call(this,姓名,年龄);
}
let 张三 = new people("张三",15);
let 李四 = new HRBP("李四",23)
console.log(李四);
  • 然后是原型继承以及会出现的一些问题:
    第一个思路是把父类的原型之间赋值给子类,虽然子类可以拿到父类的属性,但是这样会导致传址,即当我们再在子类上面修改prototype时,人类的prototype也会受到影响。
function people(姓名,年龄){
    this.姓名 = 姓名;
    this.年龄 = 年龄;
}
people.prototype.说话 = function(话语){
    console.log(this.姓名+"说"+话语);
}
function HRBP(姓名,年龄){
    // 构造函数的继承 (call apply bind)
    people.call(this,姓名,年龄);
}

HRBP.prototype = people.prototype;
let 张三 = new people("张三",15);
let 李四 = new HRBP("李四",23)
console.log(李四);
李四.说话("我就是李四");
  • 所以说这样显然是行不通的,下面我来具体讲一下如何对父类的属性进行拷贝,分为浅拷贝深拷贝

浅拷贝

拷贝:复制该对象的属性。把父类中原型中的所有属性拷贝到子类的原型中 而constructor本身属于不可枚举的属性 那这样的话就实现了父级的继承而且不会影响父类自身的属性。

浅拷贝:只拷贝对象的第一层

function people(姓名,年龄){
    this.姓名 = 姓名;
    this.年龄 = 年龄;
}
people.prototype.说话 = function(话语){
    console.log(this.姓名+"说"+话语);
}
function HRBP(姓名,年龄){
    // 构造函数的继承 (call apply bind)
    people.call(this,姓名,年龄);
}
HRBP.prototype.job = function(){
	console.log("公司经营计划");
}
HRBP.prototype = people.prototype;
function extend(father,child){
    for(let s in father.prototype){
       child.prototype[s] = father.prototype[s];
    }
 }
 extend(people,HRBP);
let 张三 = new people("张三",15);
let 李四 = new HRBP("李四",23)
console.log(李四);
console.log(张三);
李四.说话("我就是李四");

  • 但是浅拷贝也还是会有一些问题,比如父类比较复杂,可能不只含有基本类型的属性,还会有一些引用类型Object(如数组Arr或者对象),此时使用浅拷贝继承的话,又会把这个引用类型的属性直接传给子类,这样就又重新造成了传址的问题,所以只拷贝一层显然是不行的,于是深拷贝就很好的解决了该问题。

深拷贝

深拷贝: 循环对象的每一层,只要该属性的值是对象类型就进行拷贝。
通过刚刚对浅拷贝的安全性问题分析我们发现,使用深拷贝原型继承会更安全。总结一下深拷贝的过程:先传入数据进行拷贝,然后对数据进行判断,如果是基本类型数据那就直接返回该属性,如果是引用类型,那就再判断是对象格式的数据还是数组格式的数据,然后通过递归沿着对象或数组的属性一层一层向下拷贝(每一层都进行拷贝),把基本类型的数据拷贝给子类,这样就不会发生传址问题。

let father = {
        name: "姓名",
        age: 48,
        child:[
            {
                name: "小明",
                age: 20 
            },{
                name: "小红",
                age: 15 
            }
        ],
        salary:[
            10000,
            20000,
            25000
        ]
    };
    /*
        copy(father)
    */
    function copy(data){// 传入数据,拷贝该数据
        if(typeof data === "object"){ // 如果是一个引用类型就接着进行拷贝
            // 引用类型的数据常用有两种:数组 和 对象
            return Array.isArray(data)?copyArr(data):copyObj(data);
        } else {
            return data;
        }
    }
    function copyArr(arr){ // 对数组格式的数据进行拷贝
        let newArr = [];
        for(var i = 0; i < arr.length; i++){
            // arr[i] 有可能是基本类型也有可能是引用类型
            newArr.push(copy(arr[i]));
        }
        return newArr;
    }
    function copyObj(obj){ // 对对象格式的数据进行拷贝
        let newObj = {};
        for(var s in obj){
            newObj[s] = copy(obj[s]);
        }
        return newObj;
    }

    let child = copy(father);
    child.child[0].age = 24;
    console.log(child);
    console.log(father);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值