JavaScript object面向对象——封装、继承、多态

130 阅读6分钟

Object:面向对象开发方式 - 三大特点(封装、继承、多态)

什么是面向对象:在程序中都使用对象来描述现实中的一个事物
           现实中事物的属性,代码中就成为了对象的属性
	   现实中事物的方法,代码中就成为了对象的函数
	   现实中所有数据都必须包含在一个事物中才有具体的意义

面向对象(Object-Oriented,简称OOP)是一种编程范式,它以对象(Object)为核心,将数据(即对象的属性,有时称为成员变量或字段)和操作这些数据的方法(即对象的行为,有时称为成员函数或方法)封装在一起,以此作为程序的基本单元。面向对象编程旨在模拟现实世界中的实体和它们之间的关系,通过抽象、封装、继承和多态四个基本原则来设计和实现软件。

10个引用类型都是对象(String/Number/Boolean/Array/Function/Math/Date/RegExp/Error/Object) - 浏览器内置对象

1、封装/创建/定义/声明/实例化:自定义创建对象:3种

封装意味着将对象的状态(属性)和行为(方法)捆绑在一起,并对外界隐藏内部细节,仅通过对象提供的公共接口与外界交互。这有助于减少代码间的耦合度,增强模块性。

	1、*直接量方式:
		var obj={
			"属性名":属性值,
			...
			"方法名":function(){},
			...
		}
		强调:1、其实属性名和方法名的""可以省略,但是不推荐
		      2、如何访问对象属性和方法
				obj.属性名 === obj["属性名"]
				obj.方法名(); === obj["方法名"]();
			 强烈建议:使用.去访问
		      3、访问到不存在的属性:返回undefined
		      4、也可以在后续添加自己想要的东西

		特殊:this在当前对象的方法内,指向的当前调用方法对象
		      面试题:this指向:
			1、单个元素绑定事件 this->单个元素
			2、多个元素绑定事件 this->当前触发的元素
			3、函数中也可以使用 this->当前调用函数的对象
			4、构造函数中如果出现了this->当前正在创建的对象
                            5、定时器中this->window
		      只要以后对象的方法想要使用对象自己的属性,那么就写为this.属性名

	2、预定义构造函数:var obj=new Object();//空对象
		     obj.属性名=属性值;
		     ...
		     obj.方法名=function(){}
		     ...

	以上两个方法仅适合创建单个对象,如果想要创建多个对象则太繁琐
	3、*自定义构造函数:21、创建一个构造函数
			function 类名(形参,...){
				this.属性名=形参1;
				this.属性名=形参2;
				...
			}

		2、反复调用构造函数创建出多个对象
			var xxx=new 类名(实参,...)
                            

继承:父对象的成员(属性和方法):子对象可以直接使用

继承允许一个类(子类)继承另一个类(父类)的特性和行为,从而实现代码复用,减少重复代码,并支持分层分类的概念。

为什么继承:代码重用!节约内存空间!
何时继承:只要多个子对象公用的属性和【方法】,都应该集中定义在父对象中

JS的面向对象是基于原型(父对象)的

什么是原型:保存一类子对象共有属性和共有方法的原型对象(父对象)

1、如何去找到原型对象:
	1、对象名.__proto__ - 至少要创建一个对象才可以使用
	2、构造函数名.prototype
	new 构造函数(Object RegExp Date Function String Number Boolean...)

2、在原型对象中添加共有属性和共有方法
	原型对象.属性名=属性值
	原型对象.方法名=function(){}

每一个对象都有一个.__proto__的属性指向着自己的原型
每一个构造函数都有一个.prototype属性指向着自己的原型

面试题:两链一包:
	原型链:自己没有的属性和方法,可以顺着原型链一直向上找,直到最顶层:Object.prototype - 
	作用:查找属性和方法
            一包:闭包

自有和共有
自有:保存在对象本地的
共有:保存在原型对象中的,子对象都可以直接使用

笔试题:
  1、判断一个属性是自有还是共有:
	1、判断自有:obj.hasOwnProperty("属性名");
		如果结果为true,说明是自有
		如果结果为false,可能是共有也可能是没有

	2、判断共有:2个条件
		obj.hasOwnProperty("属性名")==false;//可能是共有也可能是没有
		"属性名" in obj;//in关键字会查找自己的原型
		if(obj.hasOwnProperty("属性名")==false && "属性名" in obj){
			console.log("共有")
		}else{
			console.log("没有")
		}
	完整的:
		if(obj.hasOwnProperty("属性名")){
			console.log("自有");
		}else{
			if(obj.hasOwnProperty("属性名")==false && "属性名" in obj){
				console.log("共有")
			}else{
				console.log("没有")
			}
		}

  2、修改/删除属性
	自有:修改:obj.属性名=新值;
	      删除:delete obj.属性名;

	共有:修改:千万不要在本地做操作,那会导致在本地添加上一个同名属性,优先使用自己的,但并没有修改原型对象
	      删除:千万不要在本地做操作,那会导致白做没有任何效果
	      强调:一定要找到原型再做操作

  3、为一类人添加方法:
	比如:最常见的一道题:为老IE的数组添加indexOf方法 - 原本只有字符串可以使用,是后续升级数组才能使用的
		if(Array.prototype.indexOf === undefined){//老IE
			Array.prototype.indexOf = function(key,starti){
				starti===undefined&&(starti=0);
				for(var i=starti;i<this.length;i++){
					if(this[i]==key){
						return i;
					}
				}
				return -1;
			}
		}
	
	比如:为一人添加共有方法
		构造函数名.prototype.函数名=function(){
			this->函数中的代表当前调用此函数的对象
		}

   4、判断x是不是一个数组:41、判断当前x对象是否是继承自Array.prototypeArray.prototype.isPrototypeOf(x);
		true说明是一个数组

	2、判断当前x对象是否是由此构造函数所创建
		x instanceof Array
		true说明是一个数组

	3Array.isArray(x); - 只有数组才有此方法
		true说明是一个数组

	4、
	   在Object的prototype中保存着最原始的toString方法
	   原始的toString输出的结果:[object 构造函数名]
	***多态:子对象觉得父对象提供的方法不好用,可以再本地定义一个同名成员,优先使用离自己更近的方法
		 同一个函数名,但根本不是同一个方法
	   固定套路:
		 if(Object.prototype.toString.apply(arr)==="[object Array]"){
			数组
		 }
	
   5、如何设置自定义继承
	设置单个对象的继承:
		obj.__proto__=新对象

	设置多个对象的继承:
		构造函数名.prototype=新对象
		注意时机:在创建对象之前就设置好父对象
            

多态:

多态意味着子类可以重写或实现父类的方法,使得不同对象可以用统一的接口来调用,但表现出不同的行为。这增强了代码的灵活性和可扩展性

同一操作作用在不同对象上,可以产生不同的解释和不同的执行结果
简单说:给不同对象发送同一消息,可能会得到不同的反馈。