js继承

继承

prototype属性

  • 当我们在类中定义方法的时候,这个方法在每次创建实例对象的时候,都会被调用,开辟新的内存空间,则会导致内存消耗很大,因此我们可以将这个类具有的方法放在原型对象上(prototype)
  • 当我们修改原型上的属性的时候,就相当于在给该实例添加了一个这个属性
  • 所有通过同一个构造函数创建的实例对象,都会共享同一个prototype,这个属性是个指针,指向一个对象,该对象的用途就是包含所有实例共享的属性和方法
             function Person(newId,newName){
					 this.id=newId;
					 this.name=newName;
					 // this.eat=function(){
						//  console.log(eat);
					 // }
					 // this.sleep=function(){
						//  console.log(sleep)
					 // } 
				 }
				 Person.prototype.eat=function(){
					 console.log("eat");
				 }
				 Person.prototype.doing="做饭";
				 
				 let p=new Person(12,"小王");
				 // 当
				 p.doing="洗衣服";
				
				 let p1=new Person(13,"小明");
				 
				 console.log(p,p1)

在这里插入图片描述
可以通过delete来删除这个属性

 delete p.doing;

在这里插入图片描述

官方原型属性添加方法

             let arr=[1,3,4,5,6];
				Array.prototype.max=function(){
					let max=this[0];
					for(let i=0;i<this.length;i++){
						 if(max<this[i]){
							 max=this[i];
						 }
					}
					return max;
				}
				 console.log(arr.max())//6              

区分原型的属性和实例的属性

实例:用new调用构造函数创建出来的对象叫做实例
原型属性:写在prototype后面的叫做原型属性
实例属性:创建出来的对象,重新给原型属性赋值后,就成为了实例属性
函数(类)的属性: prototype
实例的属性proto

原型继承

  • 子类自动拥有父类的属性和方法就称为继承,继承可以提高代码的复用性。并且子类可以添加新的属性(自身)的属性和方法。
  • JS里的继承主要依靠的是原型链让原型对象(每一个构造函数都有一个原型对象)的值,等于另一个类型的实例,即实现了继承。
  • 另外一个类型的原型再指向第三个类型的实例,以此类推,也就形成了一个原型链
function Animal(newName,newAge){
	this.name=newName;
	this.age=newAge;
}

Animal.prototype.eat=function(str){
	console.log(this.name+"爱吃"+str);
}

 function Person(newId){
	 this.id=newId;
 }
 
 Person.prototype=new Animal("老王",18);
 
 Person.prototype.listen=function(str){
	 console.log(this.name+"听"+str);
 }
 
 let p=new Person("999");//实例中有一个_proto_属性指向原型对象
 
   console.log(p.name,p.age,p.id);
 p.eat("米饭");
 let a=new Animal();
// 使用instanceof操作符检测对象类型
 console.log(p instanceof Person);//true
 console.log(a instanceof Animal);//true

在这里插入图片描述
原型继承中的注意事项:

  • 先定义原型继承关系,再添加子类的自定义方法或属性(原型的属性,即共享的属性和方法要放在原型继承关系确立后,再定义,类对象在添加新的方式时,一定要保证,先实现继承,在添加原型方法)
  • 利用原型链继承,给子类添加原型方法的时,不可以重写prototype(:由父类派生给子类的属性,无法初始化)
    缺点
  • 被继承的类型(父类)里包括引用类型的属性的时候,它会被所有实例共享其值
  • 创建子类型的实例时,没法传参给被继承类型

call和apply的继承

bind、call、apply的区别

bind改变匿名函数的this指向

 setTimeout(function(){
		console.log(this);//document
	}.bind(document),1000)
	

apply()、call()
apply和call改变有名函数的this指向
第一个参数为this的指向
第二个参数为函数的实参
apply 传入函数的实参时候,传入的是一个数组
call 传入函数的实参的时候,实参分开写

   function fun(a,b){
			console.log(this)
			console.log(a+b);
		}
		fun.apply(document,[1,2])//参数为数组
		fun.call(document,1,2)//参数分开写

当一个方法被多个类进行调用的时候,如果在原型上定义该方法,内存还是会浪费,因此我们可以定义一个接口,此时则需要借助apply和call的方法改变this指向,从而实现不同的对象实现不同的消息响应

function Person(newId,newName){
			this.id=newId;
			this.name=newName;
			
		}
		// Person.prototype.eat=function(){
		// 	console.log(this.name+"吃"+str+str2)
		// }
		function Student(newId,newName){
			this.id=newId;
			this.name=newName;
			
		}
		// Student.prototype.eat=function(str,str2){
		// 	console.log(this.name+"吃"+str+str2)
		// }
		function eat(str,str2){
			console.log(this.name+"爱吃"+str+str2)
		}
		let p=new Person("1","小王")
			let s=new Student("2","小明")
		// 接口:发出一个消息,不同对象实现不同的消息响应
		eat.call(p,"面包","米饭");
		eat.apply(s,["米饭",""])

在这里插入图片描述

call和apply模拟继承

可以解决原型继承没有办法进行初始化的问题
原型继承缺陷:父类的属性派生给子类时,子类对象无法初始化父类继承来的属性,
call和apply继承可以进行进行初始化

function Person(newId,newName){
			this.id=newId;
			this.name=newName;
		}
		Person.prototype.eat=function(){
			console.log("Person eat");
		}
		function Student(newId,newName,newScore){
			// 借用构造方法
			Person.call(this,newId,newName);
			this.score=newScore;
		}
		let s=new Student(1,"老王",100);
		console.log(s.id,s.name,s.score)

在这里插入图片描述
当子类访问父类原型上的方法的时候,出现了报错,因此子类不能继承父类原型上的方法

 	s.eat();

在这里插入图片描述

混合继承

属性用apply和call
方法用原型

解决了原型继承和call,apply继承的缺陷

  • 父类的属性派生给子类时,子类对象可以初始化父类继承来的属性
  • 同时子类也会继承父类原型上的方法
function Person(newId,newName){
			this.id=newId;
			this.name=newName;
		}
		Person.prototype.eat=function(){
			console.log("Person eat");
		}
		function Student(newId,newName,newScore){
			// 借用构造方法
			Person.call(this,newId,newName);
			this.score=newScore;
		}
		Student.prototype=new Person();
			 
		Student.prototype.study=function(){
			console.log("Student study")
		}
		let s=new Student(1,"老王",100);
		s.eat();
		s.study()
		console.log(s.id,s.name,s.score)

在这里插入图片描述

ES6继承

extends:继承的关键字
super相当于父类的constructor
super一定要放在构造函数的第一位

class Person {
			constructor(newId,newName) {
				this.id=newId;
				this.name=newName;
			}
			eat(){
				console.log('Person eat');
			}
		}
			
		class Student extends Person{
			constructor(newId,newName,newScore) {
			//借用父类的构造方法
				super(newId,newName);
				this.score=newScore;
			}
			study(){
				console.log("Student study")
			}
		}
		let s=new Student(1,"老王",100);
		s.eat();
		s.study()
		console.log(s.id,s.name,s.score)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值