优点

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)

主要缺点是,比较复杂,用到了this和prototype,编写和阅读都很费力。

上面的式子可以如下简单的理解:

用构造函数模拟"类",在其内部用this关键字指代实例对象。

function Point(x, y) {

    this.x = x;
this.y = y; }

生成实例的时候,使用new关键字。

const p = new Point(1,2);

然后将类的属性和方法,定义在构造函数prototype对象上

Point.prototype.toString = function(){

    return "(" + this.x + "," + this.y + ")";

}

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);//function
console.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 green
console.log(cp instanceof ColorPoin);//true
console.log(cp instanceof Poin);//true
// instanceof测试构造函数的prototype属性是否出现在对象的原型链中的任何位置

Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系(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();//string
Obj.toValue();//value
console.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"));//true
console.log(pott.hasOwnProperty("y"));//true
console.log(pott.hasOwnProperty("toString"));//false
console.log(pott);
console.log(pott.__proto__);
console.log(pott.__proto__.hasOwnProperty("toString"));//true const p1 = new Pott(2,3);
const p2 = new Pott(3,3); console.log(p1.__proto__ === p2.__proto__);//true p1.__proto__.printName = function(){
return "Oops";
}
console.log(p1.printName());//Oops
console.log(p2.printName());//Oops
const 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: 123
console.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) // true
console.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());//Hello const 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

注意:Object.create()法

Javascript的国际标准ECMAScript第五版(目前通行的是第三版),提出了一个新的方法Object.create()。

使用Object.create()的方法,"类"就是一个对象,不是函数。

详细的可以看这篇文章:Javascript定义类(class)的三种方法

参考文章

探索ES6

ES6-阮一峰

Javascript定义类(class)的三种方法-阮一峰

ES6 class 类的理解(一)的更多相关文章

  1. JavaScript es6 class类的理解。

    本着互联网的分享精神,在本篇文章我将会把我对JavaScript  es6 class类的理解分享给大家. JavaScript 类主要是 JavaScript 现有的基于原型的继承的语法糖. 类语法 ...

  2. ES6中的class类的理解

    传统的javascript中只有对象,没有类的概念.它是基于原型的面向对象语言.原型对象特点就是将自身的属性共享给新对象.这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的感脚!非常容易让人 ...

  3. ES6入门——类的概念

    1.Class的基本用法 概述 JavaScript语言的传统方式是通过构造函数,定义并生成新对象.这种写法和传统的面向对象语言差异很大,下面是一个例子: function Point(x, y) { ...

  4. ES6之let(理解闭包)和const命令

    ES6之let(理解闭包)和const命令 最近做项目的过程中,使用到了ES6,因为之前很少接触,所以使用起来还不够熟悉.因此购买了阮一峰老师的ES6标准入门,在此感谢阮一峰老师的著作. 我们知道,E ...

  5. React和ES6(二)ES6的类和ES7的property initializer

    React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...

  6. [BS-18] 对OC中不可变类的理解

    对OC中不可变类的理解 OC中存在很多不可变的类(如NSString,NSAttributedString,NSArray,NSDictionary,NSSet等),用它们创建的对象存在于堆内存中,但 ...

  7. [js高手之路] es6系列教程 - new.target属性与es5改造es6的类语法

    es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 ...

  8. 对Java中properties类的理解

    转载于:https://www.cnblogs.com/bakari/p/3562244.html 一.Java Properties类 Java中有个比较重要的类Properties(Java.ut ...

  9. AtomicInteger类的理解与使用

    AtomicInteger类的理解与使用 首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Sample1 { private stati ...

随机推荐

  1. Javascript中String()和new String()的区别——JS的包装对象

    最近在看Symbol不能使用new操作符,然后类比到Number,String,Boolean,因为它们同属于基本类型,但是有有所差异:Number,String,Boolean是可以使用new操作符 ...

  2. Spring Boot从入门到精通(八)日志管理实现和配置信息分析

    Spring Boot对日志的处理,与平时我们处理日志的方式完全一致,它为Java Util Logging.Log4J2和Logback提供了默认配置.对于每种日志都预先配置使用控制台输出和可选的文 ...

  3. 简述N种排序算法

    排序算法概述 排序算法是程序员日常很常见的算法,基本上每天都会使用排序,在这里将进行一下总结. 排序算法大致可分为比较类排序和非比较类排序二种,其核心区别可以简单的理解为非比较类排序是对比较类排序之前 ...

  4. RStudio终端操作

    转于:https://support.rstudio.com/hc/en-us/articles/115010737148-Using-the-RStudio-Terminal#send 原文是英文版 ...

  5. 032.核心组件-kube-proxy

    一 kube-proxy原理 1.1 kube-proxy概述 Kubernetes为了支持集群的水平扩展.高可用性,抽象出了Service的概念.Service是对一组Pod的抽象,它会根据访问策略 ...

  6. 学习 CSS 之用 CSS 3D 实现炫酷效果

    一.前言 把大象关进冰箱需要几步?三步,把冰箱门打开,把大象关进去,把冰箱门关上. 用 CSS 实现 3D 效果需几步?三步,设置透视效果 perspective,改变元素载体为 preserve-3 ...

  7. [项目分享]JSP+Servlet+JDBC实现的云端汽修后台管理系统

    本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/chenlinSir/CloudDemo-servlet 难度等级:简单 基于JSP+Servlet+Jdbc的云端 ...

  8. Session的常用方法

    Session的常用方法 session对象主要用于属性操作和会话管理,常用方法如下: 1.public void setAttribute(String name,String value)设定指定 ...

  9. BFPRT算法(求第K小的数字)

    BFPRT算法: 1.介绍: BFPRT算法又叫中位数的中位数算法,主要用于在无序数组中寻找第K大或第K小的数,它的最坏时间复杂度为O(n),它是由Blum,Floyd,Pratt,Rivest,Ta ...

  10. Fiddler3 使用技巧

    1.Fiddler抓不到包怎么解决 (1)先确定是HTTP包抓不到还是HTTPS包抓不到.如果只是HTTPS包抓不到,说明是证书的问题,需要重新安装证书. (2)检查浏览器的HTTP代理设置是否正确, ...