当前位置: 首页 > Web前端 > JavaScript

JavaScript中的前端类

时间:2023-03-27 13:18:04 JavaScript

类类是创建对象的模板。JavaScript中生成对象实例的方法是通过构造函数,在写法上与主流的面向对象语言(java、C#)有很大区别,如下:functionPoint(x,y){this.x=x;this.y=y;}Point.prototype.toString=function(){return'('+this.x+','+this.y+')';};varp=newPoint(1,1);ES6提供了更接近Java的语言,引入了Class(类)的概念作为对象的模板。使用class关键字,可以定义一个类。如下:constructor()为构造方法,this代表实例对象:classPoint{constructor(x,y){this.x=x;这个.y=y;}toString(){返回'('+this.x+','+this.y+')';}}该类的数据类型是一个函数,它本身就是一个指向函数的构造函数://ES5函数声明functionPoint(){//...}//ES6类声明classPoint{//....constructor(){}}typeofPoint//"function"Point===Point.prototype.constructor//true类中定义的方法链接到Point.prototype,所以类只提供语法糖,而本质还是原型链调用。classPoint{constructor(x,y){this.x=x;这个.y=y;}toString(){返回'('+this.x+','+this.y+')';}}Point.prototype={//....toString()}varp=newPoint(1,1);p.toString()//另一种定义(1,1)类Class表达式的方法//未命名/匿名类letPoint=class{constructor(x,y){this.x=x;这个.y=y;}};Point.name//Point函数声明和类声明有一个重要区别,函数声明会被提升,类声明不会被提升。让p=新点();//提升时不会报错functionPoint(){}letp=newPoint();//会报错,ReferenceErrorclass指向{}constructor()constructor()方法是类的默认方法,new创建实例对象时会自动调用该方法。一个类必须有一个constructor()方法,如果没有显式定义,引擎会默认添加一个空的constructor()。constructor()方法默认返回实例对象(即this)。classPoint{}//自动添加classPoint{constructor(){}}getter和setter与ES5相同,可以在类内部使用get和set关键字为属性设置存储函数和取值函数,以及intercept该属性的访问行为。类用户{构造函数(名称){this.name=name;}getname(){返回this.name;}设置名称(值){this.name=value;}}this在本类的方法里面,它默认指向类的实例,用this调用方法时,需要使用obj.method()方法,否则会报错。类用户{构造函数(名称){this.name=name;}printName(){console.log('Nameis'+this.name)}}constuser=newUser('jack')user.printName()//名字是jackconst{printName}=user;printName()//ErrorCannotreadpropertiesofundefined(reading'name')如果想单独调用不报错,一个方法可以在构造函数中调用bind(this)。类用户{构造函数(名称){this.name=name;this.printName=this.printName.bind(this);}printName(){console.log('Nameis'+this.name)}}constuser=newUser('jack')const{printName}=user;printName()//Nameisjackbind(this)将创建一个新函数,并在调用该函数时使用this作为上下文点。另外,可以使用箭头函数,因为箭头函数里面的this总是指向定义它的对象。类用户{构造函数(名称){this.name=name;}printName=()=>{console.log('Nameis'+this.name)}}constuser=newUser('jack')const{printName}=user;printName()//Nameisjack静态属性静态属性是指类本身的属性,而不是定义在实例对象this上的属性。classUser{}User.prop=1;User.prop//1静态方法你可以在一个类中定义一个静态方法。该方法不会被对象实例继承,而是通过类直接调用。在静态方法中使用this是指类。classUtils{staticprintInfo(){this.info();}staticinfo(){console.log('你好');}}Utils.printInfo()//hello对方法的调用范围限制,例如:privatepublic,ES6暂时没有提供,一般是约定好的,例如:在方法前加下划线_print()表示私有方法。继承在Java中通过extends实现类的继承。ES6中的类也可以通过extends实现继承。继承时,子类必须在构造方法中调用super方法,否则新建实例时会报错。类Point3D扩展点{构造函数(x,y,z){super(x,y);//调用父类的构造函数(x,y)this.z=z;}toString(){返回super.toString()+''+this.z;//调用父类的toString()}}父类的静态方法也会被子类继承。父类{staticinfo(){console.log('helloworld');}}classChildextendsParent{}Child.info()//helloworldsuper关键字必须在子类的构造函数中执行一次super函数,它代表父类的构造函数。父类{}子类扩展父类{构造函数(){超级();}}在子类的普通方法中通过super调用父类的方法时,方法内部的this指向当前子类实例。类Parent{constructor(){this.x=1;this.y=10}printParent(){console.log(this.y);}print(){console.log(this.x);}}classChildextendsParent{constructor(){super();这个.x=2;}m(){super.print();}}letc=newChild();c.printParent()//10c.m()//2_proto_和prototype第一次学习JavaScript时,_proto_和prototype很容易混淆。首先,我们知道每个JS对象对应一个原型对象,并继承原型对象的属性和方法。原型是一些内置对象和函数的属性。它是一个指向对象的指针,该对象的目的是包含所有实例共享的属性和方法(我们称这个对象为原型对象)。_proto_每个对象都有这个属性,一般指向对应构造函数的prototype属性。下图显示了一些带有原型的内置对象。根据上面的描述,看下面的代码varobj={}//等同于varobj=newObject()//obj.__proto__指向Object构造函数的原型obj.__proto__===Object.prototype//真//对象。toString调用方法继承自Object.prototypeobj.toString===obj.__proto__.toString//true//arrayvararr=[]arr.__proto__===Array.prototype//true对于函数对象,每个声明的Function具有原型和__proto__属性。创建的对象属性__proto__指向函数原型,函数的__proto__指向内置函数对象(Function)的原型。函数Foo(){}varf=newFoo();f.__proto__===Foo.prototype//trueFoo.__proto__===Function.prototype//true继承中的__proto__类作为构造函数的语法糖,也会同时拥有prototype属性和__proto__属性,所以同时存在两条继承链。子类的__proto__属性表示继承构造函数,始终指向父类。子类的prototype属性的__proto__属性表示方法的继承,始终指向父类的prototype属性。classParent{}classChildextendsParent{}Child.__proto__===Parent//trueChild.prototype.__proto__===Parent.prototype//true继承实例中__proto__子类实例的__proto__属性,指向原型的子类构造函数。子类实例的__proto__属性的__proto__属性指向父类实例的__proto__属性。也就是说,子类的原型的原型就是父类的原型。classParent{}classChildextendsParent{}varp=newParent();varc=newChild();c.__proto__===p.__proto__//falsesec.__proto__===Child.prototype//truec。__proto__.__proto__===p.__proto__//true总结JavaScript中的Class更多的是语法糖,本质上绕不开原型链。欢迎留言交流。