继承
作者:互联网
1.继承
继承分为:接口继承,实现继承,在js中只要实现继承,实现继承主要依靠原型链来做到的。
定义:利用原型链让一个对象拥有另一个对象的属性和方法。
让一个构造函数的原型对象等于另一个构造函数的实例
function Fn1(){ this.num=100; } Fn1.prototype.getNum=function(){ console.log(this.num) }; var fn1=new Fn1();
function Fn2(){}; Fn2.prototype=new Fn1(); var fn2=new Fn2();
console.log(fn2.getNum()) //100 console.log(fn2.__proto__) //Fn1 {num: 100} console.log(fn1.__proto__) //{getNum: ƒ, constructor: ƒ} console.log(Fn1.prototype) //{getNum: ƒ, constructor: ƒ}
console.log(Fn1.prototype==fn1.__proto__) //true
console.log(Fn2.prototype.__proto__==fn1.__proto__) //true console.log(fn1.__proto__==Fn1.prototype) //true
console.log(Fn2.prototype.__proto__==Fn1.prototype) //true
1.每个构造函数都有一个原型对象(prototype) 2.每个原型对象都包含一个指向该构造函数的constructor属性 3.每个new出来的实例都包含一个指向原型对象的隐式原型(__proto__)属性
2.构造函数的进阶应用
- 为什么我们要在构造函数里面定义属性,在构造函数的原型对象上写方法。
- 从实例化的过程来看,每个实例化对象的属性大多情况下都是不同的,所有大多数属性是可变的,定义在构造函数里面的属性优先级较高,所以实例化对象可以快速访问使用构造函数中的属性。
- 可以通过实例对象来访问保存在构造函数原型对象上的值,但是不能通过实例对象来重写原型上的值,如果一个实例对象修改了一个原型上的属性,其他实例对象在去访问这个实例属性的时候,这个实例属性就不是以前的实例属性了。
- 方法大多数情况下都是固定的,因此不必每次实例化的时候都把所有的方法实例化复制一遍。
- 构造函数的继承是依托于原型链来完成的,而在原型链中,构造函数的原型对象大多数情况下都是用来共享方法的,当然也可以共享一些衡邵改变的共享共用属性。
- 每次实例化都可以得到一个构造函数实例属性的副本,同时又可以共享着共用的方法,这样可以最大限度的节省内存。同时构造函数中的属性也支持床底参数来动态修改
function Fn1(name){ this.name=name; //this.getName=function(){} //可以这样写--但不建议--原因3 } //Fn1.prototype.name='1111'; //可以这样写--但不建议--原因2 Fn1.prototype.getName=function(){ console.log(this.name) } var fn1=new Fn1('2222').getName(); //2222 var fn2=new Fn1('3333').getName(); //3333
构造函数与原型组合使用的方式,在js组件化开发过程中是最通用用到的组件化开发方式
3.继承的方式
- new实例化的过程
- 创建一个空对象,
- 把实例对象的隐式原型__proto__指向构造函数的原型prototype(实例对象拥有了构造函数prototype原型对象上的属性和方法)
- 把构造函数的this指向替换成实例对象,再执行构造函数,(实例对象拥有了构造函数的属性和方法)
- 继承的方式
- 借用构造函数
原理:子类型构造函数的内部调用父类型构造函数
优点:1.子类可以继承父类构造函数中的属性 2.可以给父类构造函数中传递参数
缺点:子类没办法继承父类构造函数原型上的方法
function Fn1(name){ this.name=name; this.num=100; } Fn1.prototype.getName=function(){ return this.name } function Fn2(name){ Fn1.call(this,name); this.job='work' } var fn2=new Fn2('name'); console.log(fn2) //Fn2 {name: "name", num: 100, job: "work"}
2.组合继承
原理:利用原型链实现对原型属性和方法的继承,同时通过借用构造函数来实现子类对父类构造函数内部属性的继承(先用借用构造函数的形式让子类继承父类构造函数的属性,再用原型链让子类继承父类原型对象的方法)
优点:子类可以继承父类构造函数原型上的方法
缺点:1.会调用2次父类构造函数(一次构建子类原型对象,一次子类构造函数内部构建子类属性)
function Fn1(name){ this.name=name; this.num=100 } Fn1.prototype.getName=function(){ console.log(this.name) } function Fn2(name){ Fn1.call(this,name) //借用构造函数继承属性 this.job='work' } Fn2.prototype=new Fn1(); //使用原型链继承方法 Fn2.prototype.constructor=Fn2; //非必写--为了修正子类原型对象的constructor的属性
Fn2.prototype.getName=function(){
console.log(this.name+'-22')
} var fn2=new Fn2('name2'); fn2.getName(); //name2-22 console.log(fn2) //Fn2 {name: "name2", num: 100, job: "work"}
//console.log(fn2 instanceof Fn2) //true
//console.log(fn2 instanceof Fn1) //true
//console.log(fn2 instanceof Array) //false
//console.log(fn2 instanceof Object) //true
//console.log(Fn2.prototype.isPrototypeOf(fn2)) //true
//console.log(Fn1.prototype.isPrototypeOf(fn2)) //true
//console.log(Array.prototype.isPrototypeOf(fn2)) //false
//console.log(Object.prototype.isPrototypeOf(fn2)) //true
//console.log(Object.isPrototypeOf(fn2)) //false
3.原型式继承(浅拷贝)
场景:让一个对象与另一个对象保持类似结构。
原理:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
优点:构造函数内部和原型上的属性和方法都可以继承
缺点:包含引用类型值的属性会共享相应的引用类型的值。
var obj1={ name:'name1', num:[100,200], } //var obj2=obj1; //console.log(obj2) //{name: "name1", num: 100} var obj2=Object.create(obj1); obj2.name='name2'; obj2.num.push(300) //console.log(obj2.name); //name2 //console.log(obj2.num); //[100, 200, 300] //console.log(obj1.name); //name2 //console.log(obj1.num); //[100, 200, 300] var obj3=Object.create(obj1); obj3.name='name3'; obj3.num.push(400) console.log(obj3.name); //name3 console.log(obj3.num); //[100, 200, 300, 400] console.log(obj2.name); //name2 console.log(obj2.num); //[100, 200, 300, 400] console.log(obj1.name); //name1 console.log(obj1.num); //[100, 200, 300, 400]
4.寄生式继承
原理:定义一个独立的函数,在这个函数内部以某种方式来增强参数对象,在增加对象之后再返回对象
var obj1={ name:'name1', num:100, } function hanceObj(obj){ var newObj=Object.create(obj); newObj.setObj=function(){ console.log('23234') } return newObj; } var obj2=hanceObj(obj1); console.log(obj2) //{setObj: ƒ} { __proto__:{name: "name1" num: 100}}
5.寄生组合继承
原理:让第三方构造函数来寄生父类的原型,在子类构造函数内部使用父类.call(子类的实例)改变父类的构造函数的this指向
优点:1.解决组合继承调用2次父类构造函数的问题 2.节约内存开销
function Fn1(name){ this.name=name } Fn1.prototype.getName=function(){ console.log(this.name) } function Fn2(name){ Fn1.call(this,name); } hanceObj(Fn2,Fn1); function hanceObj(f2,f1){ var prototype=Object.create(f1.prototype); prototype.constructor=f2 f2.prototype=prototype; } var fn2=new Fn2('name222'); fn2.getName() //name222
标签:构造函数,console,log,Fn1,继承,prototype,name 来源: https://www.cnblogs.com/susu2020/p/16372339.html