Skip to main content
 首页 » 编程设计

Javascript面向对象之Class

2022年07月19日124xxx_UU

Javascript面向对象(八)——Class

类结构允许使用简洁、漂亮的方式定义基于原型的类模式。

class语法

类的语法有多种形式,我们从简单的开始。
这里是基于原型的类User:

function User(name) { 
  this.name = name; 
} 
 
User.prototype.sayHi = function() { 
  alert(this.name); 
} 
 
let user = new User("John"); 
user.sayHi(); 

然后,我们同样使用类的语法:

class User { 
 
  constructor(name) { 
    this.name = name; 
  } 
 
  sayHi() { 
    alert(this.name); 
  } 
 
} 
 
let user = new User("John"); 
user.sayHi(); 

很容易看到两个示例相似。那么class到底做了什么?我们可能认为这定义了新语言级的实体,但并非如此。
class User {…}确切地说做了两件事:
1、声明了变量User,其引用constructor函数。
2、把定义的方法放入User.prototype,这里包括sayHi和constructor。

下面这段代码进行检测:
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}

// proof: User is the "constructor" function 
alert(User == User.prototype.constructor); // true 
 
// proof: there are two methods in its "prototype" 
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi 

User类的图示如下:

所以class是定义构造函数和原型方法的特定语法。但不仅如此,有一些差别用来确保用法正确。
举例,constructor不能不使用new调用:

class User { 
  constructor() {} 
} 
 
alert(typeof User); // function 
User(); // Error: Class constructor User cannot be invoked without 'new' 

输出类
如果输出类,如alert(User),一些引擎显示”class User”,而另一些显示”function User…”。
这里不要困惑,字符串显示可能不同,其实仍然是函数,在javascript语言中没有单独class实体。

类方法是非枚举的
类定义对所有原型中的方法设置enumerable标志为false,这时好事,因为如果我们使用for…in遍历对象,我们通常不想得到class方法。

如果没有构造函数怎么样?
如果在class结构没有构造函数,那么一个空的构造函数自动生成,写法如:constructor(){}。

class总是使用严格模式
所有在class结构的代码自动使用严格模式。

getter/setter

类也可以包括getter/setter,这里示例使用user.name,实现代码:

class User { 
 
  constructor(name) { 
    // invokes the setter 
    this.name = name; 
  } 
 
  get name() { 
    return this._name; 
  } 
 
  set name(value) { 
    if (value.length < 4) { 
      alert("Name too short."); 
      return; 
    } 
    this._name = value; 
  } 
 
} 
 
let user = new User("John"); 
alert(user.name); // John 
 
user = new User(""); // Name too short. 

只有方法

与对象定义不同,类定义代码不能有属性:值方式赋值。只能有方法(方法间没有逗号分割)和getter/setter。

根据这个思想:类中定义的所有内容都是在原型中定义,因为原型应该只存储方法,其在对象之间共享。数据是描述具体对象的状态,应该存储在各自对象中。

如果我们真坚持方非函数值至原型中,那么class无法做到。只能手工修改原型,如下:

class User { } 
 
User.prototype.test = 5; 
 
alert( new User().test ); // 5 

虽然技术上可行,但我们应该知道我们为什么要做。使用getter的替代方式:

class User { 
  get test() { 
    return 5; 
  } 
} 
 
alert( new User().test ); // 5 

从外部代码看是一样的,但通过getter方式应该慢点。

Class 表达式

和函数一样,类能够定义在另一个表达式内部,用于传递、返回等。这里是一个返回类的函数(类工厂):

function getClass(phrase) { 
  return class { 
    sayHi() { 
      alert(phrase); 
    }; 
  }; 
} 
 
let User = getClass("Hello"); 
 
new User().sayHi(); // Hello 

如果还记得class就是函数原型模式定义的特殊形式,就会觉得这很正常。
如命名函数表达式一样,class也可以有一个名称,只能在class定义内部可见。

let User = class MyClass { 
  sayHi() { 
    alert(MyClass); 
  } 
}; 
 
new User().sayHi(); // works, shows MyClass definition 
 
alert(MyClass); // error, MyClass is only visible in methods of the class 

静态方法

静态方法与类函数绑定,而不是原型。且可以使用this关键字(this代表类,java是不能使用的),示例:

class User { 
  static staticMethod() { 
    alert(this == User); 
  } 
} 
 
User.staticMethod(); // true 

在User.staticMethod()方法内部的this值为类User的构造器自身(点前面对象的规则)。
通常static方法用来表达与类相关的功能,不是类的特定对象。
举例,我们有Article对象,并需要一个比较函数,那自然的选择应该是Article.compare,如下:

class Article { 
  constructor(title, date) { 
    this.title = title; 
    this.date = date; 
  } 
 
  static compare(articleA, articleB) { 
    return articleA.date - articleB.date; 
  } 
} 
 
// usage 
let articles = [ 
  new Article("Mind", new Date(2016, 1, 1)), 
  new Article("Body", new Date(2016, 0, 1)), 
  new Article("JavaScript", new Date(2016, 11, 1)) 
]; 
 
articles.sort(Article.compare); 
 
alert( articles[0].title ); // Body 

这里的Article.compare是在所有articles对象之上的,意味这比较他们。

另一个示例被称为工厂方法,使用特定的参数创建一个对象,如Article.createTodays():

class Article { 
  constructor(title, date) { 
    this.title = title; 
    this.date = date; 
  } 
 
  static createTodays() { 
    // remember, this = Article 
    return new this("Todays digest", new Date()); 
  } 
} 
 
let article = article.createTodays(); 
 
alert( articles.title ); // Todays digest 

现在,我们每次需要一个“当天摘要”对象,我们直接调用Article.createTodays()
静态方法用于数据库相关的类,用于从数据库中查询/保存/删除实体,代码示例:
// assuming Article is a special class for managing articles
// static method to remove the article:
Article.remove({id: 12345});


本文参考链接:https://blog.csdn.net/neweastsun/article/details/70568326