关于类:在javascript中使用哪种方法定义类

Which way to use to define classes in JavaScript

我找到了不同的工作方式。

教科书和互联网中的推荐方式:

1
2
3
4
var Person = function() {
    this.age = 23;
}
Tony = new Person();

这似乎也有效:

1
2
3
4
function Person() {
    this.age = 23;
}
Tony = new Person();

有什么区别吗?另外一个问题是:通常你不能简单地省略括号。这里是可能的(new Person而不是new Person())。这是因为使用了新的关键字,对吗?

我刚刚尝试的第三种奇怪的方法如下:

1
2
3
4
5
function Person() {
    return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.

在这里,我没有得到一个具有类名称的对象,但是我的属性也是可访问的,而且它似乎与上述两种方法非常相似。

我应该使用什么?技术上的区别是什么?谢谢您!


1和2(var x=函数vs函数x)非常相似。3是完全不同的东西。

1和2之间的区别与课程无关,之前曾被问过(几次)。我认为最完整的答案是:https://stackoverflow.com/a/338053/1669279简而言之,前x指向一个匿名函数,一些调试工具可能对此有问题。第一个可以从定义的行中获得,而第二个可以在整个范围中获得。阅读链接的答案了解详细信息。

第三个"解决方案"根本不是一个类。它只是一个返回对象的函数(可以称为工厂方法)。

从构造器返回东西不是一个好主意,尤其是return this。只有当您想要覆盖创建对象的正常过程(例如实现单例模式)时,才应该返回内容。

作为旁注,在实例化类时应该始终使用new。以下是当您试图变得聪明并保存字符时会发生的情况:

1
2
3
4
5
function X () {
  return this;  
}

console.log(X()); // outputs the window object

调用不带参数的构造函数后的括号是可选的,但不希望这样做,因为这样会导致代码更加混乱。

总而言之,我通常使用模式1。模式2也可以。

模式2的一个问题是:

1
2
3
4
5
6
7
8
9
10
11
var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet

function X() {
  this.message = 'I am X';
}

X.prototype.method = function() {
  console.log(this.message);
};

JavaScript是一种无类语言。类不存在,但对象可以通过使用原型彼此继承属性。这意味着您不局限于以类的方式实现继承。就我个人而言,我喜欢使用backbonejs启发的方法(代码需要下划线):

1
2
3
4
5
6
7
8
9
10
11
12
var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor

BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
    var base = this; //Save a reference for later
    //Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
    var SubObject = _.extend(function(){
        base.apply(this, arguments); //Call base constructor
    }, this);
    SubObject.prototype=  _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
    return SubObject; //Return the new constructor + prototype
};

这可以让你做一些很酷的课程,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var Car = BaseObject.extend({
    speed: 0,
    acceleration: 5,

    accelerate: function(){
        this.speed += this.acceleration;
    }
});

var RaceCar = Car.extend({
    acceleration: 10,
});

var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();

if(raceCar.speed > car.speed){
    console.log('raceCar won');
}else{
    console.log('car won');
}

关于javascript继承的更多信息,我强烈推荐阅读javascript:DouglasCrockford的好文章。

关于你的例子:

1和2之间的差异最小。有关详细信息,请参阅此问题。

在3中,您只是返回一个对象文本。新关键字只影响函数中不使用的此关键字,因此使用新关键字没有任何效果。有关详细信息,请参阅此队列


我就是这样做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    ;(function (window) {
       "use strict";
        //-- Private Vars
        var opt, obj, rm, Debug;

        //-- construtor
        function App(requestedMethod) {
            //-- set up some vars
            if(typeof requestedMethod !== 'undefined') {
                rm = requestedMethod;
            }
            opt = {
                rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
            }
            //-- containe resulable objects
            obj = {}
            //-- call the init method
            this.init();
        }


        /** Public Methods **/

        /**
         * The Init method called on every page load
         */

        App.prototype.init = function () {
            var om = opt.rMethod;
            //-- Once all init settings are performed call the requested method if required
            if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
        };

        /**
         * testmethod
         */

        App.prototype.testmethod = function () {



        };


        /** Private Methods **/

        function PrivateMethod(){

        }
        /**
         *  A console output that should enable to remain enable js to work in IE
         *  just incase i forget to remove it when checking on those pesky IE browsers....
         */

        function _DB(msg){
            if(window.console && window.console.log){
                var logDate = new Date();
                window.console.log('------------------- ' + logDate + ' ----------------------------------');
                window.console.log(msg);
            }
        };


        window.App = App;

    })(window);

然后像这样称呼它:

1
2
    <script src="ptha/to/your/app.js">
    $(function() { new App('testmethod'); });

当加载代码时,新的app()将在所有页面加载数据完成后运行。

希望这有帮助。要在外部访问它,请将新的添加到var

1
 var App = new App('testmethod);

然后你可以访问

1
    App.testmethod()...

1
2
3
var Person = function() {
    this.age = 23;
}

person是一个包含(被引用)匿名函数的变量

1
2
3
function Person() {
    this.age = 23;
}

但在这里,您声明了一个名为"person"的函数

1
2
3
function Person() {
    return {age: 2};
}

所以您声明一个函数,它返回一个新的静态对象。

最好的方法取决于需求,如果要声明类,请使用第二种方法,而创建模块则使用第三种方法。有关第一个方法,请访问:http://helephant.com/2008/08/23/javascript-anonymous-functions/