资讯专栏INFORMATION COLUMN

《ES6学习4》Class

seal_de / 1397人阅读

摘要:语言传统方法通过构造函数定义并生成新对象,引入了这个概念作为对象的模板,通过关键字可以定义类。基本语法等同于上面的代码表明,类的数据类型就是函数,类本身指向构造函数。属性引入了属性,在构造函数中返回命令所作用的构造函数。

JS语言传统方法通过构造函数定义并生成新对象,ES6引入了Class这个概念作为对象的模板,通过class关键字可以定义类。

基本语法
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return "(" + this.x + "," + this.y + ")";
}
Point.protortype.doStuff = function () {
  console.log("stuff");
}
// 等同于
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

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

  doStuff() {
    console.log("stuff");
  }
}

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

上面的代码表明,类的数据类型就是函数,类本身指向构造函数。类的所有方法都定义在类的prototype属性上。在类的实例上调用方法,就是在调用原型上的方法。constructor方法是类的默认方法,通过new命令生成对象实例时自动调用该方法。如果没有显示定义,一个空的construtor方法会被默认添加。

类的实例对象

生成实例对象的写法和ES5一样,也是使用new命令,不同于ES5,如果忘记加new将会报错。

class Point {
}
// 等同于
class Point {
  constructor() {
  }
}
var b = new Point(2, 3); // 生成Point实例
var c = Pint(2, 3) // 报错
Class表达式

与函数一样,Class可以使用表达式的形式定义。

const MyClass = class Me { 
  getClassName() {
    return Me.Name;
  }
}

需要注意的是这个类的名字是MyClass,而不是Me,Me只在Class内部有定义指代当前类。如果Class内部没有用到,那么可以省略Me。

let int = new MyClass();
int.getClassName() // Me
Me.Name // 报错

const MyClass = class { 
  getClassName() {
    return Me.Name;
  }
}
# 不存在变量提升
类不存在变量提升,与ES5完全不同。

new Foo() // 报错
class Foo {}

# Class的实例属性
Class的实例属性可以用等式写入类的定义中。

class MyClass {
myProp = 42;

constructor() {

console.log(this.myProp); // 42

}
}

new.target属性

ES6引入了new.target属性,(在构造函数中)返回new命令所作用的构造函数。如果构造函数不是通过new命令调用,那么new.target将会返回undefined,可以利用这个属性确定构造函数是怎么调用的。

function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error("必须使用new生成实例")
  }
  /*另一种写法 
 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(); // 正确
Class的继承

Class可以通过extends关键字实现继承,之类必须在constructor方法中调用super方法,否则新建实例会报错。这是因为子类没有自己的this对象,而是继承父类的this对象。如果子类没有定义constructor方法,那么constructor方法(调用super)会被默认添加。

class Point { /* ... */}

class ColorPoint extends Point {
  constructor() {
    //此处应调用super();
  }
}

let cp = new ColorPoint(); // 报错

另一个注意点是,在子类的构造函数中只有在调用super之后才可以使用this关键字,否则会报错。

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

class ColorPoint extends Point {
  constructor(x, y , color) {
    this.color = color; //报错
    super(x, y);
    this.color = color; //正确
  }
}
super关键字 用作函数

super既可以当作函数使用,也可以当作对象使用。第一种情况,super作为函数调用时代表父类的构造函数。但是返回的之类的实例,即super内部的this指向实例。因此super()相当于A.prototype.constructor.call(this)。

class A {
  constructor() {
    console.log(new.target.name);
  }
}

class B extends A {
  constructor() {
    super();  //作为函数时只能在子类的构造函数中
  }
}

new A // A
new B // B
作为对象

第二种情况,super作为对象时在在普通方法中指向父类的原型对象;在静态方法中指向父类。

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

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2 这里相当于A.prototype.p()
  }
}

let b = new B(); 
this指向

ES6规定,通过super调用父类的方法时,super会绑定子类的this。如果通过super对某个属性赋值,这时的super就是this,赋值的属性会变成子类实例的属性。

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

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

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

ps ...参考资料《ES6标准入门》(第三版)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104362.html

相关文章

  • [译] 在你学习 React 之前必备的 JavaScript 基础

    摘要:前言在理想的状态下,你可以在深入了解之前了解和开发的所有知识。继承另一个类的类,通常称为类或类,而正在扩展的类称为类或类。这种类型的组件称为无状态功能组件。在你有足够的信心构建用户界面之后,最好学习。 原文地址:JavaScript Basics Before You Learn React 原文作者: Nathan Sebhastian 写在前面 为了不浪费大家的宝贵时间,在开...

    Chaz 评论0 收藏0
  • ES6,你不得不学!

    摘要:但是,的本质仍然是函数,是构造函数的另外一种写法。报错原生构造函数的继承对于一些原生的构造函数,比如,,,等,在是无法通过方法实现原生函数的内部属性,原生函数内部的无法绑定,内部属性获得不了。 在没有学习 ES6 之前,学习 React,真的是一件非常痛苦的事情。即使之前你对 ES5 有着很好的基础,包括闭包、函数、原型链和继承,但是 React 中已经普遍使用 ES6 的语法,包括 ...

    CKJOKER 评论0 收藏0
  • 前端基础进阶(十四):es6常用基础合集

    摘要:在继承的构造函数中,我们必须如上面的例子那么调用一次方法,它表示构造函数的继承,与中利用继承构造函数是一样的功能。 showImg(https://segmentfault.com/img/remote/1460000009078532); 在实际开发中,ES6已经非常普及了。掌握ES6的知识变成了一种必须。尽管我们在使用时仍然需要经过babel编译。 ES6彻底改变了前端的编码风格,...

    Ryan_Li 评论0 收藏0
  • 精益 React 学习指南 (Lean React)- 4.1 react 代码规范

    书籍完整目录 4.1 react 代码规范 showImg(https://segmentfault.com/img/bVyE9m); 关于 基础规范 组件结构 命名规范 jsx 书写规范 eslint-plugin-react 关于 在代码的设计上,每个团队可能都有一定的代码规范和模式,好的代码规范能够提高代码的可读性便于协作沟通,好的模式能够上层设计上避免不必要的 bug 出现。本节会参考...

    zhangqh 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<