【问题标题】:Several formats of using OOP in JSJS中使用OOP的几种格式
【发布时间】:2015-02-07 03:29:18
【问题描述】:

前段时间,我想从其他几个语言中多年的 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/

然后我开始在日常工作中使用这种格式,一切都很好。但现在,在成功使用这种格式几个月后,我继续阅读这个主题,发现很多人使用不同的格式。所以我正在尝试将上面的代码调整为使用对象的其他可能格式。我认识的有:

格式一:

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 的答案和cmets 之后,我使用Module Pattern 做了一个替代示例:

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

【问题讨论】:

  • 您展示的不同示例本质上不提供相同的功能。
  • 还有其他提供吗?

标签: javascript oop prototype


【解决方案1】:

JavaScript 有很多选择,所以它让我困惑了很长一段时间,但最终我最终还是接受了它作为一种新的东西,而忽略了我所拥有的任何 OOP 知识。

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

我通常使用对象文字表示法创建我的对象,以便在我的应用程序之间移动数据。

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

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

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

这里是一个 printModule 和一个使用它的模块的例子。注意 ModuleB 可以很容易地用另一个 printModule 替换当前的 printModule,只需将不同的对象传递给 moduleB。我使用导出变量的方式因人而异。

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

【讨论】:

  • 我已经阅读了 require.js 和许多其他人使用的模块化模式。但我还没有掌握。可以走的路。我把它包括在问题中。你能给我一些新手的例子吗?
  • 我试着做一个简单的例子,如果您有任何问题,请告诉我
  • 我发现Backbone annotated source 是一个相当好的面向对象风格的例子。例如,有事件“mixin”,Collection、View、Model 都包含在它们的对象中。
  • @Robert 我发现你的例子很有趣,我不太清楚,我已经理解了。我花了一些时间来回答,因为,正如你指示我的那样,我正在对自己进行有关 IIFE 以及模块模式、CommonJS 模块、定义函数和其他一些事情的教育。完成后我可能会有一些问题。但我还需要更多时间。谢谢。
  • 你好 ppl,在研究了你指出我的内容几天后,我使用模块模式对我的示例进行了这个改编:jsfiddle.net/ehe122e0/12
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2017-12-30
  • 2019-04-18
  • 2020-12-31
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多