day13-面向对象
-
什么是对象?
1.面向对象是什么
一种高级编程思想 OO(Object Oriented)
-
什么是OO ?
这是一种拆分思想,就是把一个整体的程序拆分成几个部分,拆分成不同的程序组件,使用高内聚低耦合的设计原则将程序配合实现功能;
-
OO应该如何实现那 ?
- OOA(Object-Oriented Analysis )面向对象分析 : 是否能将程序拆分 ?
- OOD(Object-Oriented Design )面向对象设计 : 有了OOA之后必然可以使用OOD进行伪代码编写;
- OOP(Object Oriented Programming )面向对象编程 : 借助构造函数、原型对象、实例进行编程。
2.面向对象工具
-
构造函数
- 用
new
关键字来调用的函数,称为构造函数。 - 在一个构造方法中可以使用
super
关键字来调用一个父类的构造方法。 - 构造函数不能
return
- 用
-
constructor
-
constructor 是一种用于创建和初始化
class
创建的对象的特殊方法。 - 一个类中只能有一个名为 “constructor” 的特殊方法。 一个类中出现多次构造函数 (
constructor)
方法将会抛出一个SyntaxError
错误。 - 如果没有显式指定构造方法,则会添加默认的 constructor 方法。
- constructor表示函数是由谁构造的,是说明自己属于谁的一个属性。
- constructor和构造函数是伴生的关系。
var d = new Date(); console.log(d.constructor === Date); //true
-
constructor 是一种用于创建和初始化
-
类
- 类是抽象的,对象是具体的。
- 类是对象的抽象,对象是类的具体表现 。
- 类名首字母必须大写,驼峰式命名。
- 一个类的类体是一对花括号/大括号
{}
中的部分。这是你定义类成员的位置,如方法或构造函数。
-
子类
子类就是基于一个类别的扩展而实现新类别,原类别相对这个新类别叫做父类
-
基类
最起始的类别叫做基类,Object就是Js所有类别的基类
-
超类
子类的父类称为超类
-
继承
- 在原本类别的基础上实现扩展形成另一个类别,这就是继承
- 如果不继承任何类别,意味着自动继承Object
-
构造函数
构造函数,通过类创建对象的唯一入口函数
如果不写constructor,类别会自动添加这个函数,默认该函数没有内容,或者执行超类的构造函数
-
static
static
关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化该类,但不能通过一个类实例调用静态方法。静态方法通常用于为一个应用程序创建工具函数。 -
来个案例瞅瞅吧
class RectDiv { constructor(w, h, c) { this.createElem(w, h, c); } createElem(w, h, c) { this.elem = document.createElement("div"); Object.assign(this.elem.style, { width: w + "px", height: h + "px", backgroundColor: c }); } appendTo(parent) { parent.appendChild(this.elem); } } // extends继承 class Circle extends RectDiv { // 静态属性,只属于类 static FINISH_EVENT = "finish_event"; sum = 10; constructor(r, c) { // super()是超类的构造函数 super(r * 2, r * 2, c); // this.setCircle(r); } // 如果类的方法名与父类的方法名重名时,就意味这覆盖了父类的该方法 // override createElem(w, h, c) { // 调用超类的该方法,仍然使用父类的这个方法,只不过在下面追加该方法的内容 super.createElem(w, h, c); this.elem.style.borderRadius = w / 2 + "px"; Circle.dispatchs(); } static dispatchs() { // 不建议大家在静态方法中使用this,静态方法中的this就是该类名 let evt = new Event(Circle.FINISH_EVENT); document.dispatchEvent(evt); } } for (let i = 0; i < 10; i++) { let num = Math.floor(Math.random() * 25 + 25); let a = new Circle(num, Utils.randomColor()); a.appendTo(document.body); }
-
动态方法与静态方法
-
动态方法
直接在类中写的属性和方法,这些方法和属性,属于创建出来的对象,没有对象则不可以调用
var str = "abc"; str.substring() ; str.sub(); str.replace();
-
静态方法
使用static写的,这种方法是属于类的方法,不需要实例化就可以直接调用
例如:Math String.formCharCode
-
-
单例模式
保证一个类仅有一个实例。
无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象
class Circle{ constructor(r,c){ this.elem = this.createElem(r, c); } createElem(r,c){ //单例模式 if(this.elem) return this.elem; } }
3.ES6模块化开发
- ES6的模块化的基本规则或特点:
- 每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象;
- 每一个模块内声明的变量都是局部变量, 不会污染全局作用域;
- 模块内部的变量或者函数可以通过export导出;
- 一个模块可以导入别的模块
-
Circle.js
export class Circle{ } export class Rect{ }
-
Rect.js
export default class Rect{ a = 1; constructor(){ } play(){ } }
-
Circle11.js
import Rect from "./Rect.js" export default class Circle11 Rect{ }
-
HTML引入js
<script type="modul"> //解构赋值 import {Circle,Rect} from "./js/Circle.js"; //只需要导入一个模块时 //import Circle11 from "./js/Circle.js"; let a = new Circle(); let b = new Cirlce(); console.log(a, b) <script>
4.构造函数、实例对象和原型对象
实例对象
-
原型对象
// __proto__表明原产地的东西, // __proto__ : 原型指针; 创建了当前对象(实例)构造函数的原型; // object是顶级对象,它没有原型指针,顶级原型对象是Object.prototype; //__proto__指向当前对象的构造函数的原型对象 function Foo(){ } console.log(new Foo().__proto__ === Foo.prototype);//true
三者之间的关系:
- 构造函数 = 创造了 > 实例对象
- 实例对象 = 原型指针 > 原型对象
- 构造函数 = 伴生 > 原型对象
因为每次实例构造函数(new调用构造函数)的时候; 我们都会重新创建一套构造函数里的方法,导致同样的函数被多次创建,造成函数冗余;
只有用到构造函数,原型才有意义;
- 构造函数作用 : 构造函数 === init 方法 ; (初始编程所需要的数据)
- 实例 : 所有的数据都存在实例之中,是数据存储对象;
- 原型对象 : 所有的方法都放在原型对象之中;
- 除了 Object.prototype 之外的所有对象都有原型指针!;
- JS的访问机制 : 当访问对象之中的属性时,如果当前对象不存在,那么沿着原型指针继续向上查找;
功能和数据如何配合(耦合关系设计):
- 通过事件去进行调用处理
- 定时器进行调用
- 通过ajax请求进行调用
说明:
function Foo(){
this.fn = function(){
}
Foo.prototype.fn = function(){
}
}
var table = new Table();
table.fn();
// 直接把原型的方法放在函数里面和放在外面有什么区别吗
// 不会报错; 在实例调用fn的时候,是fn已经绑定在原型上之后调用的;
function Foo(){
this.fn = function(){
}
}
var table = new Table();
table.fn(); //调用fn的时候 , 原型之中还没有绑定fn方法;
// 直接把原型的方法放在函数里面和放在外面有什么区别吗
Foo.prototype.fn = function(){
}
// 会报错;