Javascript:Function和Class之间有什么区别

时间:2016-03-19 08:47:58

标签: javascript ecmascript-6

随着2015年6月ECMAScript 6的发布,引入了Javascript类语法。

此语法:

class Polygon {
      constructor(width, height) {
        this.width = width;
        this.height = height;
      }
}

基本相同:

function Polygon(width, height) {
    this.width = width;
    this.height = height;
}

那么使用class而不是传统函数有什么好处? 在什么条件下我应该使用类而不是函数?

2 个答案:

答案 0 :(得分:19)

类和函数之间存在一些差异 - 大多数人会首先说类是“只是语法糖”,但糖确实很重要。当JS解析器处理JavaScript代码时,解析器会将它们保存在不同的AST节点中,如此处所示, ClassDeclaration ClassExpression 是生成的AST树中的不同节点类型:

https://github.com/estree/estree/blob/master/es2015.md#classes

你可以看到,对于这个解析器,新的ES6 Classes规范在语法中引入了许多新的AST元素:

  • ClassBody
  • MethodDefinition
  • ClassDeclaration
  • ClassExpression
  • 元属性

由于AST语法不是标准的,因此可能有更多或更少的类型,具体取决于解析器,但重要的是要注意当代码进入类声明或类表达式时,JavaScript引擎将对它进行不同的解释。

这意味着,无法交换类和函数声明。如果你试着写

,你可以看到这个
class notWorking {
  return 1;  // <-- creates a parser error
};

这是因为当解析器遇到类-keyword时,它将开始将以下代码视为ClassDeclaration或ClassExpression的ClassBody,然后它希望找到MethodDefinitions。

这是一个小问题,因为创建私有变量会变得更具挑战性。函数声明可以像这样整齐地定义一个私有变量:

function myClass() {
    var privateVar;
}

类声明不能包含:

class myClass {
    var privateVar; // ERROR: should be a method
}

这是因为class的语法只允许在类体内声明方法。至少现在。

但是,存在创建私有字段的提议:

https://github.com/zenparsing/es-private-fields

因此,将来你可能会说

class myClass {
   #privateVar; // maybe this works in the future?
}

考虑到ES6类中的私有属性,有一个单独的答案,它提出了一些解决方法,比如使用符号:

Private properties in JavaScript ES6 classes

var property = Symbol(); // private property workaround example
class Something {
    constructor(){
        this[property] = "test";
    }
}

当然,类和函数之间存在更多差异。 其中一个是吊装 1 - 与函数不同,您无法在范围内的任何位置声明类:

  

函数声明和类之间的重要区别   声明是函数声明被提升和类   声明不是。首先需要声明你的课程   访问它

类声明和函数声明非常相似;

function foo1() {} // can be used before declaration
class  foo2{}      // new foo2(); works only after this declaration

类表达式与函数表达式的工作方式非常相似,例如可以将它们分配给变量:

var myClass = class foobar {};

更多差异为1

  1. 类表达式/声明体始终在严格模式中执行 - 无需手动指定
  2. 类具有特殊关键字构造函数 - 只能有其中一个,或者抛出错误。函数可以有多个名为“constructor”
  3. 的函数变量定义
  4. 类具有与父类构造函数相关的特殊关键字 super 。如果你在构造函数中,可以调用 super(x,y); 来调用父类构造函数,但在Method中你可以调用 super.foobar()来创建调用任何父类函数。这种功能不适用于标准功能,尽管您可以通过一些自定义黑客来模拟它。
  5. 在类体内部,您可以使用 static 关键字定义函数,因此只能使用 ClassName.FunctionName() -syntax调用它。
  6. 类声明和表达式都可以使用 extends 关键字,例如类Dog extends Animal
  7. MethodDeclaration不需要函数-prefix,因此您可以在类“m”中定义函数“ok”,如下所示: class m {ok(){}} 。实际上甚至不允许将函数定义为 class m {function ok(){}}
  8. 然而,在解析器完成它的工作之后,类实例基本上以与任何其他对象相同的方式运行。

    新的ES6 Class语法本质上是以传统的OOP方式表达对象的更清晰的方式,如果你喜欢它,那么你应该使用它。

    编辑:另外,ES6 Class语法还有另一个限制:它不允许成员函数使用胖箭头进行词法绑定。 ES7似乎允许experimental feature允许它。例如,当将方法绑定到事件处理程序时,这可能很有用,相关问题是here

    1 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

答案 1 :(得分:0)

class它只不过是使用function创建javascript逻辑类的语法糖。如果你使用function作为class整个函数充当构造函数,如果你想在this.something = ...或{{{{}}之类的构造函数中放置其他成员函数。 1}}如果是私有成员(如果你不是从外部注入,假设你正在用其他方法/属性创建对象),但是在类的情况下,整个函数实际上不是一个构造函数,你可以明确地将它与其他成员职能和数据。