JavaScript学习11-面向对象和原型

面向对象编程

以对象功能划分问题。
特性:封装性、继承性、多态性。
易维护、易复用、易扩展,性能比面向过程低。
思维特点:
1、抽取对象共用的属性和行为组织成一个类
2、对类进行实例化、获取类的对象

ES6中的类和对象

class关键字声明一个类。
类名首字母大写。

class 类名{
	//类属性、类方法
}

创建实例

var obj=new 类名();
构造函数constructor

constructor()方法是类的构造函数,用于传递参数、返回实例化对象,通过new命令生成对象实例时自动调用该方法,如果没有显示定义,类内部会自动创建一个constructor()。

<script>
	class Person{
		constructor(uname){
			this.name=uname;
		}
		sayHi(){
			console.log('嗨'+this.name);
		}
	}
	var xx=new Person('小明');
	console.log(xx);
	xx.sayHi();
</script>

类里的所有函数不需要写function,多个函数之间不需要添加逗号分隔。

类的继承

子类可以继承父类的一些属性和方法。

<script>
	class Parent{}
	class Son extends Parent{}
</script>
<script>
	class Parent{
		giveMoney(){
			console.log('give money');
		}
	}
	class Son extends Parent{}
	var son=new Son();
	son.giveMoney();
</script>
super关键字

用于访问和调用对象父类的函数,构造函数和普通函数

<script>
	class Parent{
		constructor(x,y){
			this.x=x;
			this.y=y;
		}
		sum(){
			console.log(this.x+this.y);
		}
	}

	class Son extends Parent{
		constructor(x,y){
			this.x=x;
			this.y=y;
		}
	}

	var son=new Son(1,2);
	son.sum();  //报错,因为子类没有使用super,不能用父类的方法

	// 子类修改成以下代码
	class Son extends Parent{
		constructor(x,y){
			super(x,y);  //调用父类的构造方法
			this.x=x;
			this.y=y;   // this要放在super下面
		}
		sum(){
			super.sum();  //调用父类的普通方法
		}
	}
</script>

ES6类没有变量提升,必须先定义类才能实例化对象,类里面的共有属性和方法一定要使用this

<script>
	class Start{
		constructor(){
			this.btn=document.querySelector('button');
			this.btn.onclick=this.sing;
		}
		sing(){
			console.log('lalalala');
		}	
	}
</script>

类的this指向

constructor里的this指向的是创建的实例化对象。
普通方法里的this指向的是调用方法的对象。

构造函数和原型

ES6

ECMAScript,2015年06月发布,大部分浏览器还是ES5,也支持ES6,但只实现了ES6部分功能和特性。
ES6前对象由构造函数来定义。
创建对象的三种方式:
1、对象字面量
2、new Object()
3、自定义构造函数

构造函数和原型

构造函数是一种特殊的函数,主要用来初始化对象,为对象成员变量赋初值,总是与new一起使用。

new 执行时做的四件事

1、在内存中申请空间,创建一个空对象
2、让this指向这个新对象
3、执行构造函数里的代码,给这个空对象添加属性和方法
4、返回这个新对象,所以构造函数中不需要return

成员

构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加,分为静态成员和实例成员。
静态成员:在构造函数上添加的成员,只能由构造函数本身访问。
实例成员:在构造函数内部创建的对象成员,只能由实例化对象访问。

<script>
	function Star(name){
			this.username=name;   //username是实例成员,只能通过实例化对象访问
		}
	Star.sex='男';   //sex是静态成员,只能通过构造函数访问

	var xx=new Star('小明');
	console.log(xx.username);
	console.log(Star.sex);
</script>

构造函数存在内存浪费的问题。

<script>
	function Star(name){
			this.username=name; 
			this.sing=function(){
				console.log('lalala');
			}
	}
	var xx=new Star('小明');
	var yy=new Star('小红');
</script>

每个对象的方法都要占空间
在这里插入图片描述

构造函数原型prototype

构造函数通过原型分配的函数是所有对象共享的。
每一个构造函数都有一个prototype属性,指向另一个对象。这个prototype属性就是一个对象,这个对象的所有属性和方法,都被构造函数所拥有。
可以把那些不变的方法定义在prototype对象上,这样所有的对象都可以共享。
原型是一个对象,我们称prototype为原型对象
原型的作用:共享方法

<script>
	class Person{}
	Person.prototype.sing=function(){
		console.log('lalalla');
	}
	var xx=new Person();
	var yy=new Person();
	xx.sing();
	yy.sing();
<script>

一般把共有属性定义在构造函数里,共有方法定义在prototype里。

对象原型__proto__

对象会有一个属性__proto__,指向构造函数的prototype原型对象,之所以对象可以使用构造函数的prototype原型对象的属性和方法就是因为对象有__proto__属性。

对象原型__proto__和原型对象prototype是等价的

<script>
	class Person{}
	var p=new Person();
	console.log(p.__proto__ === Person.prototype);   //true
</script>

对象原型__proto__存在的意义:为对象的查找机制提供一个方向,实际开发中不能使用这个属性。
在这里插入图片描述

constructor构造函数

对象原型和构造函数原型对象都有一个属性:constructor属性,指回构造函数本身。
constructor主要用于记录对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。

<script>
	function Person(){}
	var p=new Person();
	console.log(p.__proto__.constructor===Person.prototype.constructor);   //true
	console.log(p.__proto__);   //构造函数指向Person
	console.log(Person.prototype);   //构造函数指向Person
</script>

修改原型对象,会覆盖原来的原型对象

<script>
	function Person(){}
	Person.prototype={
		sing:function(){
			console.log('sing');
		}
		run:function(){
			console.log('run');
		}
	}
	var xx=new Person();
	var yy=new Person();
	console.log(xx.__proto__===Person.prototype);   //true
	console.log(p.__proto__);   //只包含sing和run,没有构造函数
	console.log(Person.prototype);   //只包含sing和run,没有构造函数
</script>

修改原型对象,利用constructor重新指向原来的构造函数

<script>
	function Person(){}
	Person.prototype={
		constructor:Person,
		sing:function(){
			console.log('sing');
		}
		run:function(){
			console.log('run');
		}
	}
	var xx=new Person();
	var yy=new Person();
	console.log(xx.__proto__===Person.prototype);   //true
	console.log(p.__proto__);   //有构造函数,sing,run
	console.log(Person.prototype);   //有构造函数,sing,run
</script>
原型对象的应用:扩展内置对象

通过原型对象,对内置对象进行扩展自定义方法
数组和字符串内置对象不能给原型对象覆盖操作:Array.prototype={}

<script>
	Array.prototype.sum=function(){
		var sum=0;
		for(var i=0;i<this.length;i++){
			sum+=this[i];
		}
		return sum;
	}

	var arr=[1,2,3];
	console.log(arr.sum());
</script>
构造函数、实例、原型对象之间的关系

在这里插入图片描述

原型链

在这里插入图片描述
构造函数有prototype属性,指向prototype对象,prototype对象有constructor属性,指回构造函数。
对象有__proto__属性,指向prototype对象,prototype对象有constructor属性,指回构造函数。

原型对象prototype也是对象,
对象有__proto__属性,指向Object prototype对象,Object prototype对象有constructor属性,指回Object 构造函数。
Object 构造函数有prototype属性,指向Object prototype对象,Object prototype对象有constructor属性,指回Object 构造函数。

Object 对象有__proto__属性,指向null。

JavaScript成员查找机制

1、访问一个对象的属性方法时先看这个对象自身有没有
2、对象自身没有,找他的原型,即__proto__指向的prototype原型对象
3、原型对象没有,找Object原型对象
4、一直找到null

继承

ES6之前没有extends关键字实现继承,通过构造函数+原型对象模拟实现继承,称为组合继承

call()

调用这个函数,并且修改函数运行的this指向

fun.call(thisArg,arg1,arg2...)
// thisArg: 当前调用函数this的指向对象
// arg1,arg2传递的其他对象
<script>
	function fn(){
		console.log(this);   
	}
	fn();   //window

	// 调用函数,等于fun();
	fn.call();   //window

	var obj={
		name: 'andy';
	}
	// 改变this指向
	fn.call(obj);    // obj{name:'andy'}
</script>
<script>
	function fn(x,y){
		console.log(this);  
		console.log(x+y); 
	}
	var obj={
		name: 'andy';
	}
	// 改变this指向,传其他参数
	fn.call(obj,1,2);    // obj{name:'andy'}   3
</script>
借用构造函数继承父类型属性

通过call()把父类型的this指向子类型的this,实现继承。

<script>
	function Father(uname){
		this.uname=uname;
	}
	function Son(uname){
		Father.call(this,uname);
	}
</script>
<script>
	function Father(uname){
		this.uname=uname;
	}
	function Son(uname){
		Father.call(this,uname);
	}
	Son.prototype=new Father();   //子类原型对象指向父类的构造函数
	Son.prototype.constructor=Son;  //利用对象形式改变了原型对象要利用constructor指回原构造函数
	// 添加子类的专有方法
	Son.prototype.exam=function(){
		console.log('exam');
	}
</script>
ES6通过类实现面向对象
class 类名{}

类的本质还是一个函数

console.log(typeof 类名);  //打印function

类有原型对象,也有constructor属性,也可以通过原型对象添加方法

console.log(类名.prototype);

语法糖:一种简便写法,es6的类的写法就是es5的简便写法。

ES5新增方法

数组方法

遍历方法:forEach(), map(), filter(), some(), every()

array.forEach(function(currentValue,index,arr))
				//数组当前项的值,当前项索引,数组
<script>
	var arr=[1,3,5];
	arr.forEach(function(value,index,array){
		console.log('每个元素值:'+value+',下标:'+index);
	});
</script>
array.filter(function(currentVale,index,arr))
				//数组当前项的值,当前项索引,数组
// filter()方法返回一个新数组,包含所有满足条件的元素,用于筛选
<script>
	var arr=[1,3,5];
	arr.filter(function(value,index){
		return value>1;
	});
</script>
array.some(function(currentValue,index,arr))
// 返回一个布尔值,查找是否存在满足条件的元素,找到一个就终止查找
<script>
	var arr=[1,3,5];
	var flag=arr.some(function(value){
		return value>1;
	});
	console.log(flag);
</script>
字符串方法
str.trim()
// 删除字符串两端空白字符,返回一个新字符
<script>
	var str1='    hi   ';
	var str2=str1.trim();
	console.log(str2);   //hi
</script>
对象方法
Object.defineProperty(obj,prop,descriptior)
				// 目标对象,属性名字,属性特性
// 定义对象中新属性,或修改原有属性

descriptor以对象形式书写,内包含:
value::设置属性的值,默认undefined;
writeable:值能否重写,默认false;
enumerable:是否能被枚举,默认false;
configurable:能否被删除或修改特性,默认false;

<script>
	var obj={
		id:1,
		name:'小明',
		age:18
	}
	Object.defineProperty(obj,'num',{
		value:100,
		enumerable:true
	})
	console.log(Object.keys(obj))   //返回对象的所有属性名
	delete obj.num;    //删除对象属性
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值