1.面向对象编程介绍
面向过程:分析出解决问题所需要的步骤,再用函数分步解决。
面向对象:把事务分解成对象,再由对象之间分工合作。
面向对象是以对象功能来划分问题,而不是步骤。
每一个对象都是功能中心,具有明确分工。灵活、可复用、易于维护。
面向对象的特性:
- 封装性
- 继承性
- 多态性
2.ES6中的类和对象
对象:可以用来描述现实事物,事物又可以分为具体的事物和抽象的事物。
手机(泛指,抽象);我手里的这一部手机(具体化,实例化,具体)。
面向对象的思维特点:
- 抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)
- 对类进行实例化,获取类的对象
面向对象编程就需要考虑:有哪些对象,按照面向对象的思维特点,不断创建对象,使用对象,指挥对象做事情。
2.1 对象
现实生活中,对象是一个具体的事物,看得见摸得着的实物。
JavaScript:对象是一组无序的相关属性和方法的集合,所有的事物都是对象。例如字符串、数值、数组、函数等。
对象是由属性和方法组成的:
- 属性:事物的特征(常用名词)
- 方法:事物的行为(常用动词)
2.2 类 class
ES6新特性,新增概念,可以使用class关键字声明一个类,之后用这个类实例化对象。
- 类抽象了对象的公共部分,泛指一大类(class)
- 对象特指某一个,通过类实例化一个具体的对象
2.3 创建类
类必须使用new实例化对象
2.4 类 的constructor 构造函数
constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过new命令生成对象实例时,自动调用该方法。如果没有显示类内部会自动给我们创建一个constructor().
// 1. 创建一个类 class
class Star {
// 类的构造函数 constructor()
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
}
// 2. 实例化对象
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 22);
console.log(ldh);
console.log(zxy);
注意点:
(1)通过类class 关键字创建类,类名习惯性首字母大写;
(2)类里面有个constructor函数,这个函数可以传递参数,也可以返回实例对象;
(3)constructor函数,只要 new生成实例的时候,就会自动调用,如果我们不写明,类也会自动生成这个函数;
(4)生成实例new 不能省略;
(5)创建类 类名后面不加小括号,生成实例 类名后加小括号,构造函数不加function.
2.5 类添加方法
// 1. 创建一个类 class
class Star {
// 类的构造函数 constructor()
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
// 类中添加方法
sing(song) {
// console.log('会唱歌');
console.log(this.uname + '唱了' + song);
}
}
// 2. 实例化对象
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 22);
console.log(ldh);
console.log(zxy);
// 调用
ldh.sing('冰雨');
3.类的继承
3.1 继承
子类可以继承父类的属性和方法。
class Father {
constructor() {
}
money() {
console.log(1000);
}
}
// 继承extends
class Son extends Father {
}
var son = new Son();
// 类Son 里没有方法,但是还是可以调用父类的方法
son.money(); // 1000
3.2 super
super() 关键字可以用来调用父类中的函数,包括构造函数和普通函数。
1. 调用构造函数
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关键字 可以调用父类中的构造函数
super(x, y);
// 这里不用this.x是由于指向问题,没办法传递参数进行函数调用(计算)
}
}
var son = new Son(1, 2);
son.sum(); // 3
2. 调用普通函数
(1)不继承就调用自身
// 1.子类(这里指Son)不继承,调用say()方法直接调用自己内部的函数
class Father {
say() {
return '这是父亲';
}
}
class Son {
say() {
console.log('这是儿子');
}
}
var son = new Son();
son.say(); // 这是儿子
(2)继承但由于自己也有这个方法,也会调用自己内部的
// 2. 继承但由于自己也有这个方法,也会调用自己内部的
class Father {
say() {
return '这是父亲';
}
}
class Son extends Father {
say() {
console.log('这是儿子');
}
}
var son = new Son();
son.say(); // 这是儿子
(3)子类自己内部没有,会调用父类里的
// 3. 子类自己内部没有,会调用父类里的
class Father {
say() {
// return 'test';
console.log('这是父亲');
}
}
class Son extends Father {
}
var son = new Son();
son.say(); // 这是父亲
(4)super关键字调用父类中的普通函数
// 4. super关键字调用父类中的普通函数
class Father {
say() {
return '这是父亲';
// console.log('这是父亲'); // 会 我是父亲 undefined
}
}
class Son extends Father {
say() {
console.log(super.say());
}
}
var son = new Son();
son.say(); // 这是父亲
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) {
// 1. 利用 super 调用父类中的sum方法
super(x, y);
// 而且必须在子类的this之前调用
this.x = x;
this.y = y;
}
// 2. 扩展自身减法
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(3, 1);
son.sum();
son.subtract();
// 注意:super在子类构造函数中使用时,必须在this之前调用
// (即必须先调用父类构造函数,再使用子类构造函数)
4.类和对象的三个注意点
-
ES6中的类没有变量提升,所以要先定义类,再实例化对象。
-
类里面共有的属性和方法一定要加this使用。
-
一定要注意类里面的this指向问题:
constructor里面的this指向实例对象,方法里的this指向这个方法的调用者。
var that;
class Star {
constructor(uname, age) {
// construcutor 中的this 指向 创建的实例
that = this;
this.uname = uname;
this.age = age;
// this.sing();
this.btn = document.querySelector('button'); // 选择button标签
this.btn.onclick = this.sing; // 点击后再调用,所以不加()
}
sing() {
// this 指向 btn,因为btn调用了sing()
console.log(that.uname);
// that里面存储的是constructor里的this
// 在constructor外部声明一个全局变量,把this存到里面;在这里调用that,相当于调用了constructor里面的this
}
dance() {
// 这个函数中,ldh调用了,所以指向ldh
console.log(this);
}
}
var ldh = new Star('刘德华');
ldh.dance();