JavaScript基本面向对象

6

好的,我应该知道这个问题的答案,但由于某些原因我从未真正理解或需要了解JavaScript。

我的问题是:看下面的代码示例,我的理解是否正确,还是我缺少一些信息。


示例1

需要实例化函数(或类)才能使用IsOld方法,并且每个实例都将创建一个单独的IsOld函数副本。

function MyClass1() {
    this.IsOld = function (age) {
        if (age > 40) {
            return true;
        }
        return false;
    };
}

// sample usage
var m1 = new MyClass1();
console.log(m1.IsOld(34));

示例2

需要实例化,但与 MyClass1 不同,脚本引擎不需要为每个类实例创建 IsOld 方法的副本。

var MyClass2 = (function () {
    function MyClass2() { }

    MyClass2.prototype.IsOld = function (age) {
        if (age > 40) {
            return true;
        }
        return false;
    };

    return MyClass2;
})();

// sample usage
var m2 = new MyClass2();
console.log(m2.IsOld(34));

第三个示例

不需要实例化函数/类来访问IsOld方法。一个IsOld方法的单一实例在所有调用中使用。

var MyClass3 = {
    IsOld: function (age) {
        if (age > 40) {
            return true;
        }
        return false;
    },
};

// sample uage
console.log(MyClass3.IsOld(34));

注意:我猜测在SO上有很多类似的问题/答案,但出于某种原因我找不到一个对我来说真正有意义的。

1
你的理解是正确的,尽管在我看来第二个例子用了立即执行函数表达式是不必要的复杂。 - Felix Kling
@FelixKling:实际上这就是CoffeeScript编译类的方式:http://coffeescript.org/#try:class%20Auto - Amberlamps
3个回答

2
您的理解似乎是正确的。
如果您所说的“需要实例化”是指使用“new”关键字,我想在这里补充一些内容。
在JavaScript中,使用new关键字不是创建新实例的唯一方法。(根据评论进行编辑) 任何函数都可以作为构造函数。
当您使用new关键字后跟任何函数(比如“x”)时,它会做以下几件事:
1. 创建新对象(称为“y”),并将函数x的原型设置为新对象(y)的原型。 2. 在新创建的对象y的上下文中调用函数“x”,即在函数“x”内部,this将引用这个新对象“y”。 3. 如果函数没有返回对象,则返回由new运算符创建的新对象“x”作为new表达式的结果。
这是Douglas Crockford撰写的学习JavaScript的好资源 (http://javascript.crockford.com/)
因此,如果您关心内存(应该关注),请使用构造函数,并将所有常见方法添加到函数原型中,就像在示例2中所做的那样。
然后,所有使用此函数作为构造函数创建的对象都将继承所有这些方法。但是,如前所述,我认为示例2可能更简单:
var MyClass2 = function MyClass2() { };

MyClass2.prototype.IsOld = function (age) {
    if (age > 40) {
        return true;
    }
    return false;
};

var obj = new MyClass2();

1
在这里使用的情况下,new关键字是不可选的。 - nnnnnn
是的,我同意,因为这些函数并没有在其中创建对象。我的意思是使用“new”不是创建新对象的必要条件。 - BuddhiP

1
据我所知,你在这三种情况下都是正确的。
1. 需要实例化IsOld,每个实例都会创建一个新函数。 2. 不需要实例化IsOld,因为它在原型中。 3. 不需要实例化IsOld,因为MyClass3已经是一个实例(一个对象而不是一个函数)。

1

我觉得关于类的结构和Javascript的动态性质存在一些误解:对于所有提出的情况,每个“类”的实例都会创建一个新的未命名函数。

如果你想以更传统的方式(如C++或Java)声明“类”,最好:

1)定义函数:

function MyClass_IsOld(age) {
    return (age > 40);
} 

2) 创建“类”并定义其原型:

function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;

3) 使用该类:

var myInstance = new MyClass();
console.log(myInstance.IsOld(37));

如果您想将“method”作为常规函数使用,请全局声明它,例如:
function MyClass_IsOld(age) {
    return (age > 40);
} 
function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;

var myInstance = new MyClass();
console.log(myInstance.IsOld(37));        // use as a method
console.log(MyClass_IsOld(37));           // use as a function

如果您想隐藏实现细节,请创建一个闭包:
var MyClass = (function () {
    function _MyClass_IsOld(age) {
        return (age > 40);
    } 
    function _MyClass() { /* put any instance constructor logic here */ };
    _MyClass.prototype.IsOld = _MyClass_IsOld;  // use as a method

    return _MyClass;
})();

var myInstance = new MyClass();
console.log(myInstance.IsOld(37));        // use as a method
console.log(MyClass_IsOld(37));           // ERROR: undefined function

在第二个例子中,原型并没有被每个实例覆盖。它只在立即调用的函数表达式中创建一次,并返回 MyClass2() 构造函数。请再仔细看一下... - nnnnnn
是的,@nnnnnn,你是对的,我确实忽略了类构造函数,并混淆了实例构造函数。顺便说一下,这就是我在Javascript中实现类的方式。感谢你的提醒。 - Gerardo Lima

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