在原先的js上生成实例是通过构造函数和原型结合,一个简单的例子
function Person(name,age){
this.name=name;
this.age=age;
};
Person.prototype.getName=function (){
return this.name;
};
Person.prototype.getAge=function (){
return this.age;
};
var p=new Person("张三",15);
console.log(p.getName());//张三
console.log(p.constructor === Person);//true
console.log(p instanceof Person);//true
es6的class生成的实例对象
class Person{
constructor(name,age){
this.name=name;
this.age=age;
}
getName(){
return this.name;
}
getAge(){
return this.age;
}
}
let p1=new Person("张三",15);
let p2=new Person("李四",17);
console.log(p1.getName());//张三
console.log(p1.constructor === Person);//true 类本身就指向构造函数。
console.log(p1 instanceof Person);//true
console.log(p1.prototype===p2.prototype);//true 因为原型相等,所以可以为其中一个实例添加方法,另外的实例也就有了这个方法
上面的例子中注意一下几个点
- 如果不写constructor,class会默认加个constructor
- class里函数与函数之间不用写逗号
- 类里面的所有函数都定义在类的prototype上
class表达式
let Person=class Bodys{
constructor(name,age){
this.name=name;
this.age=age;
}
getClassName(){
return Bodys.name;
}
getAge(){
return Bodys.age;
}
getName(){
return this.name;
}
}
let p=new Person("王五",13);
console.log(p.getClassName());//Bodys
console.log(p.getName());//王五
- 注意上面的bodys只是个class名字而已,只能在class内部用,真正的构造函数名字还是Person
- class和let一样,不存在变量提升
如果用不到这个bodys,是可以不写的
{
let Person=class{
/*..... */
}
}
用表达式可以立即执行,如下
{
let Person=new class{
/*..... */
}
}
class里的this指向 类内部的this默认指向类的实例
let Person=class{
getThis(){
console.log(this);
}
}
let p=new Person();
p.getThis();//this 就是Person这个实例
let {getThis}=p;
getThis.call(this);//window
getThis();//undefinde
上面三种调用方法有三种结果,不稳定,如果我们就想要这个this指向类的实例,一个简单的方法,就是在constructor绑定this,或者用箭头函数
let Person=class{
constructor (){
this.getThis=this.getThis.bind(this);
}
getThis(){
console.log(this);
}
}
let p=new Person();
p.getThis();//this 就是Person这个实例
let {getThis}=p;
getThis.call(this);//this 就是Person这个实例
getThis();//this 就是Person这个实例
箭头函数,因为箭头函数里面的this永远都是外层的this,没有自己的this,可以很好的利用这个特性
let Person=class{
constructor (){
this.getThis=()=>{
console.log(this);
};
}
}
let p=new Person();
p.getThis();//this 就是Person这个实例
let {getThis}=p;
getThis.call(this);//this 就是Person这个实例
getThis();//this 就是Person这个实例
class的取值函数和设置函数,可以用来在class的属性设置或者取值的过程中做一些处理
class Person{
set prop(val){
console.log("处理一下"+val+"逻辑");
}
get prop(){
console.log("处理一下逻辑");
return "getVal";
}
}
let p=new Person();
p.prop="张三";//处理一下张三逻辑
console.log(p.prop);//getVal
class的静态方法
- 静态方法就是在class里的方法前加上“static”关键字就行了
- 静态方法只能通过类来调用,而且可以跟class实例的方法重名,并不影响.而且static里面的this指的是class,并不是实例
let Person=class{
static getName(){
this.getAge();//classAge
console.log("ClassName");
}
static getAge(){
console.log("classAge");
return "Person:classAge";
}
getName(){
console.log("name");
}
getAge(){
console.log("age");
}
}
const p=new Person();
p.getName();//name
Person.getName();//ClassName
//继承
//子类可以继承父类的静态方法,也可以在super上调用
class Son extends Person{
static superAge(){
console.log("super+"+super.getAge());
}
}
Son.getName();//className
Son.superAge();//super+Person:classAge
class的静态属性和实例属性
类的静态属性是直接在class身上加的,目前而言,es6规定,class内部只有静态方法,没有静态属性,实例属性只能定义在constructor里
let Person = class{
constructor(){
this.y=0;
}
}
Person.x=12;
console.log(Person.x);//12
console.log(new Person().y);//0
现在有个提案,就是直接在class里定义静态属性,和属性
let Myclass=class{
x=12;
static y=0;
}
console.log(new Myclass().x);
console.log(Myclass.y);
class 的new.target的属性
new.target这个属性一般在构造函数里,这个值就是当前的class,不过子类继承的时候值是子类的class,可以利用这个特性来写一个只有被子类继承的时候才能用的class
class Person{
constructor(name,age){
if (new.target===Person){
throw new Error("必须子类继承才能实例");
}else{
this.name=name;
this.age=age;
}
}
}
class Son extends Person{
constructor(name,age,job){
super(name,age);
this.job=job;
}
}
//let p=new Person("张三",18);//报错 必须子类继承才能实例
let s=new Son("李四",12,"IT");
console.log(s.name);//李四
class的继承
class Person{
constructor(name,age){
this.name=name;
this.age=age;
this.x=1;
}
getName(){
console.log(this.name);
return this.name;
}
static getName(){
return "static+"+this.name;
}
}
class Son extends Person{
constructor(name,age,job){
super(name,age);
this.job=job;
this.x=2;
super.x=3;
console.log(super.x);//undefined
console.log(this.x);//3
}
getName(){
console.log(this.job+"--"+super.getName());//IT--李四
}
getAge(){
console.log(super.age);//undefined
}
static getName(){
console.log(super.getName());//static+Son
}
}
let p=new Person("张三",18);
let s=new Son("李四",12,"IT");
console.log(s.name);//李四
console.log(s instanceof Person);//true
console.log(s instanceof Son);//true
s.getName();
s.getAge();
Son.getName();
类的继承super关键字的几个注意点
- super函数只能在constructor里用,并且必须写在第一句,否则会报错
- 如果继承后不写constructor,会自动加上constructor并且加上super(...args)这句代码
- super函数相当于是Person.prototype.constructor.call(this),虽然代表的是父类,但是返回是子类,new.target可以证明
- super作为对象时,是指向父类的原型对象,是拿不到父类构造函数里的属性或者方法,只能取原型上的 Son里的getAge可以说明
- es6规定,通过super调用父类的方法时,方法内部的this指向子类 Son通过调用父类的getName可以说明
- 如果通过super对某个属性赋值,这时的this就是super,指向子类,赋值的属性就变成子类实例的属性。如果通过super对某个属性取值时,super代表的是父类的原型对象 Son实例的this.x可以证明
- super在static静态方法中指向父类,而不是父类的原型对象
Object.getPrototypeOf(子类)可以查找父类
类的prototype和proto属性
- 子类的proto属性,表示构造函数的继承,总是指向父类。
- 子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
class A{
}
class B extends A{
}
console.log(A.prototype);
console.log(A===B.__proto__);//true
console.log(A.prototype===B.prototype.__proto__);//true
//内部就是子类继承父类的实例和属性
Object.setPrototypeOf(B,A);
Object.setPrototypeOf(B.prototype,A.prototype);
setPrototypeOf的实现
Object.setPrototype=(obj,proto)=>{
obj.__proto__=proto;
return obj;
}
原生构造函数的继承,大概有这些Boolean()、Number()、String()、Array()、Date()、Function()、RegExp()、Error()、Object()
es6以前是无法继承原声构造函数的,因为拿不到父类的属性,但是es6是可以的
class newArr extends Array{
}
let arr=new newArr;
arr.push(12);
console.log(arr[0]);//12
console.log(arr.length);//1
关于class就介绍这么多,希望对你有所帮助,如果想看更详细的资料,请狠狠的点击我
网友评论