JavaScript定义类

8
什么是定义类的最佳方式?我知道大多数情况下这取决于个人偏好,但以下3个示例之间有什么直接区别?
示例1:
var Class = (function(){
    function Class() {
      this.test = 'test'                
    }
    return Class;
})();

var c = new Class();
console.log(typeof Class);
console.log(c.test);

示例2

var Class2 = function(){
      this.test = 'test'                
};

var c2 = new Class2();
console.log(typeof Class2);
console.log(c2.test);

示例三

function Class3(){
      this.test = 'test'                
};

var c3 = new Class3();
console.log(typeof Class3);
console.log(c3.test);

有时我也会这样使用: var Class =(function(){ var Private = {},Public = {}; //你的代码 });
    Private._doSomething = function() {
        // something
    }

    Public.doSomethingElse = function() {
        // something else
    }
    return Public;
    })();

虽然不会有太大的帮助,但实际上在ECMAScript/JavaScript中并没有类;如果你经常使用instanceof,那么你可能需要更深入地学习这门语言。 - Julien Royer
1
首先要记住的是,在JavaScript中真正没有“类”这样的东西。你可以通过几种方式来模拟这种结构,但语言本身并没有这样的构造。编辑 -- 哈哈 - Pointy
虽然 JavaScript 目前还没有 Class(首字母大写)特性,但仍然可以使用类(小写)的概念来描述共享相同特征的对象。Julien 的观点是正确的,过多使用 typeofinstanceof 等通常意味着你可能错过了某些技巧。 - T.J. Crowder
我同意您的观点,T.J.;但是“Class”关键字的问题在于它通常会隐含地与类继承一起使用,而JavaScript的继承是基于对象/实例的。 - Julien Royer
您可以使用这个小脚本:http://classjs.weew.ch/ - M K
1个回答

7

注意:下面的主要答案是在2012年写的。有关JavaScript自己的class功能(ES2015 +),请参见结尾处的其他说明。


“最好”的东西本质上是主观的,但我会试着指出每个选项的一些信息,让你自己决定“最好”。

示例1

……让你拥有一个方便的范围(匿名函数),在这里你可以放置真正私有的类范围信息(和实用函数),只有Class函数才能访问:

var Class = (function(){
    var trulyPrivateInformation = 42;

    function trulyPrivateUtilityFunction() {
        // ...
    }

    function Class() {
      this.test = 'test';
    }
    return Class;
})();

例子1不会被"提升"。它将作为逐步执行的代码的一部分进行处理。

Class函数将有一个真实的名称。

例子2

...创建了一个没有名称的函数并将其分配给一个有名称的变量。现代浏览器对此非常聪明,但至少在理论上,该函数是匿名的,这会影响您的工具所提供的信息(截至ES2015)。它有一个名称(Class2),除了像IE这样过时的环境以外。它没有私有类范围的作用域,就像例子1一样。

与例子1一样,例子2作为逐步执行的代码的一部分进行处理,而不是被"提升"。

例子3

...就是没有私有类范围的例子1,但它也被"提升"——Class函数在任何逐步执行的代码之前就被定义了。这意味着这样可以工作:

var c = new Class();
console.log(c.test); // Logs 'test'

function Class() {
    this.test = 'test';
}

请注意,即使 Class 定义在下面,它也会在上面的代码运行之前被执行。这对于 Example 1 和 Example 2 都不成立。
与 Example 1(但不是 2)类似,Class 函数有一个真实的名称。
2015 年,JavaScript 推出了自己的 class 语法。现在,在 2019 年,所有现代浏览器都原生支持它,并且如果需要支持 IE,可以使用 Babel 等工具进行转译。以下是 class 如何与 OP 的问题相关联:

Example 1 使用 class

const Class = (() => {
    let trulyPrivateInformation = 42;

    function trulyPrivateUtilityFunction() {
        // ...
    }

    return class Class {
        constructor() {
            this.test = 'test';
        }
    }
})();

在代码逐步执行的过程中进行处理。对于真正私有的内容,具有真正的私有范围(在匿名作用域函数内)。具有适当的名称。

使用class的示例2(也是使用class的示例3)

class Class2 {
    constructor() {
        this.test = 'test';
    }
}

let c2 = new Class2();
console.log(typeof Class2);
console.log(c2.test);

逐步执行代码处理。不具有像示例1那样的真正私有作用域(尽管私有字段和方法即将推出)。有一个适当的名称。


如果你对使用JavaScript进行这些操作感兴趣,我已经编写了一个工具脚本叫做Lineage,以简化在处理层次结构时的操作。 - T.J. Crowder
谢谢TJ!是的,对于其他人来说,我非常清楚javascript目前还没有官方的类支持。我希望它会出现,但我猜这仍在讨论中。我一定会看看你的库! - barry
据我理解,示例3可以在实例之间拥有私有方法和属性(而不是共享实例数据)。您自己说过3是被提升的,因此,加上简洁明了的语法,我会选择3。我知道这并没有什么实际好处,但我喜欢它,因为它类似于其他面向对象的语言中的类,并且我认为例如1有点违反了类的一般定义,即蓝图而不是变量,并且不关心它在执行流程中的定义位置。 - MrCode
@MrCode:不,正如OP(和上面)引用的示例3没有为实例之间的私有方法和属性提供任何规定。(仅在实例内部,通过在构造函数本身中定义它们。)我同意hoisting很好(有些人认为它是邪恶的,但我不这么认为),但由于我所做的与示例1最相似,所以我只需确保在尝试使用它们之前定义我的“类”。 - T.J. Crowder
@MrCode:我们只能同意不同意见,我没有看到 Example 3 中有任何封装,而 Example 1 没有。我倒是看到了相反的情况。祝好! - T.J. Crowder
显示剩余13条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接