ES6中Class类的用法以及和ES5函数声明的区别

news/2024/7/10 22:59:41 标签: es6, javascript, 原型模式
类声明
Class由来

Class写法更接近传统的面向对象语言的语法,它的绝大部分功能,ES5都可以实现,只是为了在写法上更加清晰、更像面向对象语言的语法。其思想和 ES5 是一致的。

Class语法

// es5
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);

等同于

//es6
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ',' + this.y + ')';
  }
}
const p = new Point(1,2);  // 生成类的实例的写法,与 ES5 完全一样,也是使用`new`命令


其中 constructor 方法是类的构造函数,是一个默认方法。通过 new 命令创建对象实例时,会自动调用该方法。一个类必须有 constructor 方法,如果没有显式定义,会自动添加一个默认的consructor方法。所以即使你没有添加构造函数,也是会有一个默认的构造函数的。一般 constructor 方法返回实例对象 this ,但是也可以指定 constructor 方法返回一个全新的对象,让返回的实例对象不是该类的实例。

constructor 方法中的this指向实例对象p,参数x,y的值是创建实例时,通过new Point(1,2)传递进来的。x,y相当于是给p对象的x,y属性设置初始值。创建实例时,可以不传x,y参数,默认为undefiend。

// 不设置初始值
const p = new Point();     // p:{x: undefined, y: undefined}
// 设置初始值
const p = new Point(1,2);  // p:{x: 1, y: 2}


在Class中定义的所有方法都定义在类的prototype属性上面。

class Point {
  constructor() {
    // ...
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同于

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};


与 ES5 一样,类的所有实例共享一个原型对象。也共享原型上的属性。

静态属性和静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

静态属性指的是 Class 本身的属性。同理,如果在一个属性前,加上static关键字,就代表该属性是 Class 本身的属性。该属性也不会被实例继承。

class Foo {
  static myStaticProp = 42;
  static classMethod() {
    return 'hello';
  }
}

Foo.myStaticProp // 42
Foo.classMethod() // 'hello'

var foo = new Foo();
foo.myStaticProp;
// undefined
foo.classMethod()
// TypeError: foo.classMethod is not a function


注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。所以,静态方法中this调用的只能是静态属性和静态方法。

class Foo {
  static bar() {
    this.baz();
  }
  static baz() {
    console.log('hello');
  }
  baz() {
    console.log('world');
  }
}

Foo.bar() // hello


上面代码中,静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。另外,从这个例子还可以看出,静态方法可以与非静态方法重名。

ES5函数声明与ES6类声明的区别
1.枚举性

ES6类内部定义的方式,是不可枚举的;

Object.keys(Point.prototype)
// []


ES5 的写法,toString()方法就是可枚举的。

Object.keys(Point.prototype)
// ["toString"]


2.变量提升

函数声明和类声明之间的一个重要区别在于,函数声明会提升,类声明不会。你首先需要声明你的类,然后再访问它,否则类似以下的代码将抛出ReferenceError:

let p = new Rectangle(); // ReferenceError

class Rectangle {}


3.严格模式

使用类声明,在其内部采用的是严格模式,而函数声明不是。

在函数声明中,未声明变量count不会报错:

function Foo () {
    count = 1
}
const foo = new Foo()
console.log(foo)


使用class声明的方式

class Bar {
    constructor () {
        count = 2 // Uncaught ReferenceError: count is not defined
    }
}
const bar = new Bar()
console.log(bar)


4.new创建实例

类声明必须通过new命令创建实例,而函数声明可以不使用new命令创建实例

function Foo(){
    console.log('函数声明')
}
const foo = Foo();
class Bar{
    constructor(){
        console.log('类声明')
    }
}
const bar = Bar();
// Uncaught TypeError: Class constructor Bar cannot be invoked without 'new'

5.重写类名 

类声明class内部无法重写类名,而函数声明可以重写类名。

function Foo(){
    Foo = 'abc'
}
new Foo()
// 重写类名报错
class Bar{
    constructor(){
        Bar = 'def' // Uncaught TypeError: Assignment to constant variable.
    }
}
new Bar()

 类继承
Class继承语法

Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class Point {
}

class ColorPoint extends Point {
}


Super关键字

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

class Point { /* ... */ }

class ColorPoint extends Point {
  constructor() {
  }
}

let cp = new ColorPoint(); // ReferenceError
 

 另一个需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    this.color = color; // ReferenceError
    super(x, y);
    this.color = color; // 正确
  }
}
 

父类的静态方法,也会被子类继承。 

ES5与ES6继承的区别
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。

ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。


http://www.niftyadmin.cn/n/5164721.html

相关文章

JavaWeb篇_07——Tomcat组件介绍

Tomcat组件 Server组件 启动一个server实例(即一个JVM进程),它监听在8005端口以接收shutdown命令。Server的定义不能使用同一个端口,这意味着如果在同一个物理机上启动了多个Server实例,必须配置它们使用不同的端口。…

直播商城系统源码:实现自营+多商户入驻,提升销售转化率的利器

在当今的数字化时代,直播商城系统源码已经成为商家必备的工具。它不仅可以帮助商家快速搭建自己的电商平台,还能支持自营和多商户入驻,为商家提供多元化的销售渠道。同时,丰富的营销玩法,如优惠券、拼团、秒杀、分销、…

黑洞路由的几种应用场景

第一种在内网中产生环路: 这种核心交换机上肯定写一条默认路由 0.0.0.0 0 10.0.0.1 出口路由要写一条192.168.0.0 16 10.0.0.2 如果出口路由访问一条不存在的内网网段,又或者访问的那台终端停机了,那就会产生三层环路,数据包在…

java excel、word、PPT转换成pdf预览

先引入包:[lib下载地址](https://mp.csdn.net/mp_download/manage/download/UpDetailed)Controllerpublic AjaxResult fileToPdf(RequestBody VerifyCode url, HttpServletResponse response, HttpServletRequest request) throws IOException {String fileUrl req…

【Git】git的安装与使用教程

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Git》。🎯🎯 &#x1f449…

人工智能时代,掌握未来技术趋势,成为领先者

人工智能时代,掌握未来技术趋势,成为领先者 摘要:本文将从热门技术趋势、技术应用场景、技术实践案例、技术发展趋势等角度进行探讨,帮助读者更好地了解技术前沿动态,为自身职业发展提供指导。在人工智能时代&#xf…

ArrayList的初始容量是多少。

如果使用无参构造函数ArrayList()创建一个空的ArrayList对象,那么它的初始容量为10。但是,这个容量是在第一次添加元素时才会分配的,也就是说,在创建对象时,ArrayList的底层是一个长度为0的空数组。如果使用有参构造函…

(四)Spring源码解析:bean的加载流程

一、概述 在前几讲中,我们着重的分析了Spring对xml配置文件的解析和注册过程。那么,本节内容,将会试图分析一下bean的加载过程。具体代码,如下图所示: 1.1> doGetBean(...) 针对bean的创建和加载,我们…