类与对象
类(class)是对象(Object)的模板,定义了同一组对象共有的属性和方法
类更加的抽象,对象更加的具体
ES5的 类
类的名称使用 大写,是为了让别人知道这不是一个普通的方法
function People() {
this.name = '潜龙'
this.age = 34
}
// 对象实例化
const p1 = new People()
console.log('p1', p1);
为了提高对象实例化的复用性,对象类属性的赋值采用形参的方式
function People(name, age) {
this.name = name
this.age = age
}
let p2 = new People('潜龙', 24);
console.log('p2', p2)
// p2 People {name: "潜龙", age: 24}
People 类 中 等号左边 是 类里面的属性, 右边是 传入的形参
上面的 p1 和 p2 就是 实例化后的 对象, 而 People 则是抽象类
类里面 this 指向
function People(name, age) {
console.log(this)
this.name = name
this.age = age
}
let p1 = new People('潜龙', 24);
let p2 = new People('simpleSky12', 34);
console.log(p1, p2);
this 指向的 是, 实例化对象后 的本身
类中方法的定义
一般 es5 中定义 类的方法,不会将方法放在构造函数中定义,也就是通过 this.方法名() 的方式去定义,这样的做法会损耗性能,因为每次我们 new 实例化的时候都会渲染方法,但是可能我们用不到这个方法,这就会导致资源的浪费。
所以常规的做法是 将 类的方法,通过 原型链的方式 去定义, 即 prototype
function People(name, age) {
this.name = name
this.age = age
}
People.prototype.showName = function () {
console.log('名字是:' + this.name);
};
let p1 = new People('潜龙', 24);
let p2 = new People('simpleSky12', 34);
p1.showName();
p2.showName();
//名字是:潜龙
//名字是:simpleSky12
常见的内置对象
常见的 内置对象 为 String, Object, Array, Math
let str = new String('潜龙');
console.log('str:', str);
let arr = new Array(1, 2, 3);
console.log('arr: ', arr);
let obj = new Object();
obj.name = '潜龙'
console.log('obj: ', obj);
// 静态方法
console.log(Math.max(4, 10));
console.log(Math.random() * 10);
Math对象下 方法 的调用方式中可以看出, Math 下的方法 属于静态方法,不需要对 Math 实例化,即可直接使用,很便捷
静态属性与静态方法
静态属性 是 直接定义在 类下面,而实例属性 则是定义在 类的 构造函数中
实例属性 => 构造函数
实例属性,会在类每次的实例化中,重复的调用
// People 类的 构造方法
function People(name, age) {
// 实例属性
this.name = name
this.age = age
// People 每实例化一次,静态属性 count 就自增一
People.count++
}
// 静态属性
People.count = 0
console.log(People.count)
console.log(new People('潜龙', 24));
console.log(new People('simpleSky12', 34));
console.log(People.count);
静态方法是直接定义在类下面的,和静态属性类似,但是实例方法是定义在 类的 原型链上的
function People(name, age) {
this.name = name
this.age = age
}
People.count = 0
// 静态方法
People.getCount = function () {
console.log('当前实例化的对象个数:', People.count)
};
// 实例方法
People.prototype.getAge = function () {
console.log('年龄是:', this.age);
}
People.getCount() //当前实例化的对象个数: 0
let p1 = new People('潜龙', 24);
p1.getAge() //年龄是: 24
静态方法只能调用 静态属性,如果调用 this下的属性,会返回 undefined, 因为 构造函数中的this指向 的 是实例化对象,我们调用 静态方法的时候,没有实例化对象
ES5 中 类的 继承
构造函数继承
这个方法只能继承 构造函数中 this 的属性,不能继承 类中的声明的方法
主要使用的方法 是 call() , 来改变 this 指向, 将原来子类中的this指向,改成 父类的this指向
// 父类
function Animal(name) {
this.name = name
}
Animal.prototype.showName = function () {
console.log('名字是:' + this.name);
};
// 子类
function Dog(name, color) {
Animal.call(this, name) // 继承父类属性
this.color = color
}
let dog1 = new Dog('旺财', 'white');
console.log('dog1', dog1);
dog1.showName()
这里我们可以看出来 dog1 对象,只是成功继承了 父类 Animal 中 构造函数中 关于 this下属性 name 的继承,并没有成功继承到 父类 Animal 中的方法showName()
原型继承
改进方法,利用 对象的 prototype 原型来进行 方法和构造方法的继承
这个方式只能继承 父类的方法,无法继承 父类 的 this 属性,即构造函数
// 父类
function Animal(name) {
this.name = name
}
Animal.prototype.showName = function () {
console.log('名字是:' + this.name);
};
// 子类
function Dog(name, color) {
this.color = color
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
let dog2 = new Dog('小白', 'white')
console.log(dog2);
dog2.showName()
从控制台的 打印结果可以看出 父类 的构造方法 对于 name的设置并没有生效
组合式继承
这个方式是将 原型继承和 构造函数继承结合在一起,这样就能既可以 继承 类中的 方法,也能继承构造函数中的属性了
// 父类
function Animal(name) {
this.name = name
}
Animal.prototype.showName = function () {
console.log('名字是:' + this.name);
};
// 子类
function Dog(name, color) {
Animal.call(this, name)
this.color = color
}
Dog.prototype = new Animal()
let dog3 = new Dog('小白', 'white')
console.log(dog3);
dog3.showName()
ES6 中的类
class 就是 原来 es5 中声明类的 一种语法糖,更好更方便的去定义类
class People {
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() {
console.log('名字:', this.name)
}
}
let p1 = new People('潜龙', 24);
console.log('p1', p1);
p1.showName()
类的继承
我们通过 extend 来继承父类, 构造函数中 通过 spuer() 方法 继承父类属性
class People {
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() {
console.log('名字:', this.name)
}
}
class Coder extends People{
constructor(name, age, company) {
super(name, age); // 将 父类中的 name 和 age 继承下来
this.company = company
}
showCompany() {
console.log('工作的公司:', this.company);
}
}
let c1 = new Coder('simpleSky12', 34, '慕课网');
console.log('c1', c1);
c1.showName();
c1.showCompany();
类中的 get 与 set 方法
class People {
constructor(name, age) {
this.name = name;
this.age = age;
this._sex = -1;
}
get sex() {
return this._sex;
}
set sex(val) {
this._sex = val;
}
showName() {
console.log('名字:', this.name)
}
}
let p1 = new People('潜龙', 24);
p1.sex = '男'
console.log(p1.sex);
这里使用 set() 以及和 sex 别名 _sex 相结合 是为了起到一个 避免死循环的出现
当我们不使用 _sex 当做 sex的别名的时候,就会出现死循环,因为 this.sex 等于是触发了 get方法,this.sex = ‘’’ 相当于触发了 set方法,所以就会导致死循环的出现,内存溢出
get() 与 set() 方法的优势 就是,我们在使用 get与set 方法的时候可以对其进行业务操作,这是我们在 构造函数中 使用 this.xxx = xxx 所达不到的效果,例如我们可以 对属性的设置 和获取 进行一次拦截
class People {
constructor(name, age) {
this.name = name;
this.age = age;
this._sex = -1
}
get sex() {
if (this._sex === 1) {
return 'male'
}else if (this._sex === 0) {
return 'female'
}
return 'error';
}
set sex(val) {
if (val === 0 || val === 1) {
this._sex = val
}
}
showName() {
console.log('名字:', this.name)
}
}
let p2 = new People('潜龙', 24);
console.log(p2.sex); // error
p2.sex = 1;
console.log(p2.sex); // male
一开始因为 没有使用 set() 方法去设置 _sex 属性的值,默认值是 -1, 所以返回的是 error
后面利用 set方法 设置了 _sex 为 1, 当我们调用get方法时,返回的就是 male
get 与 set 的继承
People 中定义的 get 与 set 方法可以看做是 顶层属性,是可以被子类继承的
class People {
constructor(name, age) {
this.name = name;
this.age = age;
this._sex = -1
}
get sex() {
if (this._sex === 1) {
return 'male'
}else if (this._sex === 0) {
return 'female'
}
return 'error';
}
set sex(val) {
if (val === 0 || val === 1) {
this._sex = val
}
}
}
class Coder extends People {
constructor(name, age) {
super(name, age);
}
}
let c2 = new Coder('simpleSky12', 34);
c2.sex = 1
console.log(c2.sex); // male
静态属性与静态方法
静态方法只能通过类名.的方式来调用
ES6 中 主要是通过 使用 关键字 static 来定义静态的属性 和 静态方法
静态方法
class Count{
static getCount() {
return 5
}
}
console.log(Count.getCount()) // 5
静态方法是否可以被继承
class Num extends Count{
}
console.log(Num.getCount()) // 5
静态方法支持继承
静态方法错误的调用
let count = new Count()
console.log(count.getCount())
let num = new Num();
console.log(num.getCount())
实例化后的对象是无法调用 类中定义的 静态方法
静态属性
可以在类中直接使用 static 定义 静态属性吗?
class Count {
static count = 5
}
console.log(Count.count) // 5
static 暂时还不能用来修饰 静态属性,
如何声明 静态属性?
定义方式和 ES5 相同
class Count {
}
Count.count = 66
console.log(Count.count) // 6