Javacript继承实现
原型链
实现继承
子类构造函数调用时同时调用父类构造函数,并将父类构造函数作用域的this指向子类构造函数的this
<script>
//子类构造函数调用父类构造函数的继承实现方法
function Super(){ //父类构造函数
this.val = 1;
this.arr = [1];
}
function Sub(){ //子类构造函数
// 子类公共变量
Super.call(this);//完成继承,改变作用域指向
}
var sub1 = new Sub(); //子类实例如果想要继承父类的公共变量,只需要让构造子类实例时调用父类构造函数,并将this指向新对象就可以了
console.log(sub1);
</script>
- 原型链继承
使用父类实例对象充当子类的原型对象属性
<script>
function Super(){
this.val = 1;
this.arr = [1];
}
function Sub(){
// 子类公共变量
}
Sub.prototype = new Super(); // 核心:拿父类实例来充当子类原型对象
var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
console.log(sub1.val); // 2,改了
console.log(sub2.val); // 1,没改,只能改自己的
console.log(sub1.arr); // 1, 2改变了数组
console.log(sub2.arr); // 1, 2
*问题
(1)继承到了修改后的 来源是一个对象Object 值类型数据指向同一个数组对象,一改全改不好用,有局限性
(2)不能通过子类构造函数实例化修改父类的成员变量—不能向父类实例对象传参
补充:构造函数实例化传参
//方便修改
2.借用父类构造函数实现继承
优化:可以向父类构造函数传参的问题
不用同一个对象指向
<script>
// 实现向父类构造函数的传参问题
function Super(val){ //可以传参
this.val = val;
this.arr = [1];
this.fun = function(){}
}
function Sub(val){
// 用了不同数组,也实现了同一对象的混淆性
Super.call(this, val); // 核心:借父类的构造函数来增强子类实例(把父类的实例属性复制了一份给子类实例装上了)
//this指的是实例化出来的对象
// 子类公共变量
}
var sub1 = new Sub(1);
var sub2 = new Sub(2);
sub1.arr.push(2);
console.log(sub1.val); // 1
console.log(sub2.val); // 2
console.log(sub1.arr); // 1, 2 //子类对象型数据不再公用
console.log(sub2.arr); // 1
alert(sub1.fun === sub2.fun); // false
</script>
存在的问题:
实例方法一对一冗余
3.组合式继承
最常用的
把实例函数都放在原型对象上
*考虑兼容性的情况下
<script>
// 考虑兼容性
function Super(val){ // 只在此处声明基本属性和引用属性
this.val = val;
this.arr = [1];
}
//函数写在原型对象上
Super.prototype.fun1 = function(){}; // 在此处声明函数
Super.prototype.fun2 = function(){}; // 把实例函数都放在原型对象上
//其他原型对象上的方法
function Sub(val){
Super.call(this,val); // 核心,保留借用构造函数方式的优点,让子类继承父类的基本属性和引用属性
// 子类公共变量
}
Sub.prototype = new Super(); // 核心,子类继承父类函数,实现函数复用
var sub1 = new Sub(1);
var sub2 = new Sub(2);
console.log(sub1.fun1 === sub2.fun1); // true 共用同一个函数
</script>
*声明函数啥都不发生,仅声明
子类的属性:自己的+原型链得来的 val,arr,fun1,fun2------查找时候先找自己的再找原型链的
瑕疵:同样属性给两份,浪费了内存
4.寄生组合式继承
*解决内存浪费问题
完美但不常用
<script>
function beget(obj){ // 生孩子函数,返回一个将参数对象作为原型对象的函数的实例
var F = function(){};
F.prototype = obj;
return new F();//对象的构造器
}
function Super(){ // 只在此处声明基本属性和引用属性
this.val = val;
this.arr = [1];
}
Super.prototype.fun1 = function(){}; // 在此处声明函数
function Sub(){
Super.call(this); // 核心,保留借用构造函数方式的优点,让子类继承父类的基本属性和引用属性
// 获取父类的成员变量
}
var proto = beget(Super.prototype); // 核心:用beget方法切掉了原型对象上多余的那份父类实例属性
proto.constructor = Sub; // 核心:将子类构造函数赋予beget出的对象的constructor属性
Sub.prototype = proto; // 核心:将beget出的对象赋予子类构造函数的prototype属性
var sub = new Sub();
console.log(sub.val);
console.log(sub.arr);
</script>
!!! 转载请注明出处