ES6 Class语法学习

前言

大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,这种状态一直延续到了ES5。由于类似的库层出不穷,最终还是在ECMAScript 6中引入了类的特性。本文将详细介绍ES6中的类

类的定义

【ES5的类】

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

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

【ES6的类】

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

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

[注意]this关键字则代表实例对象
[注意]类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。
[注意]类不存在变量提升,这点与ES5完全不同

typeof Point  // 'function'
Point === Point.prototype.constructor // true

类的数据类型就是函数,类本身就指向构造函数。

属性的另一种定义方式

class IncreasingCounter {

  _count = 0; // 可以直接这样定义,而不定义在constructor中

  increment() {
    this._count++;
  }
}

这种写法比较简洁,比较推荐的写法

是否可枚举

ES5中类的方法可以枚举

var Point = function (x, y) {
  // ...
};

Point.prototype.toString = function() {
  // ...
};

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

ES6中类的方法不可枚举

class Point {
  constructor(x, y) {
    // ...
  }

  toString() {
    // ...
  }
}

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

constructor构造函数

1、constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
2、一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

类的调用

通过 new 关键字调用,如果忘记加 new 则会报错

const point = new Point();

类的属性表达式

let methodName = 'getArea';

class Square {
  constructor(length) {
    // ...
  }

  [methodName]() {
    // ...
  }
}

立即执行类

let person = new class {
  constructor(name) {
    this.name = name;
  }

  sayName() {
    console.log(this.name);
  }
}('张三');

person.sayName(); // "张三"

静态方法

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

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

Foo.classMethod() // 'hello'

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

[注意]如果静态方法包含this关键字,这个this指的是类,而不是实例。
[注意]静态方法可继承

静态属性

静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

class Foo {
}

Foo.prop = 1;
Foo.prop // 1

new.target 属性

new是从构造函数生成实例对象的命令。ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

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('张三'); // 正确
var notAPerson = Person.call(person, '张三');  // 报错

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); // 输出 true

【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, 4);  // 正确

extends 继承

class Point {
}

class ColorPoint extends Point {
}

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

class A {
  static hello() {
    console.log('hello world');
  }
}

class B extends A {
}

B.hello()  // hello world

super 关键字

1、super作为函数调用时,代表父类的构造函数。
2、super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
3、在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
4、super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

【1】

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

[注意]子类必须在constructor方法中调用super方法,否则新建实例时会报错。

【2】

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();

子类B当中的super.p(),就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.p()就相当于A.prototype.p()。

【3】

class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
  }
}

let b = new B();
b.m() // 2

【4】

class Parent {
  static myMethod(msg) {
    console.log('static', msg);
  }

  myMethod(msg) {
    console.log('instance', msg);
  }
}

class Child extends Parent {
  static myMethod(msg) {
    super.myMethod(msg);
  }

  myMethod(msg) {
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2

Object.getPrototypeOf()

Object.getPrototypeOf方法可以用来从子类上获取父类。

Object.getPrototypeOf(ColorPoint) === Point // true

类的 prototype 属性和__proto__属性
大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。

(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

【非继承时__proto , prototype】

class A {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true

这种情况下,A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回一个空对象(即Object实例),所以A.prototype.__proto__指向构造函数(Object)的prototype属性。

原文地址:https://www.cnblogs.com/shiyou00/p/10669463.html

时间: 2024-11-09 09:21:53

ES6 Class语法学习的相关文章

解构赋值 —— ES6新语法学习心得

## 3.解构赋值 ## 作用:将数组.对象.函数的参数 解构,对变量进行赋值,可以直接调用该变量,大大提高效率 ## 例 1: ##  标准模式的解构赋值 var [a,b,c]=[1,2,3] console.log(a) //1 console.log(b) //2 console.log(c) //3 ## 例2 : ##  嵌套解构赋值,只要"模式匹配",就能解构赋值,如果没有对应的值,就是undefined let [foo, [[bar], baz]] = [1, [[2

let 和 coust —— ES6新语法学习心得

## 1.let  ## 作用:1. 将变量作用域设置为当前{},外部无法访问 2.在同一个作用域下不允许重复定义相同变量 ## 例1:let的作用域 ## { var a= 10; let b =20; } console.log(a)  //10 console.log(b)   // b is not defined let会将{}作为其作用域,在外面不能访问 ## 例 2: let不会造成变量泄漏 ## for(var i  =0; i < 10 ;i++){ console.log(i

ES6常用语法

ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015. 也就是说,ES6就是ES2015. 虽然目前并不是所有浏览器都能兼容ES6全部特性,但越来越多的程序员在实际项目当中已经开始使用ES6了.所以就算你现在不打算使用ES6,但为了看懂别人的你也该懂点ES6的语法了... 在我们正式讲解ES6语法之前,我们得先了解下Babel. Babel Babel是一个广泛使用的ES6转码器,可以将

ES6新语法之---对象字面量扩展、模板字符串(5)

这节课学习ES6中对象字面量扩展和新增模板字符串 第一部分:对象字面量扩展 1.简洁写法 ES6对于对象字面量属性提供了简写方式. 1.1:属性简写 //传统写法 var x = 2, y = 3, o = { x: x, y: y }; //ES6简洁写法 var x = 2, y = 3, o = { x, //属性名和赋值变量名相同时,可简写 y }; 1.2:方法简写 //传统写法 var o = { x: function() { //... }, y: function() { //

ECMAScript简介以及es6新增语法

ECMAScript简介 ECMAScript与JavaScript的关系 ECMAScript是JavaScript语言的国际化标准,JavaScript是ECMAScript的实现.(前者是后者的规格,后者是前者的实现.但通常两者是可互换的.) ESMAScript的历史 1996年11月,Netscape公司将Js提交给国际化标准组织ECMA,当初该语言能够成为国际化标准. 1997年,ECMAScript 1.0版本推出.(在这年,ECMA发布262号标准文件(ECMA-262)的第一版

正则表达式语法学习

正则表达式用到的地方很多很广,一般用于验证 此文讲解了正则表达式的语法,以下内容转自网友[丰衣足食]的帖子 一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式.该模式描述在查找文字主体时待匹配的一个或多个字符串.正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配. \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 后向引用.或一个八进制转义符.例如,'n' 匹配字符 "n".'\n' 匹配一个换行符.序列 '\\' 匹配

【JavaScript】02.基础语法学习

[JavaScript]02.基础语法学习 引言: 老农认为(老农是我对自己的昵称),学习任何一门计算机程序语言都要先从它的语法知识开始.计算机程序语言由一堆预定义的字符和书写这些字符的规则组成.这些预定义的字符在语言里面叫做关键字或者保留字,书写这些字符的规则叫做语法. 计算机语言(Computer Lnguage),是指用于人与计算机之间通讯的语言.语言分为自然语言与人工语言两大类.自然语言是人类在自身发展的过程中形成的语言,是人与人之间传递信息的媒介.人工语言指的是人们为了某种目的而自行设

Java语法学习概述

Java语法学习概述: 1,数值型有:    整数类型分     byte:127到-128 8位(1个字节);只用后七位表示数字 第一位表            示正负号;特点最基本数据单元,占空间少 short:16位(2个字节)短整型 -32768到32767 int:32位(4个字节) 整型 正负21亿 写程序大部分用int写 long:64位(8个字节) 长整型 +-922后面16个零多           数字后面加字母L 或小写l 表示long型数据           用数字表示

总结常见的ES6新语法特性

总结常见的ES6新语法特性 ES6给我们带来了更"甜"的语法糖(一种语法,使得语言更容易理解和更具有可读性,也让我们编写代码更加简单快捷),如箭头函数(=>).class等等.用一句话来说就是: ES6给我们提供了许多的新语法和代码特性来提高javascript的体验 不过遗憾的是,现在还没有浏览器能够很好的支持es6语法,点这里查看浏览器支持情况,所以我们在开发中还需要用babel进行转换为CommonJS这种模块化标准的语法. 因为下面我会讲到一些es6新特性的例子,如果想要