class基本语法
class Point{
constructor(x,y){
this.x=x;
this.y=y;
}
toString(){
return '('+this.x+','+this.y+')';
}
}
类的数据类型就是函数,类本身就指向构造函数,类的所有方法定义在prototype上.
Obejct.assign可以方便向类添加多个方法。
class Point{
constructor(){}
}
Object.assign(Point.protorype,{
toString(){},
toValue(){}
})
类的内部所定义的方法,都是不可枚举的。
constructor方法
必须new
类的实例
实例属性除非显示定义在其本身,否则都是定义咋原型上。
类的所有实例共享原型对象。
取值存值函数
class MyClass{
constructor(){
}
get prop(){
return 'getter';
}
set prop(value){
console.log('setter:'+value);
}
}
let inst = new MyClass();
inst.prop = 123;
inst.prop;
属性表达式
let methodName='getArea';
class Square{
constructor(length){
}
[methodName](){
}
}
class 表达式
const MyClass = class Me{
getClassName(){
return Me.name;
}
}
这个Me只能在内部,用不到可以省略
const MyClass = class{}
立即执行的Class
let person=new Class{
constructor(name){
this.name=name;
}
sayName(){
console.log(this.name);
}
}("xx");
person.sayName();
注意
严格模式,不存在提升,name属性,generator方法
class Point{}
Point.name
class Foo{
constructor(...args){
this.args=args;
}
*[Symbol.iterator](){
for(let arg of this.args){
yield arg;
}
}
}
for(let x of new Foo('hello', 'world')){
console.log(x);
}
//hello
//world
this指向,
class Logger{
printName(name='there'){
this.print(`hello ${name}`);
}
print(text){
console.log(text)
}
}
const logger = new Logger();
const { printName } = logger;
printName();//会报错 this会指向该方法运行时所在的环境
解决方法在构造函数中绑定this
class Logger{
constructor(){
this.printName = this.printName.bind(this);
}
}
另一种解决方法箭头函数
class Obj{
constructor(){
this.getThis = () = > this;
}
}
const myObj=new Obj();
myObj.getThis() === myObj;
!!!还有一种解决方法proxy
function selfish(target){
const cache=new WeakMap();
const handler={
get(target,key){
const value=Reflect.get(target,key);
if(typeof value !== 'function'){
return value;
}
if(!cache.has(value)){
cache.set(value,value.bind(target));
}
return cache.get(value);
}
};
const proxy=new Proxy(target,handler);
}
静态方法
所有类定义的方法被实例继承,加上static表示直接通过类调用。
class Foo{
static classMethod(){
return "hello";
}
}
Foo.classMethod()
var foo=new Foo();
foo.classMethod()//错误
如果静态方法包含this,this指的是类
class Foo{
static bar(){
this.baz();
}
static baz(){
console.log('hello');
}
baz(){
console.log('world');
}
}
Foo.baz();
子类可以调用父类的静态方法
class Foo{
static classMethod(){
return 'hello';
}
}
class Bar extends Foo{
}
Bar.classMethod()
静态方法也可以从super对象调用
class Foo{
static classMethod(){
return 'hello';
}
}
class Bar extends Foo{
static classMethod(){
return super.classMethod() + ',too';
}
}
Bar.classMethod()
实例属性新写法
原写法
class IncreasingCounter{
constructor(){
this._count=0;
}
get value(){
console.log('getting the current value');
return this._count;
}
increment(){
this._count++;
}
}
class IncreasingCounter{
_count=0;
get value(){
console.log('getting the current value');
return this._count;
}
increment(){
this._count++;
}
}
这种写法好处,比较整齐
静态属性
class本身的属性Class.propName
class Foo{
}
Foo.prop=1;
Foo.prop
目前只有这种可行,新的提案
class MyClass{
static myStaticProp=42;
constructor(){
console.log(MyClass.myStaticProp);
}
}
这个新写法大大方便静态属性的表达,测试了chrome可以用
class Foo{
}
Foo.prop=1;
新写法
class Foo{
static prop=1;
}
私有方法和私有属性
有利于代码封装,现有解决方案
//命名上区分
class Widget{
foo(baz){
this._bar(baz);
}
_bar(baz){
return this.snaf=baz;
}
}
_为只限于内部使用的私有方法,不保险,类的外部也可以调用
另一种移除模块,模块内部的所有方法都是对外可见的
class Widget{
foo(baz){
bar.call(this,baz);
}
}
function bar(baz){
return this.snaf=baz;
}
foo是公开的方法,内部调用bar.call(this,baz),使得bar称为当前模块私有方法。
还可以利用symbol唯一性,将私有方法的名字命名为一个Symbol
const bar=Symbol('bar');
const snaf=Symbol('snaf');
export default class myClass{
foo(baz){
this[bar](baz);
}
//私有方法提案
[bar](baz){
return this[snaf]=baz;
}
}
私有属性提案
//#号表示
class IncreasingCounter{
#count=0;
get value(){
console.log('geting the current value');
return this.#count;
}
increment(){
this.#count++;
}
}
在chrome也可以用,也可以用来写私有方法
class Foo{
#a;
#b;
constructor(a,b){
this.#a=a;
this.#b=b;
}
#sum(){
return #a + #b;
}
printSum(){
console.log(this.#sum());
}
}
不能用 也可以设置getset,
私有属性不限于this引用,只要是在内部,实例也可以引用思域属性
class Foo{
#privateValue=42;
static getPrivateValue(foo){
return foo.#privateValue;
}
}
Foo.getPrivateValue(new Foo());
私有属性和方法也可以加static关键字
class FakeMath{
static PI=22/7;
static #totallyRandomNumber=4;
static #computeRandomNumber(){
return FakeMath.#totallyRandomNumber;
}
static random(){
console.log('I heard you like random numbers.')
return FakeMath.#computeRandomNumber();
}
}
FakeMath.PI
FakeMath.random()
new.target属性
返回new命令作用的那个构造函数,如果构造函数不是通过new或者Reflect.construct()调用
function Person(name){
if(new.target !== undefined){
this.name = name;
}else {
throw new Error("必须使用new生成实例");
}
}
//另一种写法
function Person(name){
if(new.target ===Person){
this.name = name;
}else {
throw new Error('必须new');
}
}
var Person= new Person('1');
function person(){}
var notAPerson = Person.call(person,'xx');
Class内部调用new.target 返回class
class Rectangle{
constructor(length,width){
console.log(new.target === Rectangle);
this.length=length;
this.width=width;
}
}
var obj=new Rectangle(3,4);
需要注意,子类继承父类时,new.target返回子类
class Rectangle{
constructor(length,width){
console.log(new.target === Rectangle);
}
}
class Square extends Rectangle{
constructor(length){
super(length,width);
}
}
var obj=new Square(3);
上述代码new.target返回子类,利用这个特点,可以写出不能独立使用,必须继承后使用的类
class Shape{
constructor(){
if(new.target === Shape){
throw new Error('本类不能实例化')
}
}
}
class Rectangle extends Shape{
constructor(length,width){
super();
}
}
var x=new Shape();
var y=new Rectangle(3,5);