关于js中function和class的内在关系及区别的理解

在js中,从es6开始引进class,根本上是基于js中已经存在的原型继承的语法糖,class语法并没有引进一种新的面向对象的继承机制。

一、定义class

  class事实上是一种特殊的funcion,就像可以定义funcion表达式和funcion声明一样,class语法也有2种形式:class表达式和class声明。

  1、class声明

  定义一个class,可以使用class关键字加上类名。需要注意的是,funcion声明和class声明有一个重要的却别:funcion声明是hosting(状态提升)的,而class不是,class需要先声明再使用。

1 class Rectangle {
2   constructor(height, width) {
3     this.height = height;
4     this.width = width;
5   }
6 }

  2、class表达式

  class表达式类名可选,已经命名的class可以通过实例的'.name'属性获取,依据class自身的命名。

 1 // unnamed
 2 let Rectangle = class {
 3   constructor(height, width) {
 4     this.height = height;
 5     this.width = width;
 6   }
 7 };
 8 console.log(Rectangle.name);
 9 // output: "Rectangle"
10 
11 // named
12 let Rectangle = class Rectangle2 {
13   constructor(height, width) {
14     this.height = height;
15     this.width = width;
16   }
17 };
18 console.log(Rectangle.name);
19 // output: "Rectangle2"

 

二、class中body和method的定义

  class的body部分包含在花括号{}中,这里是定义class成员的地方,比如constructor和method。

  1、constructor

  constructor方法是一个特殊的方法,用来创建并初始化一个对象。在一个class中只能有一个命名为constructor的特殊方法,如果包含多个将会报错。

  constructor中可以通过super关键字,调用父类的constructor方法。

  2、prototype methods(原型方法)

 1 class Rectangle {
 2   constructor(height, width) {
 3     this.height = height;
 4     this.width = width;
 5   }
 6   // Getter
 7   get area() {
 8     return this.calcArea();
 9   }
10   // Method
11   calcArea() {
12     return this.height * this.width;
13   }
14 }
15 
16 const square = new Rectangle(10, 10);
17 
18 console.log(square.area); // 100

  3、static methods(静态方法)

  通过static关键字为一个class创建静态方法,static methods的调用无需对class实例化,也不能被实例对象所调用。

 1 class Point {
 2   constructor(x, y) {
 3     this.x = x;
 4     this.y = y;
 5   }
 6     
 7   static distance(a, b) {
 8     const dx = a.x - b.x;
 9     const dy = a.y - b.y;
10 
11     return Math.hypot(dx, dy);
12   }
13 }
14 
15 const p1 = new Point(5, 5);
16 const p2 = new Point(10, 10);
17 
18 console.log(Point.distance(p1, p2)); // 7.0710678118654755

  4、static和prototype method的封装

  当static或prototype method被调用的时候,如果没有对this赋值,那么this将是undefine状态。这和是否采用static模式无关,因为class类体中的代码已经默认执行static模式。

 1 class Animal { 
 2   speak() {
 3     return this;
 4   }
 5   static eat() {
 6     return this;
 7   }
 8 }
 9 
10 let obj = new Animal();
11 obj.speak(); // Animal {}
12 let speak = obj.speak;
13 speak(); // undefined
14 
15 Animal.eat() // class Animal
16 let eat = Animal.eat;
17 eat(); // undefined

  如果以上代码是基于传统的function的语法,则this值是global object。

三、extends创建子类

  extends关键字用于在class声明或表达式中,创建另一个class的子类。

 1 class Animal { 
 2   constructor(name) {
 3     this.name = name;
 4   }
 5   
 6   speak() {
 7     console.log(this.name + ' makes a noise.');
 8   }
 9 }
10 
11 class Dog extends Animal {
12   constructor(name) {
13     super(name); // call the super class constructor and pass in the name parameter
14   }
15 
16   speak() {
17     console.log(this.name + ' barks.');
18   }
19 }
20 
21 let d = new Dog('Mitzie');
22 d.speak(); // Mitzie barks.

  如果在子类中有constructor方法,在使用"this"之前需要调用super()。也可以继承自function-based的class。

 1 function Animal (name) {
 2   this.name = name;  
 3 }
 4 
 5 Animal.prototype.speak = function () {
 6   console.log(this.name + ' makes a noise.');
 7 }
 8 
 9 class Dog extends Animal {
10   speak() {
11     console.log(this.name + ' barks.');
12   }
13 }
14 
15 let d = new Dog('Mitzie');
16 d.speak(); // Mitzie barks.

  需要注意的是:class不能继承自常规对象(non-constructible),如果想继承自常规对象,可以使用Object.setPrototypeOf()替代。

 1 const Animal = {
 2   speak() {
 3     console.log(this.name + ' makes a noise.');
 4   }
 5 };
 6 
 7 class Dog {
 8   constructor(name) {
 9     this.name = name;
10   }
11 }
12 
13 // If you do not do this you will get a TypeError when you invoke speak
14 Object.setPrototypeOf(Dog.prototype, Animal);
15 
16 let d = new Dog('Mitzie');
17 d.speak(); // Mitzie makes a noise.

四、super关键字调用父类

  关键字super用于调用父类相应的方法,这是相较于原型继承的一个好处。

 1 class Cat { 
 2   constructor(name) {
 3     this.name = name;
 4   }
 5   
 6   speak() {
 7     console.log(`${this.name} makes a noise.`);
 8   }
 9 }
10 
11 class Lion extends Cat {
12   speak() {
13     super.speak();
14     console.log(`${this.name} roars.`);
15   }
16 }
17 
18 let l = new Lion('Fuzzy');
19 l.speak(); 
20 // Fuzzy makes a noise.
21 // Fuzzy roars.

  

  

posted @ 2018-07-18 16:32  dunaiyang  阅读(14835)  评论(0编辑  收藏  举报