【问题标题】:OOP In javascript在 JavaScript 中的 OOP
【发布时间】:2012-03-13 23:45:21
【问题描述】:

我想知道在 Javascript 中使用 OOP 的最佳方式是哪种方式。

有这个原型的东西,你有功能风格的方式。但是两者都有非常糟糕的方法来继承基类。

所以我尝试构建一种方法来实现这一点,而不必使用原型等。

function Car(name) {
    this.Name = name;

    this.FullName = function () {
        return this.Name;
    }
}

function SpecialCar(name, variant) {
    //BaseClass.apply(this, PARAMS AS ARRAY);
    Car.apply( this, [name] );

    //new property
    this.Variant = variant;

    //override function
    this.FullName = function () {
        return this.Name + " " + this.Variant ;
    }
}

var audi = new Car("audi");
$("#result").append(audi.FullName() + "<br>");

var audia3 = new SpecialCar("audi", "a3");
$("#result").append(audia3.FullName()+ "<br>");

你可以在这里查看 jsFiddle:http://jsfiddle.net/vu9ZF/2/

这样可以吗,还是只是不好的做法?

很高兴能得到一些答案,为什么其他方法更好,因为我只是不明白。

编辑:谢谢大家这么快回复我! 我试图为自己在 javascript 中找到某种 OOP 方式,而不是回答如何在 javascript 中进行 oop。 我不喜欢为此使用原型的方式,因为我大部分工作时间都在使用 c#,而且在“c#-like oop”和“prototype oop”之间切换有点混乱。 但是 cmets 中有人告诉我,避免原型不是一个好主意,所以我放弃了。

感谢stackoverflow,您的一切都很棒并为我节省了很多时间=)

【问题讨论】:

  • 如果我是你,我会去看看 Mootools。它有一个内置的类系统,非常容易理解。
  • :/ 我的项目中不能使用除 kendoui 和 jquery 以外的其他框架
  • @ChaosPandion 因为它与其他语言完全不同。
  • @SSchnitzler - 想一想……这个理由在逻辑上有意义吗?
  • @SSchnitzler 那是因为它一种不同的语言。它不是 C(++|#) 或Java,需要学习新的做事方式才能正确使用。

标签: javascript oop inheritance


【解决方案1】:

它是这样完成的:

function Car ( name ) {
    this.name = name;
}

Car.prototype.fullName = function () {
    return this.name;
}

function SpecialCar ( name, variant ) {
    Car.apply( this, arguments );
    this.variant = variant;
}

SpecialCar.prototype = Object.create( Car.prototype );

SpecialCar.prototype.fullName = function () {
    return this.name + ' ' + this.variant;
}; 

(对于 IE8,您需要填充 Object.create

现场演示: http://jsfiddle.net/3Rehr/


因此,方法应该分配给构造函数的原型对象,而不是分配给实例本身。

此外,为了使用超级构造函数对实例进行预处理,只需执行以下操作:

Car.apply( this, arguments );

所以不需要this.base 的东西。

【讨论】:

  • 我知道如何做类以及如何继承它们。只是我想知道为什么这样做,以及我的做法是否不好。但无论如何感谢您的回答。我上面显示的方法也有效。
  • 我相信他想知道为什么其他方式更好?
  • @SSchnitzler 您问题中显示的代码不是最佳的。您将方法直接分配给实例。您想将方法分配给构造函数的原型。此外,this.base 也不是最佳的。您可以直接使用 this 值。
  • @SSchnitzler 啊,我明白了,你明确地试图避免原型对象。好吧,这绝对不是一个好主意。方法应该从原型继承。这样,每个方法只存在一个实例,被所有实例继承。
  • @SSchnitzler 看看我的回答。 Car.prototype.fullName 必须在构造函数主体的外部。另外,您需要手动设置继承(B.prototype = Object.create( A.prototype );。这一切都在我的回答中。
【解决方案2】:

就构造函数模式而言,我实际上更喜欢你的方法,而不是使用apply 或类似的东西。由于return 的必要性,它可能会有点混乱,但对我来说,它不像apply 那样脏。

不过,我更喜欢直接使用原型继承,Object.create

var Car = {
    fullName: function() {
        return this.name;
    }
}

var SpecialCar = Object.create(Car);
SpecialCar.fullName = function() {
    return this.name + ' ' + this.variant;
};

var audi = Object.create(Car);
audi.name = 'audi';

var audiA3 = Object.create(SpecialCar);
audiA3.name = 'audi';
audiA3.variant = 'A3';

某些浏览器本身不支持Object.create,但它是可调整的。

【讨论】:

  • 您的代码不起作用 - Object.create 的第二个参数必须是属性描述符的哈希值。简单的属性散列是无效的。所以:Object.create( Car, { fullName: { value: function () { ... }, enumerable: true });
  • 虽然我希望你的方法是有效的。属性描述符很烂:P
【解决方案3】:

这并不是特别推荐,因为您实际上返回的是 Car 实例而不是 SpecialCar 实例。

audia3 instanceof Car === true;
audia3 instanceof SpecialCar === false;

这很令人困惑,因为您确实执行了new SpecialCarSpecialCar.prototype 的属性也不会在实例上可用,但您似乎正在使用自定义继承复制模式。

【讨论】:

  • 哦,好点。 +1。我已经放弃了可靠的instanceof 的所有伪装,但仍然是一个好点。
  • instanceof靠谱,只是他继承的方式不对。
【解决方案4】:

我通常走的是in this page描述的那条路

它为代码提供了更结构化的链接,即使你喜欢代码中能够调用父级构造函数的特性。

function Car( name ) {
  this.Name = name;
}

Car.prototype.FullName = function FullName() {
  return this.Name;
}


function SpecialCar( name, variant ) {
  this.Name = name;
  this.Variant = variant;
}

SpecialCar.prototype = new Car();
SpecialCar.constructor = SpecialCar;

SpecialCar.prototype.FullName = function FullName() {
  return this.Name + " " + this.Variant; 
}

【讨论】:

  • SpecialCar.prototype = Object.create( Car.prototype ); 和你是怎么做的有什么区别:SpecialCar.prototype = new Car(); SpecialCar.constructor = SpecialCar;,IE8 不需要 shim 吗?
  • @Knownasilya 使用Object.create 是设置继承的正确方法。 new Car() 也有效,但它存在缺陷,因为它用不必要的实例属性污染了对象(在这种情况下为.Name)。是的,您需要为 IE8 填充 Object.create(使用 es5-shim)。
【解决方案5】:

我会这样做。需要一些糖代码才能工作。你可以找到OoJs on github。 OoJs 涵盖了 C++ 中的大部分 OOP 特性,除了多重继承和强制纯虚函数......

;( function class_Car( namespace )
{
    'use strict';

    if( namespace.Car ) return    // protect against double inclusions

        namespace.Car = Car
    var Static        = TidBits.OoJs.setupClass( namespace, "Car" )


    // constructor
    //
    function Car( name )
    {
        this.Name = name               // data member, private by default

        return this.Public( FullName ) // method FullName will be public
    }


    function FullName()
    {
        return this.Name;
    }

})( window )




;( function class_SpecialCar( namespace )
{
    'use strict';

    if( namespace.SpecialCar ) return    // protect against double inclusions

        namespace.SpecialCar = SpecialCar
    var Static               = TidBits.OoJs.setupClass( namespace, "SpecialCar", "Car" )


    // constructor
    //
    function SpecialCar( name, variant )
    {
        this.Super( name )

        this.Variant = variant

        return this.Public( FullName )
    }


    function FullName()
    {
        return this.Car.FullName() + " " + this.Variant
    }

})( window )


var audi = new Car("audi");
$("#result").append(audi.FullName() + "<br>"); // output: audi

var audia3 = new SpecialCar("audi", "a3");
$("#result").append(audia3.FullName()+ "<br>"); // output: audi a3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2016-06-25
    • 2019-01-31
    相关资源
    最近更新 更多