原型及继承

原型相关概念

一、实例和构造函数的关系
	实例是构造函数的具象化,由new关键字执行类之后得到的对象
	类是实例的抽象化   将多个具有共同特点的对象的特点抽象成规范,这个规范叫类(构造函数)
	实例 被 类 创造
二、实例对象
	实例对象和普通对象
	内部自带一个属性:`__proto__,这个属性是个对象类型,用来指向创建自身的类身上的`prototype`属性
三、 可被构造的函数(类)
    - 每个可被new执行的函数(类),身上都有一个属性:`prototype`,这个属性是个对象类型,用来**被**将来new执行时创建出来的实例身上的隐式原型`__proto__`指向
    - `prototype`也被称为显示原型
    - 在`prototype`这个属性内,又有一个属性:`constructor`,用来指向当前`prototype`所属的函数
四. 对象的属性的读写规则
    - 向上查找,就近原则
        - 当使用对象某个属性时,会先在对象自身查找,如果有就使用,如果没有,会顺着隐式原型__proto__,继续查找,如果找到,使用,同时停止,如果还没,继续查找...直到顶层原型,还找不到,抛出undefined

    - 通过实例,查找某个属性,自身没有,其实就是找自身构造函数的`prototype`,直达到找到最外层的Object,还没有就是undefined

    - 如果给构造函数的`prototype`添加属性或方法,意味着,将来的实例,也可以使用

继承方式

注:js继承指的是类与类之间的继承

一、改变this指向实现继承
特点:
**1.只能继承构造函数内部的属性或方法,无法继承原型上的属性或方法
 2. 简单方便易操作**
// 一、改变this指向实现继承
	// 特点:
	// 只能继承构造函数内部的属性或方法,无法继承原型上的属性或方法
	// 简单方便易操作
		function Speak(){
		    this.speak = function(){
		        console.log("这是一个:通话");
		    }
		}
		function Phone(){
		    Speak.call(this)
			// 原本是window执行了16行this所在的函数this指向window,通过call改变this指向,22行this所在函数被26行new执行,所以这个
			// this指向实例p,既16行执行时改变它this的指向为将来的实例
			// 通过改变父类this指向实现继承
		}
		
		var p = new Phone();
		console.log(p)   //Phone {speak: ƒ}
		p.speak()		//这是一个:通话
注:此方法 只能继承构造函数内部的属性或方法,无法继承原型上的属性或方法**

二、原型身上属性方法的继承

方式一:
	Child.prototype = Parent.prototype;
特点

对象,直接复制,浅拷贝,修改新数据,会影响老数据,
可理解为两个不同的变量名(obj1,obj2)存在栈中一样,在堆中他两对应的是一个对象a,给任意一个变量(如obj1)重新赋值(c)时obj2的值也变成了c
**

// 二、实现原型身上属性方法的继承
		
		function Parent(){}
		
		Parent.prototype.init = function(){
		    console.log("hahaha ")
		}
		
		function Child(){}
		
		var p = new Parent();
		console.log(p);
		console.log(p.init)
		p.init()
		var c = new Child();
		console.log(c);
		// console.log(c.init);
		c.init();
		// 方式一:
		// 对象,直接复制,浅拷贝,修改新数据,会影响老数据,
		// 可理解为两个不同的变量名(obj1,obj2)存在栈中一样,在堆中他两对应的是一个对象a,给任意一个变量(如obj1)重新赋值(c)时
		// obj2的值也变成了c
		Child.prototype = Parent.prototype;
		// Child.prototype.init = function(){console.log("啊啊啊 ")}
方式二:
通过for-in切换成深拷贝
	for(var i in Parent.prototype){
	    Child.prototype[i] = Parent.prototype[i];
	};

特点:
比较消耗性能,没有充分利用原型的特点,仅仅是对象的拷贝

// 方式二:还行,比较消耗性能,没有充分利用原型的特点,仅仅是对象的拷贝
function Parent(){}
		
		Parent.prototype.init = function(){
		    console.log("hahaha ")
		}
		
		function Child(){}
		//通过for-in切换成深拷贝
		for(var i in Parent.prototype){
		    Child.prototype[i] = Parent.prototype[i];
		};
		var p = new Parent();
		console.log(p);
		console.log(p.init)
		p.init()
		var c = new Child();
		console.log(c);
		// console.log(c.init);
		c.init();
方式三:
Child.prototype = new Parent("zhangsan")

将子类的原型设置成父类的实例,通过实例的__prototype__找到父类的prototype,更像是原型链
**特点:
隐患:new Parent()立即执行如果不传参报错,相当于多执行一次Parent的实例的创建 **

// 方式三:
// 将子类的原型设置成父类的实例,通过实例的__prototype__找到父类的prototype,更像是原型链
// 有隐患,某些参数的处理上如
				function Parent(name){
					this.name = name;
					this.init();
				}
				Parent.prototype.init = function(){
					var res = this.name.slice(0,3);
					console.log(res);
				}
				function Child(n){
					this.name = n;
					this.init();
				}
			Child.prototype = new Parent("zhangsan");//隐患所在
			var p = new Parent("admin");
				console.log(p);
				var c = new Child("root");
				console.log(c);
			
	// 	隐患:
	// 当parent内有属性需要参数接受时,87行 new Parent()立即执行如果不传参报错,相当于多执行一次Parent的实例的创建
		
		// 	解决思路:
			// 得到一个parent的实例
			// parent的实例的隐式原型 指向 Parent构造函数的显示原型
			
			// 既能创建一个:隐式原型指向Parent构造函数的显示原型的对象
			//             又不执行当前Parent函数,那就可以了
方式四:
Child.prototype = Object.create( Parent.prototype );

Object.create功能:创建一个新对象,并将这个新对象的隐式原型(proto),指向参数1

特点:趋向于完善,ES6提供的Object.create方法 更像是 原型 链

				function Parent(name){
					this.name = name;
					this.init();
				}
				Parent.prototype.init = function(){
					var res = this.name.slice(0,3);
					console.log(res);
				}
				function Child(n){
					this.name = n;
					this.init();
				}
// 方式四:趋向于完善,ES6提供的Object.create方法  更像是 原型 链
	Child.prototype = Object.create( Parent.prototype );
	
// Object.create功能:创建一个新对象,并将这个新对象的隐式原型(__proto__),指向参数1
		// var obj = Object.create( Parent.prototype );
				var p = new Parent("admin");
				console.log(p);
				var c = new Child("root");
				console.log(c);

注意:原型继承 只能继承原型身上的方法或属性,不能继承构造函数中的方法或属性

三、组合继承

特点:既能继承构造函数中的方法或属性,又能继承原型身上的方法或属性

继承构造函数中的方法或属性通过改变this指向;继承原型身上的方法或属性通过object.create

	function Parent(n){
		    this.name = n;
		}
		Parent.prototype.show = function(){
		    console.log(this.name);
		}
		
		
		function Child(n){
		    Parent.call(this, n);
		}
		Child.prototype = Object.create( Parent.prototype );
		var p = new Parent("admin");
		p.show();
		var c = new Child("root");
	 	c.show();

四、 最常用的是ES6提供的类的继承

父类:
class Person{
			// 相当于构造函数里的属性
			constructor(name,age){
				//属性
				this.name = name;
				this.age = age;
			}
			// 相当于父类的prototype父类的方法
			sayHello(){
				console.log(this.name)
			}
			static foo(){
				console.lg()
			}
			// static 定义静态方法(类方法),通过类直接访问,
			// 而不是通过类将来创建的实例访问
		}
		// Person.foo();
	子类	
		// 固定语法Male类继承Person类的属性,原型
		class Male extends Person{
			constructor(name,age){
				super(name,age);
				//super作用:
				// 1.创建this对象
				// 2.指向父类的构造函数
				// 当给子类添加自己的属性时一定要加上super
				this.sexy = "male";
			}
			// 给子类添加自己的类方法
			sayHi(){
				// console.log("hi"+this.name);子类的原型方法
				// 需求:在子类的原型方法内部使用父类的方法
				super.sayHello();
				// 这里super的作用:
					// 指向父类的原型对象
				this.sayHello();
				// this指向实例
				// sayHi是子类Male的原型方法,子类Male继承了
				// 父类的sayHello原型方法,this指向将来的实例,
				// 也能访问到父类sayHello因为创造实例的类
				// 已经继承父类sayHello
			}
			// 子类的类方法(静态方法)
			static bar(){
			// 需求在子类的类(静态)方法中访问父类的类(静态)方法
				super.foo()//super指向父类,相当于Person.foo();
				
				this.foo()
				// cosole.log(this)
				 这里的this指向的是整个子类Male,
				 子类继承了父类,子类本身(不是子类创造的实例)
				 也能访问到父类的类方法
				 父类中原型对象的方法,子类的实例也能访问到
				 
			}
		}
		// 原型方法实例访问,类方法类访问
		// 通过类访问类方法
		// Male.bar()
		
		let male = new Male("zhangsan",20);
		male.sayHello();
		console.log(male.sexy);
		male.sayHi()
		Male.bar()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值