在原先的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 Myclass=class{
x=12;
static y=0;
getX=()=>{
console.log(this.x)
}
static getY=()=>{
console.log(this.y)
}
}
console.log(new Myclass().x);
console.log(Myclass.y);
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身上加的,前面加上static关键字,静态属性只存在class本身上,不在class实例上
let Person = class{
constructor(){
this.y=0;
}
static z=10
}
Person.x=12;
console.log(Person.x);//12
console.log(Person.z);//10
console.log(new Person().y);//0
class的私有属性和方法
- 私有属性或者方法前面必须加上
#
号,就代表是私有的 - 只能在
class
里访问,在class
外访问不了 - 公共属性或者方法可以跟私有的属性或者方法重名
- 在私有的方法里
this
代表的是实例,不是class
let Person = class{
age=9
#age=18
#getAge=()=>{
return this.#age // 18
}
getAge=()=>{
// 在class内部可以调用私有属性或者方法
return this.#age
}
}
const p = new Person()
// 在class外部不可以调用私有属性或者方法,所以会报错
p.#age=12;// 报错 Private field '#age' must be declared in an enclosing class
console.log(p.getAge())// 18
class的私有静态属性和方法
- 私有静态属性或者方法
static
后面必须加上#
号,就代表是私有的 - 只能在class里访问,在class外访问不了
- 公共属性或者方法可以跟私有的属性或者方法重名
- 在私有静态的方法里
this
代表的是class
,不是实例
let Person = class{
static #age=1
static #getAge=()=>{
return this.#age
}
static getAgeFn=()=>{
// 在class内部可以调用私有静态属性或者方法
this.#getAge()
return this.#age
}
}
console.log(Person.getAge()) // 报错,因为是私有的,必须在class内部使用
// Private field '#getAge' must be declared in an enclosing class
console.log(Person.getAgeFn()) // 1
class 类静态块
想要在class
里有try...catch
一样有异常处理,就得在class
里写此逻辑,但是直接写的话会报错,所以得用静态块包起来,就可以写了,其中可以访问静态属性(或方法)或者静态私有属性(或方法),访问不了公共的属性和方法,也访问不了私有的属性和方法,因为this
是class
本身,不是class
实例
class Person{
name="张三"
static error="error"
static {
try{
console.log(this.name) // Person
console.log(this.error) // error
}catch(e){
}
}
}
in 判断某个对象是否拥有某个私有属性或者静态私有属性
通过in
操作符来判断这个属性有没有在这个对象上
下面是判断私有属性有没有在class
实例上
class myClass {
name="张三"
#age=18
getName = ()=>{
console.log(#age in this) // true
return this.name
}
}
const my=new myClass()
my.getName()
下面是判断静态私有属性有没有在class
对象上
class countClass{
static #count=10
static getCount=()=>{
console.log(#count in countClass) // true
return countClass.count
}
}
countClass.getCount()
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就介绍这么多,希望对你有所帮助