【问题标题】:Javascript: What is the difference between Function and ClassJavascript:函数和类有什么区别
【发布时间】:2016-07-06 02:43:05
【问题描述】:

随着 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;
}

那么使用类代替传统函数有什么好处呢? 在什么情况下我应该使用类而不是函数?

【问题讨论】:

  • 这个答案(虽然不是完全重复)很好地解释了这些差异:stackoverflow.com/questions/30783217/…
  • stackoverflow 有什么问题,-5 仅用于询问正常问题。我觉得够了,自己学吧。感谢那些试图给出解释的响应者,我很感激。
  • JS 中 Function 和 Class 的区别不是基于意见的。这是一个真正的区别,显然需要解释。有关该主题的更详细说明,请参阅我发布的答案。
  • 不幸的是,有些人显然不欣赏我给出的答案,但这个问题仍然非常有效且非常重要,因为 Class 语法存在一些限制 - 我认为最重要的是缺乏私有范围用于保存变量。
  • 为什么这个问题被关闭了?接受的答案提供了类和函数之间的一些具体差异,我发现它很有帮助。这个问题不应该被关闭。

标签: javascript ecmascript-6


【解决方案1】:

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

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

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

  • 类体
  • 方法定义
  • 类声明
  • 类表达式
  • 元属性

由于 AST 语法不是标准的,根据解析器的不同,可以有更多或更少的类型,但是需要注意的是,当代码进入类声明或类表达式时,JavaScript 引擎会以不同的方式解释它。

这意味着不能交换类和函数声明。如果您尝试编写,您可以看到这一点

class notWorking {
  return 1;  // <-- creates a parser error
};

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

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

function myClass() {
    var privateVar;
}

类声明不能有这个:

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

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

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

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. Class 表达式/声明主体始终以严格模式执行 - 无需手动指定
  2. 类有特殊的关键字constructor - 只能有一个,否则会抛出错误。函数可以有多个名为“构造函数”的函数变量的定义
  3. 类有特殊的关键字super,它与父类的构造函数有关。如果你在构造函数内部,你可以调用 super(x, y); 来调用父类构造函数,但是在 Method 内部你可以调用 super.foobar() 来创建调用任何父类函数。这种功能不适用于标准函数,尽管您可以通过一些自定义黑客来模拟它。
  4. 在类主体中,您可以使用 static 关键字定义函数,因此只能使用 ClassName.FunctionName() -syntax 来调用它。
  5. 类声明和表达式都可以使用 extends 关键字,例如 class Dog extends Animal
  6. MethodDeclaration 不需要函数前缀,因此您可以在类“m”中定义函数“ok”,如下所示:class m { ok() { } }。实际上甚至不允许将函数定义为 class m { function ok() { } }

然而,在解析器完成它的工作之后,类实例的运行方式基本上与任何其他对象相同。

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

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

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

【讨论】:

  • 我还添加了一条关于 ES6 类声明缺少粗箭头语法的通知。
  • @TeroTolonen:这几乎不是区分类和函数的“特性”。您可以在构造函数内部使用箭头函数,而不是在原型上。
  • @Bergi:我的意思是这样的:class a { n = (val) => { } }
  • @TeroTolonen:那应该是什么?这显然是一个语法错误,就像function n = (val) =&gt; {} 一样。您需要使用 class a { constructor() { this.n=val=&gt;{…}; } } - 就像在使用 function 关键字创建的构造函数中所做的一样。
  • (new a()).n() 在 babel repl 中工作得很好,但这仍然是实验性的,就像在文本和其他答案中解释的那样
【解决方案2】:

class 它只不过是使用function 创建 javascript 逻辑类的语法糖。如果您使用function 作为class,则整个函数都充当构造函数,如果您想将其他成员函数放入构造函数中,例如this.something = ...,或var something = ...(如果是私有成员) (如果您不是从外部注入,则假设您正在使用其他方法/属性创建对象),但在类的情况下,整个函数实际上并不是构造函数,您可以将其与其他成员函数和数据显式分开。

【讨论】:

    猜你喜欢
    • 2012-08-11
    • 2010-12-14
    • 1970-01-01
    • 2021-04-29
    • 2020-06-20
    • 2013-04-24
    相关资源
    最近更新 更多