es6 class
类 class
对象是由属性和方法组成的:属性:事物的特征,在对象中用属性来表示(常用名词)、方法:事物的行为,在对象中用方法来表示(常用动词);
类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象;
面向对象的思维特点:抽取(抽象)对象共用的属性和行为 组织(封装)成一个类(模板)对类进行实例化, 获取类的对象。暂且把class理解为一个模板;
类声明不会被提升,这与函数定义不同。类声明的行为与 let 相似
es5 中类通过原型来实现
function Pa(x,y){
//构造函数中写属性
this.x=x;
this.y=y;
}
//原型上写 公共属性或方法
Pa.prototype.say=function(){
console.log(this.x);
}
//new 一个实例 实例就会有原型上的方法 和构造函数中的属性
let p=new Pa("a",2);
p.say(); // a
es6中跟es5 原理是一样的只是写法不同而已,es5 构造函数和原型对象分开写,es6 是全部写到class中
class Pa{
//constructor 就是es5中的构造函数
constructor(x, y) {
this.x = x;
this.y = y;
}
//不需要分割符,直接写 原型方法
say() {
console.log(this.x);
}
}
let p=new Pa("a",2);
p.say(); //a
console.log(Pa == Pa.prototype.constructor); //true
//Pa 就是那个构造函数
class Pa {}
// 等同于
class Pa {
constructor() {}
}
class 的属性和方法
公有的属性和方法: 即每一个实例对象又能访问的属性和方法, 只有公有属性才会遍历出来
class PP {
constructor () {
this.a = 1
}
p = 2 // 与 constructor是一样的效果
say () { console.log(this) }
}
let p = new PP()
p.a = 5
console.log(p) // {p: 2, a: 5}
let p1 = new PP()
console.log(p1)// {p: 2, a: 1} 每一个实例互不影响
p1.say() // 返回实例对象 {p: 2, a: 1}
私有的属性和方法: 只能通过类名进行访问的 私有的属性 通过添加 static 表示 😭 ES6 明确规定,Class 内部只有静态方法,没有静态属性。静态属性只有提案,但是目前babel都支持静态属性。以下代码经babel编译后,静态属性正常使用。)
class PP {
static sing () {}
static size = 10 // 只是提案。
}
let p = PP.initPP()
console.log(PP.size) // 10
也有说通过Symbol 来实现私有属性,但这是有疑问的。
Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
class this的指向
constructor 里面的this指向实例对象,方法里面的this 指向这个方法的调用者, 在单例模式中 通过类名来执行静态属性;
实例对象上的不是静态属性不能通过类名来调用 单例中的 this.instance 就可以理解为 是class 的静态属性;
在类的内部 是可以通过 类名来访问到类的,公有私有方法都可以;
class PP {
constructor () {
this.a = 1
}
p = 2 // 与 constructor是一样的效果
static initPP () {
console.log(this.p) // undefined 实例对象上的不是静态属性不能通过类名来调用
console.log(this.a) // undefined
console.log(this.instance) // 第一次undefined 第二次会返回实例对象
console.log(this.sing) // function.. 只是静态属性 才能通过类对象来调用
console.log(this.say) // undefined
//通过类名来访问到类的
if (!this.instance) this.instance = new PP()
return this.instance
}
static sing () { console.log(this) }
say () { console.log(this) }
}
let p1 = PP.initPP()
PP.sing() // 返回类本身 PP{...}
p1.say() // 返回实例对象 {p: 2, a: 1}
class 的继承 extends
子类必须在 constructor 方法中调用super方法,否则新建实例时会报错。
class A{
constructor(x) { this.x=x }
say(){ console.log(this.x)}
}
let a=new A(6);
a.say();//6
// B继承A
class B extends A{
constructor(x,y){//B 自己的构造函数 构造函数通过new 会生成实例
super(x,y);
//super(x),代表调用A的构造函数constructor(x)。 但是返回的是子类B的实例
//super()在这里相当于A.prototype.constructor.call(this)。 this指的是B, 即:相当于把A的constructor给执行了,并且让方法中的this是B的实例,
//super 之后才能使用this
this.y=y; //B自己的属性
}
}
let b=new B(5,9);
b.say(); //5
console.log(b.y)//9
继承的默认写法
class B extends A { }
// 等同于
class B extends A{
constructor(...args) {
super(...args);
}
}
super 关键字
既可以当作函数使用,也可以当作对象使用
- 做函数:只能在子类的构造函数之中当作函数使用,代表父类的构造函数;
- 做对象:super在constructor中指向父类的原型对象,super在普通方法之中指向父类的原型对象。super在静态方法之中指向父类,可调用父类的静态方法;
class A {
constructor() {
//实例的方法 是可遍历的
this.x=function(){
return 1;
};
}
num = 123
//原型上的方法
p() {
return 2;
}
}
class B extends A {
constructor() {
// 当作函数使用
super();
// 当作对象使用
console.log(super.num) // undefined 跟constructor一样
console.log(super.p()); // 2 P是方法,在原型对象上
console.log(super.x()); // x is not a function
//A.prototype 的原型上没有x方法 就找不到
//super 是指向 A.prototype的
}
}
let b = new B();
class A {
static say(){ cconsole.log("132") }
}
class B extends A {
kk(){
super.say(); //super 没有这个say方法
//作为对象 super在普通方法之中指向父类的原型对象。
}
static gg(){
super.say(); //132
//作为对象 super在静态方法之中指向父类
}
}
b.kk(); //kk .say is not a function
B.gg(); //静态方法 所以用B 调用