深入class类

引言:
JavaScript当中并没有构造函数的概念,只是我们为了方便区分,就人为的约定了方法名首字母大写的为构造函数。
在ES6之前,如果写一个构造函数像下面这样:

function Person1(name,age){
	this.name = name;
	this.age = age;
	this.show = function(){
		console.log(this.name,this.age);
	}
}
或者标准的写法是:把属性写在构造函数里,把方法写在原型链里,如下:
function Person2(name,age){
	this.name = name;
	this.age = age;
}
Person.prototype.show = function(){
		console.log(this.name,this.age);
}

在ES6当中,引入了类(class)的概念,使用class写上面的代码如下:

class Person{
	constructor(name,age){    //构造函数
		this.name = name;
		this.age = age;
	}
	show = function(){
			console.log(this.name,this.age);
		}
}

首先,使用class声明的Person:typeof(Person); // function
并且var p = new Person(); Person.prototype.show == p.show; // true 说明class上的方法都是写在原型链上的!

接着,看一下构造函数constructor直接:

class A{}
var a = new A();

是能够直接运行的!说明内部帮我们写了一个构造函数,只不过是空的:constructor(){}

ES6之前,函数可以这样写:var show = function(){},我们称之为函数表达式;
ES6同样为我们提供了类表达式const Person = class{}

ES6之前有立即执行函数:(funcrion(){})()
ES6也同样提供了立即执行类var p = new class{}

虽然上面说了typeof(Person); // function,class是一个类,但class并不支持变量提升,必须先定义,在使用。

一、class的基本使用

  1. constructor、实例属性、实例方法
    在constructor内定义的就是实例属性,如constructor(name){ this.name = "xm"; }
    除constructor之外的函数。
  2. this指向
class Person {
	constructor(){
		this.name = "xm";
	}
	show(){
		this.print(`my name is ${this.name}`);
	}
	print(data){
		console.log(data);
	}
}
var p = new Person();

此时p具有show()和print()这两个方法,并且p是一个对象(typeof p == "object"),那么,对p进行解构赋值:

var {show : show } = p;
//   此时,执行p.show()与show(): 
p.show();  // my name is xm
show();    //报错,print undefined   此处show是单独执行,并没有被调用,所以不指向p

当我们把constructor改写为如下时:

//    方法1
constructor(){
	this.name = ""xm;
	this.show = this.show.bind(this);
}
在执行:
var {show : show } = p;
p.show();  // my name is xm
show();    // my name is xm

why???

来分析一下新增的那句this.show = this.show.bind(this);,我们知道,谁调用this就指向谁:此时,后面的this.show指的就是show方法,然后又使用bind()将show方法内部的this改变了指向!

//   方法2   利用箭头函数改写
constructor(){
	this.name = ""xm;
	this.show = () => this.print(`my name is ${this.name}`);
}
同样的在执行:
var {show : show } = p;
p.show();  // my name is xm
show();    // my name is xm

这是因为箭头函数里this指向它所在的父级对象的作用域!
constructor是一个函数,具有独立的作用域,内部箭头函数的this指向的是constructor的父级person,而p是person的实例,所以指向p

举例:
var name ="window";
bar obj = { 
	name : "obj" ,
	show :() => { console.log(this.name); };
};
//   执行:
obj.show();    // window
  1. 静态属性、静态方法 (关键字static)
class A{
	static fn(){        //静态方法
		console.log("aaa");
	}
	//   静态属性规定了在这个位置写,static abc = 123,但浏览器并没有实现
}
A.fn();           //    aaa
A.abc = 123;      //    但可以通过这种方法添加
A.abc;           //    123

二、class的继承

  1. extends
    ES6之前的继承:
function A(){}
var a = new A();
那么,a.__proto__ == A.prototype   // true

ES6的继承:

class A {
	construtor(){ this.name = "xm"; }
	print(){ console.log(this.name); }
}
class B extends A{
	construtor(){ 
		super();          //  子类要先调用super()才能使用this,因为子类没有this   默认调用父级的构造函数
		this.name = "B";	
	}
}
var b = new B();
b.print();    //   B

  1. super 详解
    通过super()调用父类的构造函数,把this绑定到自己身上。
    super()当函数使用,就相当于父级的构造函数执行。
    super()当对象使用,在父类写:print(){ console.log("A") }在子类里写:print(){ super.print(); },执行b.print(); // A,此时值的是父类的原型对象。但如果在子类写为:print(){ super.name; },执行:b.print() // undefined,而父类的print方法是在原型链上的,但name不在,说明super当作对象时,只能访问父类原型链上定义的方法
    接下来:
class A {
	construtor( name = "deng" ){ this.name = "xm"; }
	print(){ console.log(this.name); }
}
A.prototype.name = "Father name";
class B extends A{
	construtor(name){ 
		super(name);          
	}
	print(){ 
		super.print();
	}
}
var b = new B("xdend");
b.print();    //   xdend    说明super绑定了子类的this

刚才说了:function A(){}; var a = new A();,有这样的关系:a.__proto__ == A.prototype // true
那么在ES6当中,有些不同:

class A{}
class B extends A{}
//字类的__proto__表示构造函数的继承
B.__proto == A;    // true
//字类的__proto__.prototype表示方法的继承
B.__proto__.prototype  == A.prototype ;    // true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值