一、了解面向对象
1.定义
把事务分解成一个个对象,然后对象之间分工合作
2.使用场景
适合多人合作的大型项目
3.优点
可以设计出低耦合的系统,使系统更加灵活、代码可复用、容易维护
4.特性
封装、继承、多态
5.特点
-
抽取对象共用的属性金额行为组织封装成一个类
-
对类进行实例化、对象由属性(事务的特征)与方法(事务的行为)组成获取类的对象
对象由属性(事务的特征)与方法(事务的行为)组成
二、ES6中的类与对象
1.类class
使用class关键字声明一个类,之后以这个类实例化对象
类抽象了对象的公共部分,它泛指某一大类,类是对象的集合。
对象指通过对类实例化的一个具体的对象
类是对象的抽象,对象是类的实例
2.constructor构造函数
constructor()方法是类的构造函数,用于传递参数,返回实例对象,通过new命令生成对象实例时,自动调用该方法。
举例
公司员工这个集合是一个类,每个员工都是一个对象,其中姓名、工号等是属性,工作、休息等是方法。
代码实现:
// 创建类(类名首字母大写)
class Employee {
// 类的共有属性放在constructor中
constructor(name) { // constructor函数可以接收传递过来的参数,同时返回实例对象
this.name = name
} // 函数、方法之间不需要用逗号分隔
work() {
console.log(this.name + '在工作')
}
}
// 创建实例(用new实例化出一个对象)
var xWang = new Employee('小王')
console.log(xWang) // Employee { name: '小王' }
xWang.work() // 小王在工作
3.类的继承
子类可以继承父类的属性和方法
class Father {
// 父类
constructor(x, y) {
this.x = x;
this.y = y
}
sum() {
console.log(this.x + this.y)
}
}
class Son extends Father {
// 子类继承父类
constructor(x, y) {
super(x, y) // 调用了父类中的构造函数
}
}
var son = new Son(1, 2)
son.sum() // 3
- extends 关键字
- super 关键字:用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数。
继承中使用就近原则来查找一个属性或方法,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的,如果子类中没有,就去查找父类中有没有这个方法,如果有,就执行父类的这个方法。
class Father {
say() {
return '我是爸爸'
}
}
class Son {
say() {
console.log('我是儿子')
}
}
var son = new Son()
son.say() // 我是儿子
class Father {
say() {
return '我是爸爸'
}
}
class Son {
say() {
console.log(super.say() + '的儿子')
}
}
var son = new Son()
son.say() // 我是爸爸的儿子
super必须在子类this之前调用
注意:
-
es6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
-
类里面的共有属性和方法一定要加this使用
-
类中this的指向问题
- constructor中的this指向的是创建的实例对象
- 方法中的this指向这个方法的调用者
三、ES5中创建对象
在ES6之前,没有类的概念,所以是通过构造函数来定义对象和它们的特征。
1.构造函数
构造函数:一种特殊的函数,主要用于初始化对象,即为对象成员变量赋初始值,它总与new一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数中。
(1)利用new Object()创建
var obj = new Object()
(2)利用对象字面量创建
var obj = {}
(3)利用构造函数创建对象
function Employee(name, number) {
this.name = name
this.number = number
this.work = function() {
console.log('在工作')
}
}
var xWang = new Employee('小王', '1111')
console.log(xWang) // {"name":"小王","number":"1111"}
new在执行时会:
- 在内存中创建一个新的空对象
- 让this指向这个新的对象
- 执行构造函数中的代码,给这个新对象添加属性和方法
- 返回这个新对象(构造函数中不需要return)
构造函数中的属性和方法都称为成员
- 实例成员: 构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问。
- 静态成员: 在构造函数上添加的成员,静态成员只能通过构造函数来访问
// 例:
Employee.sex = '男'
console.log(Employee.sex) // 男
console.log(xWang.sex) // undefiend
构造函数的问题:存在内存空间的问题(属性属于简单式类型可以直接赋值,方法属于复杂类型,在new一个对象时,复杂类型会再开辟一个内存空间来存放复杂类型function() {})
2.构造函数原型 prototype
构造函数通过原型分配的函数时所有对象共享的。
每一个构造函数都有一个prototype属性(原型对象),prototype中所有的属性和方法,都会被构造函数所拥有。
公共属性定义到构造函数里面,公共方法放到原型对象上(不必开辟新的内存空间,所有的实例都可以使用这个方法)
// 代码实现
function Employee(name, number) {
this.name = name
this.number = number
}
Employee.prototype.work = function() {
console.log('在工作')
}
var xWang = new Employee('小王', '1111')
xWang.work() // 在工作
3.对象原型_proto_
对象都会有一个属性_proto_指向构造函数的prototype原型对象,之所以对象可以使用构造函数prototype原型对象的属性和方法,是因为对象有_proto_原型的存在。
4.construct 构造函数
对象原型_proto_和构造函数原型对象prototype中都有constructor属性。
function Employee(name, number) {
this.name = name
this.number = number
}
Employee.prototype = {
// 在这里是直接覆盖了原本的prototype对象,所以必须手动添加constructor属性来指向原本的构造函数。
constructor: Employee,
work: function() {
console.log('在工作')
},
rest: function() {
console.log('在休息')
}
}
var xWang = new Employee('小王', '1111')