使用哪种方式在 JavaScript 中定义类

Which way to use to define classes in JavaScript

本文关键字:JavaScript 定义 方式      更新时间:2023-09-26

我找到了似乎有效的不同方法。

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

var Person = function() {
    this.age = 23;
}
Tony = new Person();

这似乎也有效:

function Person() {
    this.age = 23;
}
Tony = new Person();

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

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

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

在这里,我没有获得带有类名称的对象,但是我的属性也可以访问,并且似乎与上述两种方法非常相似。

我应该使用什么,技术上有什么区别?谢谢!

JavaScript 是一种无类语言。类不存在,但对象可以使用原型相互继承属性。这意味着您不仅限于以类似类的方式实现继承。就个人而言,我喜欢使用受 BackboneJS 启发的方法(代码需要 UnderscoreJS):

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

这允许你做一些很酷的类类的东西,比如这样:

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 继承的更多信息,我强烈建议阅读 Douglas Crockford 的 JavaScript: The Good Parts。

关于你的例子:

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

在 3 中,您只是返回一个对象文字。new 关键字仅对函数中的 this 关键字有影响,您没有使用该关键字,因此使用 new 不起作用。有关详细信息,请参阅此问题

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

1 和 2 之间的区别与类无关,之前在 SO 上已经问过(几次)。我认为最完整的答案是这个:https://stackoverflow.com/a/338053/1669279简而言之,前 x 指向一个匿名函数,某些调试工具可能会有问题。第一个可从定义它的行中获得,而第二个在整个范围内可用。有关详细信息,请阅读链接的答案。

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

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

作为旁注,在实例化类时应始终使用 new。当您尝试变得聪明并保存字符时,会发生什么:

function X () {
  return this;  
}
console.log(X()); // outputs the window object

调用不带参数的构造函数后的括号是可选的,但避免使用它们是不受欢迎的,因为它会导致代码稍微混乱一些。

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

模式 2 的一个问题可能是这个:

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);
};
这就是

我的做法:

    ;(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);

然后这样称呼它:

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

加载代码后,一旦所有页面加载数据完成,新的 App() 将运行

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

 var App = new App('testmethod);

然后你可以访问类似的东西

    App.testmethod()...
var Person = function() {
    this.age = 23;
}

Person 是包含(被引用)匿名函数的变量

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

但在这里你声明了一个名为"人"的函数

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

因此,您声明了一个返回新静态对象的函数。

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