如何正确设置JavaScript命名空间和类?

Tru*_*an1 42 javascript oop javascript-framework javascript-objects javascript-namespaces

似乎有很多方法来设置JavaScript应用程序,因此对于哪一个是正确的还是最好的而言令人困惑.以下技术或更好的方法有什么不同吗?

MyNamespace.MyClass = {
    someProperty: 5,
    anotherProperty: false,

    init: function () {
        //do initialization
    },

    someFunction: function () {
        //do something
    }
};

$(function () {
    MyNamespace.MyClass.init();
});
Run Code Online (Sandbox Code Playgroud)

其他方式:

MyNamespace.MyClass = (function () {
    var someProperty = 5;
    var anotherProperty = false;

    var init = function () {
        //do something
    };

    var someFunction = function () {
        //do something
    };

    return {
        someProperty: someProperty
        anotherProperty: anotherProperty
        init: init
        someFunction: someFunction
    };
}());

MyNamespace.MyClass.init();
Run Code Online (Sandbox Code Playgroud)

第一种技术感觉更像是一门课.如果这有所不同,我来自服务器端背景.第二种技术似乎更冗余,有点尴尬,但我看到这也使用了很多.有人可以帮助解决一些问题并建议前进的最佳方式吗?我想创建一个有很多类相互交流的应用程序.

Nea*_*eal 63

不做这些事情.

制作一个javascript"class":

var MyClass = function () {

    var privateVar; //private
    var privateFn = function(){}; //private 

    this.someProperty = 5;  //public
    this.anotherProperty = false;  //public
    this.someFunction = function () {  //public
        //do something
    };

};

MyNamespace.MyClass = new MyClass();
Run Code Online (Sandbox Code Playgroud)

一个有静态变量:

var MyClass = (function(){

    var static_var; //static private var

    var MyClass = function () {

        var privateVar; //private
        var privateFn = function(){}; //private 

        this.someProperty = 5;  //public
        this.anotherProperty = false;  //public
        this.someFunction = function () {  //public
            //do something
        };
    };

    return MyClass;

})();

MyNamespace.MyClass = new MyClass();
Run Code Online (Sandbox Code Playgroud)

使用"构造函数"(所有示例都有一个"构造函数",这个只有参数可以使用):

var MyClass = function (a, b c) {

    //DO SOMETHING WITH a, b, c <--

    var privateVar; //private
    var privateFn = function(){}; //private 

    this.someProperty = 5;  //public
    this.anotherProperty = false;  //public
    this.someFunction = function () {  //public
        //do something
    };

};

MyNamespace.MyClass = new MyClass(1, 3, 4);
Run Code Online (Sandbox Code Playgroud)

有了上述所有功能,您可以:

MyNamespace.MyClass.someFunction();
Run Code Online (Sandbox Code Playgroud)

但你不能(从外面):

MyNamespace.MyClass.privateFn(); //ERROR!
Run Code Online (Sandbox Code Playgroud)

  • 从 ES6 开始这个答案不需要更新吗?https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes (2认同)

chr*_*isf 6

第一个示例只是一个Object文字 - 它无法实例化,也没有私有成员.第二个示例有一些不正确的语法(var someProperty: 5应该是var someProperty = 5)但是使用闭包来封装自调用匿名函数中的内部私有状态.

第二种方法看起来更适合封装私有成员,但可以通过使其成为可实例化的类来使其更加"面向对象":

MyNamespace.MyClass = function() { ... };
MyNamespace.MyClass.prototype.someProperty = 'foo';
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用'new'关键字对其进行实例化:

var aClass = new MyNamespace.MyClass();
aClass.init(...);
Run Code Online (Sandbox Code Playgroud)


Art*_*m G 6

为什么你不应该使用

 return { methodName : methodDelegate}
Run Code Online (Sandbox Code Playgroud)

就像第二个例子一样:

MyNamespace.MyClass = (function () {
    var someProperty = 5;

    var init = function () {
        //do something
    };

    return {
        someProperty: someProperty
        someFunction: someFunction
    };
}());

MyNamespace.MyClass.init();
Run Code Online (Sandbox Code Playgroud)

当您使用名称空间时,您必须将其视为声明,而不是实例。

MyNamespace = {};
MyNamespace.sub = {};
MyNamespace.anotherSub = {};
MyNamespace.sub.MyClass = (function () {

    var static_var; //static private var

    var MyClass2 = function () {

        var privateVar; //private
        var privateFn = function () { }; //private 

        this.someProperty = 5;  //public
        this.anotherProperty = false;  //public
        this.someFunction = function () {  //public
            //do something
        };
    };

    return MyClass2;

})();
debugger;

var c1 = new MyNamespace.sub.MyClass();
c1.someProperty = 1; // creates 5->1.

var c2 = new MyNamespace.sub.MyClass();
c2.someProperty = 2;  // creates 5->2. c1 is still 1



debugger;
var myClass = function () {
    var someProperty = 5;
    var anotherProperty = false;

    var init = function () {
        //do something
    };

    var someFunction = function () {
        //do something
    };

    return {
        someProperty: someProperty,
        anotherProperty: anotherProperty,
        init: init,
        someFunction: someFunction
    };
};


MyNamespace.MyClass = myClass();
var c2 = MyNamespace.MyClass;
// how  are planning to create one more object, while it's a reference? copy      //the whole one?

c2.someProperty = 2; // changes 5 -> 2
var c3 = MyNamespace.MyClass.init(); // create 2 instead of 5

c3.someProperty = 3;    // changes c3 and c3 from 2 to 3.
console.log(c2.someProperty + c3.someProperty);
Run Code Online (Sandbox Code Playgroud)

不管模块反模式有多流行。声明使您能够以其他开发人员预期的方式将相同的代码用于不同的实例。代码的质量和阅读的简单性都会提高。任何开发人员的目标都是编写易于阅读的简单代码,而不是较短或枯燥的代码,而是易于其他开发人员阅读和理解。这首先会减少错误的数量。(c) S·麦康奈尔


Dir*_*ter 2

时间已经过去了。我认为现在正确的答案是使用模块(在示例中输入 jsdoc)。

边缘.mjs

/**
 * @typedef {import('./Vertex.mjs').Vertex} Vertex
 */

/**
 * An Edge of a @see Graph
 */
class Edge {
    /**
     * Create an edge.
     * @param {number} weight - The weight of the edge.
     * @param {Vertex} source - The source vertex of the edge.
     * @param {Vertex} target - The target vertex of the edge.
     */
    constructor(weight, source, target) {
        this.weight = weight
        this.source = source
        this.target = target
    }
}

export { Edge }
Run Code Online (Sandbox Code Playgroud)

图.mjs

/**
 * @typedef {import('./Edge.mjs').Edge} Edge
 * @typedef {import('./Vertex.mjs').Vertex} Vertex
 */

/**
 * A Graph of @see Vertex and @see Edge
 */
class Graph {
    /**
     * Creates a new Graph instance.
     * @param {boolean} [isDirected=true] - Is the graph directed (true)?.
     * @param {boolean} [acyclic=true] - Is the graph acyclic (true) or can it contain cycles (false).
     */
    constructor(isDirected = true, acyclic = true) {
        /** @type {Vertex[]} */
        this.vertices = []
        /** @type {Edge[]} */
        this.edges = []
        this.isDirected = isDirected
        this.acyclic = acyclic
    }
...
export { Graph }
Run Code Online (Sandbox Code Playgroud)

索引.js

import { Edge } from './Edge.mjs'
import { Vertex } from './Vertex.mjs'
import { Graph } from './Graph.mjs'

export { Edge, Vertex, Graph }
Run Code Online (Sandbox Code Playgroud)

一些文件.js

import { Edge as Edge1, Vertex, Graph } from './index.mjs'
import { Edge as Edge2 } from './someotherEdge.mjs'

    let edge = new Edge1()
    let otherEdge = new Edge2()
...
Run Code Online (Sandbox Code Playgroud)

在 somefile.js 中,您可以避免名称冲突,但可以在同一文件中使用它们。并且您可以避免尝试使用对象或函数等创建名称空间,并尝试处理随之而来的 jsdoccery。

或者,如果您使用打字稿,您已经享受了命名空间支持和所有打字。