用JavaScript构建类的正确方法?

用JavaScript构建类的正确方法?,javascript,prototype-programming,Javascript,Prototype Programming,我不熟悉JavaScript,并试图理解如何编写类(我的“常规”OO语言背景,如java和c++) 我知道我有两个选择: 如果我希望我的类有私有方法和成员,我不能在原型中定义它们。但在这种情况下,它们将为创建的每个新对象构建(内存问题) 如果我在类原型中定义方法,我将没有封装(这对我来说很奇怪,作为java/c++开发人员:p) 你用哪两种方法?为什么?所以,我不认为这个问题有一个“正确的答案”…它基本上是你喜欢的,并且认为最适合你的特定用途。我的许多类都是“静态类”,例如 因为我从来不需要实例

我不熟悉JavaScript,并试图理解如何编写类(我的“常规”OO语言背景,如java和c++)

我知道我有两个选择:

  • 如果我希望我的类有私有方法和成员,我不能在原型中定义它们。但在这种情况下,它们将为创建的每个新对象构建(内存问题)

  • 如果我在类原型中定义方法,我将没有封装(这对我来说很奇怪,作为java/c++开发人员:p)


  • 你用哪两种方法?为什么?

    所以,我不认为这个问题有一个“正确的答案”…它基本上是你喜欢的,并且认为最适合你的特定用途。我的许多类都是“静态类”,例如

    因为我从来不需要实例化它们。当我需要实例化多个实例时,我使用prototype方法

    如果需要私有变量,可以定义一个函数/类来执行私有变量,以及需要访问该函数/类中的那些私有变量的方法。然后,对所有不需要访问私有变量的方法使用原型方法。例如

    var PageClass = function() {
        var _birthdate;
    
        this.getBirthdate = function() {
            return typeof(_birthdate) == "undefined" ? null : _birthdate;
        }
        this.setBirthdate = function( date ) {
            if( typeof(date) == 'object' && date.constructor == Date ) {
                _birthdate = date;
            }
            else {
                throw "Invalid Argument Exception: PageClass.setBirthdate expects parameter of type 'Date'";
            }
        }
    }
    PageClass.prototype.doSomething = function() {
        alert("DOING SOMETHING");
    }
    

    这两种方法都可以使您的实例化稍微轻一些,但仍然可以提供一些封装。到目前为止,我从未为私有变量烦恼过。

    如果使用原型框架,最好使用它们实现类和继承的方式。你可能指的是

    通常我认为javascript中不使用私有成员。(edit:不在实例化类中。我经常在我们的代码库中看到一些“模块”,它们确实持有私有状态,但可以被视为单例)

    凯文的回答大致概括了这一点。从技术上讲,解决该语言缺乏封装的问题是可能的,但如果要大量实例化类,则需要付出代价。此外,我认为如果要使用继承,您需要做一些工作来获得受保护的可见性

    例如,我认为我在查看ext源时没有看到任何私人内容。它们确实将“//private”放在了应该是私有的方法之上,这意味着不应该直接调用它们。 这确实意味着,如果要以这种方式编写代码,您需要更多的“规程”来编写getter/setter。

    为什么会有。。。现在

    以上答案对他们的时间来说是正确的

    以下是新的解决方案:

    'use strict';
    
    // Declare our class
    class Metadata {
    
        // Declare the constructor and pass it some values - a and b are "defaults"
        constructor( ninfo, a = 1.0, b = 1.0 )
        {
            // Set our class variables
            this.ninfo = ninfo;
            this.a = a;
            this.b = b;
    
            // Define our "secret" or nonenumerable options
            Object.defineProperty( this, 'addA', {
                enumerable: false,
                writable: false,
    
                // Have it add our passed in value
                value: n => this.a += n
            } );
        }
    }
    
    // Call our class and pass in some variables
    let x = new Metadata( "we have a and b", 1.0 );
    
    // Log our result if we call "addA"
    console.log( x.addA( 3 ) ); // => 4
    
    // Log our object
    console.log( x ); // => Metadata { ninfo: 'we have a and b', a: 4, b: 2 }
    
    // Log our object 'for real'
    console.log( require( 'util' ).inspect( x, { showHidden: true, depth: null } ) );
    
    // result
    // Metadata {
    //      ninfo: 'we have a and b',
    //      a: 4,
    //      b: 2,
    //      [addA]: { [Function: value] [length]: 1, [name]: 'value' } }
    
    阅读这里:还有这个:看看
    'use strict';
    
    // Declare our class
    class Metadata {
    
        // Declare the constructor and pass it some values - a and b are "defaults"
        constructor( ninfo, a = 1.0, b = 1.0 )
        {
            // Set our class variables
            this.ninfo = ninfo;
            this.a = a;
            this.b = b;
    
            // Define our "secret" or nonenumerable options
            Object.defineProperty( this, 'addA', {
                enumerable: false,
                writable: false,
    
                // Have it add our passed in value
                value: n => this.a += n
            } );
        }
    }
    
    // Call our class and pass in some variables
    let x = new Metadata( "we have a and b", 1.0 );
    
    // Log our result if we call "addA"
    console.log( x.addA( 3 ) ); // => 4
    
    // Log our object
    console.log( x ); // => Metadata { ninfo: 'we have a and b', a: 4, b: 2 }
    
    // Log our object 'for real'
    console.log( require( 'util' ).inspect( x, { showHidden: true, depth: null } ) );
    
    // result
    // Metadata {
    //      ninfo: 'we have a and b',
    //      a: 4,
    //      b: 2,
    //      [addA]: { [Function: value] [length]: 1, [name]: 'value' } }