javascript面向对象编程总结

1、javascript的类是什么?

js没有class关键字,虽然es6增加了class关键字,类的写法接近主流的高级语言的写法了,但是毕竟可能相当长时间不会大部分浏览器都支持的,因此,先忘了js的class吧。

一般语言的类是这样写的:

public class Student
{
	public string name;
	public int age;
	public int grade;

	public Student(string name,int age,int grade)
	{
		this.name=name;
		this.age=age;
		this.grade=grade;
	}
}

调用是这样的:

Student student1=new Student("小明",10,3);
Debug.WriteLine(student1.name);//小明
student1.course();//学习课程

js没有class,所以要用function代替类:

	function Student(name,age,grade)
	{
		//public属性
		this.name=name;
		this.age=age;
		this.grade=grade;

		//public方法
		this.course=function()
		{
			console.log("学生课程");
		};
	}


注意要点:必须用this.xxx来声明类属性和类方法,这样声明的属性和方法,都自动转成类实例的属性和方法。

这样调用:

var student1=new Student("小明",10,3);
var student2=new Student("小红",9,2);
console.log("student1.name="+student1.name);//小明
console.log("student2.name="+student2.name);//小红
student1.course();//学生课程
student2.course();
实例可以直接通过.xx来访问属性和方法。至此可以说js已经完成一个类的功能了,实例化每个类,变成一个独立的存在,然后拥有自己的属性和方法。

js奇葩的地方在于他还有一个原型。

2、什么是js的原型?

我个人理解,原型就是一个静态的代码段,放在内存中的某处。原型不会因为实例的增多而增多,他始终只有一个。就是静态属性和静态方法吧,简单理解。

3、js的原型怎么访问?

通过方法名(他也被叫做构造函数)访问:

Student.prototype

实例访问有两个方法:

student1.__proto__ (此方法已废弃)
或者:

Object.getPrototypeOf(student1);
他们是等价的:
console.log(Object.getPrototypeOf(student1)===Student.prototype);//true

4、js原型到底是什么东东?

之前说了,原型可以理解为静态方法和静态属性,那么比如上面这个例子,他的原型包含了什么呢?

因为上面Student这个构造函数,他只包含了一个构造函数,里面是实例属性和实例方法,并没有原型属性和原型方法,因此他的原型里面只包含了一个构造函数。

类似这样:

{constructor:function Student(name,age,grade){xxx}}

如果这个类还有其他原型方法的话,也会出现在这个大括号里,这个原型对象是一个object,用key-value的形式存放这些数据。

5、js原型有什么用?

构造方法为什么要原型化,我觉得没什么用,但是原型方法就很有用了,如果很多实例,他们都需要调用同一个方法,那么静态方法比实例方法就好多了,因为他只需要一个。而如果是用实例方法,那这些方法都是重复的,浪费了。

6、怎么构造一个原型方法或属性?

在他的原型上面添加属性或者方法:

		function Student(name,age,grade)
		{
			//public属性
			this.name=name;
			this.age=age;
			this.grade=grade;

			//public方法
			// this.course=function()
			// {
			// 	console.log("学生课程");
			// };
		}

		Student.prototype.course=function()
		{
			console.log("学生课程");
		};

还可以重写整个原型,这种方法的好处是有多少属性方法一口气写了,不用像上面那样每次加一个都要声明Student.prototype.xx=xxx:

		function Student(name,age,grade)
		{
			//public属性
			this.name=name;
			this.age=age;
			this.grade=grade;

			//public方法
			// this.course=function()
			// {
			// 	console.log("学生课程");
			// };
		}

		Student.prototype=
		{
			//注意这里构造函数要指向Student
			constructor:Student,
			course:function()
			{
				console.log("学生课程");
			}
		}

访问:

		var student1=new Student("小明",10,3);
		//可以把他当一个实例方法一样访问
		student1.course();
		Object.getPrototypeOf(student1).course();
		Student.prototype.course();

7、js的类怎么实现继承?

方法一:简单粗暴直接proto对proto赋值;效果:失败

		function Student()
		{
			this.studentValue="我是学生";
		}
		Student.prototype.getStudentValue=function()
		{
			// console.log(this.studentValue);
			console.log("我是学生,直接调用");
		};

		function HighSchoolStudent()
		{
			this.highSchoolStudentValue="我是高中生";
		}

		HighSchoolStudent.prototype=Student.prototype;



		HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
		{
			//console.log(this.highSchoolStudentValue);
			console.log("我是高中生,直接调用");
		};
调用方法:

		var student1=new Student();
		console.log(student1.studentValue);//我是学生
		student1.getStudentValue();//我是学生,直接调用
		console.log(student1.highSchoolStudentValue);//undefined
		student1.getHighSchoolStudentValue();//我是高中生,直接调用
可以看到,子类和父类共享一个prototype,当子类的prototype改变,父类的prototype也跟着改变,当子类添加了一个原型方法,父类也跟着有这个原型方法,这当然是错误的。

正确的通过原型继承的时候,当完成这个原型继承的时候(还未修改constructor指向之前),子类和父类的原型确实是一样的,但是,子类在后面对原型进行修改的时候,是绝对不会影响到父类的原型的。所以这种直接proto-proto赋值的方法是行不通的。

方法二:用父类的一个实例来给子类的proto赋值;效果:有问题

		function Student()
		{
			this.studentValue="我是学生";
		}
		Student.prototype.getStudentValue=function()
		{
			console.log(this.studentValue);
			// console.log("我是学生,直接调用");
		};

		function HighSchoolStudent()
		{
			this.highSchoolStudentValue="我是高中生";
		}

		HighSchoolStudent.prototype=new Student();
		// HighSchoolStudent.prototype=Object.create(Student.prototype);
		// HighSchoolStudent.prototype=createobject(Student.prototype);
		HighSchoolStudent.prototype.constructor=HighSchoolStudent;

		HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
		{
			console.log(this.highSchoolStudentValue);
		};
调用结果:

		var hightSchoolStudent=new HighSchoolStudent();
		console.log(hightSchoolStudent.studentValue);//我是学生
		hightSchoolStudent.getStudentValue();//我是学生
		console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生 
		hightSchoolStudent.getHighSchoolStudentValue();//我是高中生

可以看到,用过这种方式,父类的实例属性全部都带过来了,这个是不行的,这个还要原型有什么意义?

方法三:对父类使用Object.create(proto)给子类的proto赋值;效果:成功

		function Student()
		{
			this.studentValue="我是学生";
		}
		Student.prototype.getStudentValue=function()
		{
			// console.log(this.studentValue);
			console.log("我是学生,直接调用");
		};

		function HighSchoolStudent()
		{
			this.highSchoolStudentValue="我是高中生";
		}

		// HighSchoolStudent.prototype=new Student();
		HighSchoolStudent.prototype=Object.create(Student.prototype);
		// HighSchoolStudent.prototype=createobject(Student.prototype);
		HighSchoolStudent.prototype.constructor=HighSchoolStudent;

		HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
		{
			console.log(this.highSchoolStudentValue);
		};

调用结果:

		var hightSchoolStudent=new HighSchoolStudent();
		console.log(hightSchoolStudent.studentValue);//undefined
		hightSchoolStudent.getStudentValue();//我是学生,直接调用
		console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生 
		hightSchoolStudent.getHighSchoolStudentValue();//我是高中生

这是es5新增的方法,可以看到父类的实例属性已经访问不到了,但是原型方法还是可以访问到,成功。


方法四:对父类使用createobject(proto)给子类的proto赋值;效果:成功

		function Student()
		{
			this.studentValue="我是学生";
		}
		Student.prototype.getStudentValue=function()
		{
			// console.log(this.studentValue);
			console.log("我是学生,直接调用");
		};

		function HighSchoolStudent()
		{
			this.highSchoolStudentValue="我是高中生";
		}

		// HighSchoolStudent.prototype=new Student();
		// HighSchoolStudent.prototype=Object.create(Student.prototype);
		HighSchoolStudent.prototype=createobject(Student.prototype);
		HighSchoolStudent.prototype.constructor=HighSchoolStudent;

		HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
		{
			console.log(this.highSchoolStudentValue);
		};


		function createobject(proto)
		{
			function F(){}
			F.prototype=proto;
			return new F();
		}

调用结果:

		var hightSchoolStudent=new HighSchoolStudent();
		console.log(hightSchoolStudent.studentValue);//undefined
		hightSchoolStudent.getStudentValue();//我是学生,直接调用
		console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生 
		hightSchoolStudent.getHighSchoolStudentValue();//我是高中生

可以看到结果跟方法三是一样的。


方法五:对方法四进行封装。完美

把方法4封装一下,把构造函数的重新指向也封装到里面,免得漏掉了:

		function Student()
		{
			this.studentValue="我是学生";
		}
		Student.prototype.getStudentValue=function()
		{
			// console.log(this.studentValue);
			console.log("我是学生,直接调用");
		};

		function HighSchoolStudent()
		{
			this.highSchoolStudentValue="我是高中生";
		}

		// HighSchoolStudent.prototype=new Student();
		// HighSchoolStudent.prototype=Object.create(Student.prototype);
		// HighSchoolStudent.prototype=createobject(Student.prototype);
		// HighSchoolStudent.prototype.constructor=HighSchoolStudent;

		inherits(HighSchoolStudent,Student);

		HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
		{
			console.log(this.highSchoolStudentValue);
		};

		function inherits(Child,Parent)
		{
			function F(){}
			F.prototype=Parent.prototype;
			Child.prototype=new F();
			Child.prototype.constructor=Child;
		}


		function createobject(proto)
		{
			function F(){}
			F.prototype=proto;
			return new F();
		}
调用结果:

		var hightSchoolStudent=new HighSchoolStudent();
		console.log(hightSchoolStudent.studentValue);//undefined
		hightSchoolStudent.getStudentValue();//我是学生,直接调用
		console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生 
		hightSchoolStudent.getHighSchoolStudentValue();//我是高中生
可以看到,结果跟上面都是一样的。完美。

8、构造函数参数不同的子类

		function Student(name,age,grade)
		{
			this.name=name;
			this.age=age;
			this.grade=grade;
		}

		Student.prototype.course=function()
		{
			console.log("学生课程");
		};

		function HighSchoolStudent(name,age,grade,division)
		{
			Student.call(this,name,age,grade);
			this.division=division;
		}

		inherits(HighSchoolStudent,Student);

		HighSchoolStudent.prototype.highCourse=function()
		{
			console.log("高中课程");
		};

		function inherits(Child,Parent)
		{
			function F(){}
			F.prototype=Parent.prototype;
			Child.prototype=new F();
			Child.prototype.constructor=Child;
		}


		function createobject(proto)
		{
			function F(){}
			F.prototype=proto;
			return new F();
		}

调用:

		var student1=new Student("小明",10,3);
		student1.course();
		//student1.highCourse();//访问报错student1.highCourse is not a function
		console.log(student1.division);//undefined

		var highStudent1=new HighSchoolStudent("大鹏",15,12,"文科");
		highStudent1.course();//学生课程
		highStudent1.highCourse();//高中课程
		console.log(highStudent1.division);//文科




  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值