ES6 class 类的理解(一)
ES6 的类提供了几点明显的好处:
兼容当前大量的代码。
相对于构造器和构造器继承,类使初学者更容易入门。
子类化在语言层面支持。
可以子类化内置的构造器。
不再需要继承库;框架之间的代码变得更加轻便。
为将来的高级特性奠定了基础: traits (或者 mixins ), 不可变实例,等等。
使工具能够静态分析代码( IDE ,类型检测器,代码风格检测器,等等)。
ES6 类掩盖了 JavaScript 继承的本质;
类会禁锢你,因为强制性的 new。
function Point(x, y){ this.x = x; this.y = y;}Point.prototype.toString = function(){ return "(" + this.x + "," + this.y + ")";}const p = new Point(1,2);console.log(p);//Point {x: 1, y: 2}console.log(p.toString());//(1,2)
ES6的class写法就相当于语法糖
上面代码的改用class来写
class Points { constructor(x, y) { this.x = x; this.y = y; } toString(){ return '(' + this.x + ',' + this.y + ')'; }}const ps = new Points(1, 2);console.log(ps);//Points {x: 1, y: 2}console.log(ps.toString());//(1,2)
ES6的类可以看作构造函数的另一种写法
class Cty{ //....}console.log(typeof Cty);//functionconsole.log(Cty === Cty.prototype.constructor);//true//类的数据类型是函数,类本身就指向构造函数
使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致
class Bar { doStuff(){ console.log('stuff'); }}const b =new Bar();b.doStuff();//stuff
类的实例上面的方法,其实就是调用原型上的方法
class B {};const BS = new B();console.log(BS.constructor === B.prototype.constructor);//true
类与子类
class Poin{ constructor(x,y){ this.x = x; this.y = y; } toString(){ return `(${this.x},${this.y})`; }}class ColorPoin extends Poin{ constructor(x,y,color){ super(x,y); this.color = color; } toString(){ return super.toString() + " in " + this. color; }}// 类型console.log(typeof Poin);//function//news实例const cp = new ColorPoin(25,8,'green');console.log(cp.toString());//(25,8) in greenconsole.log(cp instanceof ColorPoin);//trueconsole.log(cp instanceof Poin);//true// instanceof测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
下面是一些方法:
Object.assign方法可以很方便的一次像类添加多个方法class ObjAssign { constructor(name, age){ this.name = name; this.age = age; }}Object.assign(ObjAssign.prototype,{ toString(){ console.log("string"); }, toValue(){ console.log("value") }})const Obj = new ObjAssign('Bob',24);console.log(Obj);Obj.toString();//stringObj.toValue();//valueconsole.log(Object.keys(ObjAssign.prototype));//["toString", "toValue"]console.log(Object.getOwnPropertyNames(ObjAssign.prototype));// ["constructor", "toString", "toValue"]
类的实例
class Pott { constructor(x,y){ this.x = x; this.y = y; } toString() { return '(' + this.x + ',' + this.y + ')'; }}const pott = new Pott(2,3);pott.toString();console.log(pott.hasOwnProperty("x"));//trueconsole.log(pott.hasOwnProperty("y"));//trueconsole.log(pott.hasOwnProperty("toString"));//falseconsole.log(pott);console.log(pott.__proto__);console.log(pott.__proto__.hasOwnProperty("toString"));//trueconst p1 = new Pott(2,3);const p2 = new Pott(3,3);console.log(p1.__proto__ === p2.__proto__);//truep1.__proto__.printName = function(){ return "Oops";}console.log(p1.printName());//Oopsconsole.log(p2.printName());//Oopsconst p3 = new Pott(4,2);console.log(p3.printName());//Oops
取值函数(getter)和存值函数(setter)
prop属性有对应的存值函数和取值函数
class MyClass { constructor(){ //... } get prop(){ return 'getter'; } set prop(value){ console.log("setter:" + value); }}const inst = new MyClass();inst.prop = 123;//setter: 123console.log(inst.prop)//getter
存值函数和取值函数是设置在属性的Descriptor对象上的
class CustomHTMLElement { constructor(element) { this.element = element; } get html() { return this.element.innerHTML; } set html(value) { this.element.innerHTML = value; }}const descriptor = Object.getOwnPropertyDescriptor( CustomHTMLElement.prototype, "html");console.log("get" in descriptor) // trueconsole.log("set" in descriptor) // true
calss 表达式
const MyCl = class Me { getClassName() { return Me.name; }}const inMe = new MyCl();console.log(inMe.getClassName());//Me 只在class内部有定义
person立即执行实例
const person = new class{ constructor(name){ this.name = name; } sayName(){ console.log(this.name); }}('张三');person.sayName();//张三
class name 属性
class Mine {//...}console.log(Mine.name);//Mine
class this的指向问题
this.printName = this.printName.bind(this)绑定解决
class Logger{ constructor(){ this.printName = this.printName.bind(this); } printName(name = 'there'){ this.print(`Hello ${name}`); } print(text){ console.log(text); }}const logger = new Logger();const {printName} = logger;printName();//Hello there
静态方法static
如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是通过类来调用
class Foo{ static classMethod() { return 'hello'; }}console.log(Foo.classMethod());//Helloconst foo = new Foo();// console.log(foo.classMethod())//foo.classMethod is not a function
class Fun { static bar(){ this.baz(); } static baz(){ console.log('hello'); } baz(){ console.log('world'); }}Fun.bar();//hello
父类静态方法可以被子类调用
class Func{ static classMethod() { return 'hello'; }}class Baa extends Func{ static classMethod(){ console.log(super.classMethod + ",too") ; }}Baa.classMethod();//hello,too
实例属性的新写法
class IncreasingCounter{ // constructor(){ // this._count = 0; // } _count = 0; get value(){ console.log('getting the current value'); return this._count; } increment(){ this._count++; }}
new.target属性
确保函数只能通过new命令调用
function PersonMan(name){ if(new.target !== undefined){ this.name = name; }else{ throw new Error('必须使用new命令生成实例') }}function PersonWoman(name){ if(new.target === PersonWoman){ this.name = name; }else{ throw new Error('必须使用new命令生成实例') }}const personman = new PersonMan('张三');const personwoman = new PersonWoman('张三');// const personwoman2 = PersonWoman.call(PersonWoman,'张三');//报错
内部调用new.target会返回当前的class
class Rectangle{ constructor(length,width){ console.log(new.target); console.log(new.target===Rectangle); this.length = length; this.width = width; }}const rectangle = new Rectangle(3,4);
子类继承父类时,new.target会返回子类
class Rec{ constructor(length,width){ console.log(new.target); console.log(new.target===Rectangle); console.log(new.target===Square); this.length = length; this.width = width; //... }}class Square extends Rec{ constructor(length,width){ super(length,width); }}const squareA = new Square(3,6);//false/true
参考文章
探索ES6
ES6阮一峰
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。