在JS中使用OOP的几种格式

时间:2015-02-07 03:29:19

标签: javascript oop prototype

前段时间,我一直想要了解多年来在其他几个语言中使用oop编码的js oop。我发现它很混乱。几个月之后,一本JS书和许多文章以及SO问题都被阅读了,我在一个具体的例子中将其全部说明了,这些例子说明了正确运作的主要oop概念。这是:

function Operators() {
    //mandatory
    var self = this

    //private
    var IPT_X = '#x'
    var IPT_Y = '#y'

    //public
    this.x = 0
    this.y = 0    

    this.showOperators = function() {
    //use of a private property (IPT_X) and a public property (this.x)
    $(IPT_X).val(this.x)
    $(IPT_Y).val(this.y)
    }

    this.clean = function() {
    this.x = 0
    this.y = 0
    // call to a local public method 
    this.showOperators()
    }

    this.updateOperators = function(_x, _y) {
    // use of a public property when call from
    // derived class method is necessary
    self.x = _x
    self.y = _y
    }
}

function Randomizer() {
    // mandatory for derived classes
    Operators.call(this)
    // mandatory for overloaded methods with call to the inherited method
    var parentUpdateOperators = this.updateOperators
    var self = this

    // private
    function getRandomNumber() {
    return Math.round(Math.random() * 1000)
    }

    // public
    this.updateOperators = function(_x, _y) {
        // call to inherited method of superior class
        parentUpdateOperators(_x, _y)
        // call to method of superior class
        self.showOperators()
    } 

    this.populateRandomNumbers = function() {
    // call to public local method (this.updateOperators())
    // and to a local private method (getRandomNumber())
    this.updateOperators(getRandomNumber(), getRandomNumber())
    }

    // init
    this.populateRandomNumbers()
}
// Mandatory for derived classes. Allows access to superior classes with
// more than 2 levels of inheritance ("grandfather" classes)
Randomizer.prototype = Object.create(Operators.prototype)

function Operations() {
    Randomizer.call(this)
    var self = this

    //private
    var IPT_RES = '#res'
    var BTN_SUM =  '#sum'
    var BTN_SUBTRACT =  '#subt'
    var BTN_MULTIPLY =  '#mult'
    var BTN_DIVISION =  '#div'
    var BTN_CLEAN =  '#clean'
    var BTN_RAND =  '#rand'

    function calcSum() {
    return self.x + self.y
    } 
    function calcSubtraction() {
    return self.x - self.y
    } 
    function calcMultiplication() {
    return self.x * self.y
    } 
    function calcDivision() {
    return self.x / self.y
    } 

    function showRes(val) {
    $(IPT_RES).val(val)
    }

    //public
    this.sum = function() {
    // call to 2 local private methods
    showRes(calcSum())
    }
    this.subtract = function() {
    showRes(calcSubtraction())
    }
    this.multiply = function() {
    showRes(calcMultiplication())
    }
    this.division = function() {
    showRes(calcDivision())
    }

    // init
    $(BTN_SUM).on('click', function() { self.sum() })
    $(BTN_SUBTRACT).on('click', function() { self.subtract() })
    $(BTN_MULTIPLY).on('click', function() { self.multiply() })
    $(BTN_DIVISION).on('click', function() { self.division() })    
    $(BTN_CLEAN).on('click', function() { self.clean() })
    $(BTN_RAND).on('click', function() { self.populateRandomNumbers() })
}
Operations.prototype = Object.create(Randomizer.prototype)

var obj = new Operations()

并且这是使其工作的必要HTML:

X: <input id='x'>
<br>
Y: <input id='y'>
<br>
Res: <input id='res'>
<br>
<input id='sum' type='button' value='+'>
<input id='subt' type='button' value='-'>
<input id='mult' type='button' value='*'>
<input id='div' type='button' value='/'>
<input id='clean' type='button' value='C'>
<input id='rand' type='button' value='Rand'>

这是一个JSFiddle,我的示例正常工作:

http://jsfiddle.net/vqqrf2cb/24/

然后我开始在日常工作中使用这种格式,一切都很好。但现在,在成功使用这种格式几个月后,我继续阅读有关此主题的内容,并发现许多人使用不同的格式。所以我试图将上面的代码改编为使用对象的其他可能格式。我知道的是:

格式1:

var something = (function() {
     //private
     foo = 111
     bar = 222
     function baz() {
    //whatever
     }
     return {
    // public
    x : 333,
    y : 444,
    z : function() {
        // whatever
    }
     }
})()

格式2:

var something = (function() {
     var obj {
         foo : 111,
         bar : 222,
         function baz() {
        //whatever
         },
     }
     return obj
})()

格式3:

var something = {
     foo : 111,
     bar : 222,
     baz : function() {
    //whatever
     }
}

格式4:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = new Person();

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

所有这些格式的许多小变化。我甚至倾向于认为在JS中进行OOP的方式倾向于无限。 :D无论如何,我想尝试一些方法来找到我在日常工作中找到的更好的方法。但我无法将我的代码转换为任何其他格式,以使所有oop工作。 'all oop'是指封装(私有和公共方法和变量),继承,使用优越的类调用重载,最后是类初始化(如构造函数或其他东西)。

我的问题是:有人可以将我的工作代码翻译成其他一些js对象格式吗?我特别感兴趣转换为格式1和格式3.欢迎列表中未包含的其他格式。一个限制:我不想使用mixins。我想使用原型进行继承。

我也读过关于模块化模式的文章。这个例子将如何使用它?

我也欢迎对我的例子进行更正/评论。

修改

在@Robert和@NoBugs的回答和评论后,我使用Module Pattern做了另一个例子:

http://jsfiddle.net/ehe122e0/10/

1 个答案:

答案 0 :(得分:1)

JavaScript有很多选择,所以它让我困惑了很长一段时间,但最终我最终把它当作新的东西而不顾我所拥有的任何OOP知识。

例如,按照上面描述的格式1和2。这不等于其他语言中的类,但它类似于它在程序中封装了一些“东西”。您应始终将代码包装在至少一个函数中,以确保您的变量永远不会在全局范围内,以避免与其他程序员冲突的名称。查看“IIFE”了解更多详情。

我通常会创建我的对象,只需使用对象文字表示法在我的应用程序中移动数据。

var student = {
    firstName: "Bob",
    age: 20
};

如果我的对象需要像Format 4这样的函数,那么坚持原型继承,因为它提供了更大的灵活性。

无论您决定采用何种格式,IIFE都很重要。忘记“Class”这个词并拥抱模块化模式,它非常相似但不同。这就像尝试像SVN一样使用Git。

以下是printModule和使用它的模块的示例。注意ModuleB可以简单地通过将另一个对象传递给moduleB来轻松地将当前的printModule替换为另一个printModule。我使用导出变量的方式因人而异。

http://jsfiddle.net/0zuo1w4d/1/