如何使在JavaScript良好的封装 [英] How to make good encapsulation in javascript

查看:97
本文介绍了如何使在JavaScript良好的封装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从Java来到AngularJS(我是新来的所有的JavaScript与技术),我试图翻译我的想法。
我写了一个对象的茉莉中的一些测试。一些测试工作,但一个人守在什么在我看来是一个范围问题失败。
这里的code:

Coming from Java to AngularJS (I'm new to all javascript relating technologies), I'm trying to "translate" my thoughts. I wrote an object an some tests in Jasmin. Some tests work but one keeps on failing with what seemed to me to be a scope problem. Here's the code:

function Invoice() {

var invoicelines = new LinesHandler();

function LinesHandler() {

    var lines = [];

    function Line() {
        var quantity = 0;
        var description = '';
        var rate = 0;
        var total=0;

        return {
            getQuantity : function() {
                return this.quantity;
            },

            setQuantity : function(quantity) {
                this.quantity = quantity;
                this.refreshTotal();
            },

            getDescription : function() {
                return this.description;
            },

            setDescription : function(description) {
                this.description = description;
            },

            getRate : function() {
                return this.rate;
            },

            setRate : function(rate) {
                this.rate = rate;
                this.refreshTotal();
            },

            getTotal : function() {
                return this.total;
            },

            refreshTotal : function() {
                this.total = this.quantity * this.rate;
            }
        }
    }

    return {
        getLines : function () {
            return lines;
        },

        addLine : function(line) {
            lines.push(line);
        },

        removeLine : function() {},

        editLine : function() {},

        createNewLine : function() {
            return new Line();
        },

        getCount : function() {
            return lines.length;
        },

        getLine : function(i) {
            return lines[i];
        }
    }
}
return {
    createNewLine : function() {return invoicelines.createNewLine();},
    getLinesCount : function() {return invoicelines.getCount();},
    addLine : function(line) {invoicelines.addLine(line);},
    getLines : function() {return invoiceLines;},
    getLinesTotal : function() {
        var total = 0;
        for (line in invoiceLines) {
            total += line.getTotal;
        };
        return total;
    },
    getTaxesTotal: function() {}
};

}

而这里的失败

it('Calculates invoice\'s total while adding lines', function() {
        var invoice = scope.invoice;

        for(var i = 1, j=10; i < 4; i++, j += 10){
            var line = invoice.createNewLine();
            line.setQuantity(j);
            line.setRate(j);
            invoice.addLine(line);
        }

        expect(invoice.getLinesTotal()).toBe(1400);
    });

我试图存取权限的invoiceLines直接像其他的功能,我试图与this.invoiceLines,我试过功能getLines(),但问题是一样的我保持萤火得到这样的:

I tried to acces the invoiceLines directly like in other function, I tried with this.invoiceLines, I tried the function getLines(), but the problem is the same I keep getting in firebug something like:

ReferenceError: invoiceLines is not defined

我dont't真正理解这个问题。为什么其他的功能都能够看到私有成员,但不是getLinesTotal功能?或者for循环?

I dont't really understand the problem. Why do other functions are able to see the private member but not the getLinesTotal function? or the for loop?

先谢谢了。

PS:不要犹豫,评论家code,我敢肯定,它不是在Javascript code

PS: don't hesitate to critic the code, I'm sure that it's not the best way to code in Javascript

推荐答案

关于你的标题(如何在JavaScript中很好的封装),这里是您构建面向对象的JavaScript时使用一个更好的一般模式:

Regarding your title (how to make good encapsulation in JavaScript), here's a better general pattern to use when structuring your object oriented JavaScript:

// Wrap a "class" module in an immediately invoked function expression.
var Parent = (function() {

  // Use a function declaration to create the class's constructor function.
  function Parent(param) {

    // Initialize instance properties from constructor args.
    this.param = param;

    // Initialize any other instance properties we need.
    this.initVar = "foo";
  }

  // Add instance methods to the class's prototype. These will not exist directly on the instance.
  // Instead, JS will look at the instances's prototype to find the value.
  // If you try to access a method (or property) that is not defined on this class prototype,
  // JS will keep looking up the prototype chain. The order here would go:
  //   instance -> instance.[[prototype]] (AKA Parent.prototype) -> Object.prototype -> null
  Parent.prototype.someMethod = function() {
    console.log("Cheese it!");
  };

  // Here we just make a simple method that logs an instance property to the console.
  Parent.prototype.someParentMethod = function() {
    console.log(this.param);
  };

  // Return our now-defined class
  return Parent;

// Immediately invoke the wrapping function expression, returning the Parent class.
}());

// Now lets make a class that inherits from Parent.
var Child = (function() {

  // Make the child constructor
  function Child() {
    // If we want we can call the Parent constructor, passing our Child instance as `this`
    Parent.call(this, "someParam");

    // Do any other child instance initialization
  }

  // Set the Child prototype to a new instance of Parent. For child, the prototype chain will look like:
  //   instance -> instance.[[prototype]] (AKA Child.prototype) -> instance.[[prototype]].[[prototype]] (AKA Parent.prototype) -> Object.prototype -> null
  Child.prototype = new Parent();

  // Point the constructor property to the Child constructor (currently points to Parent)
  Child.prototype.constructor = Child;

  // Override a parent method
  Child.prototype.someMethod = function() {
    console.log("Kill all humans!");
  };

  // Add a method to the Child prototype
  Child.prototype.someChildMethod = function() {
    console.log("Here be dragons");
  };

  return Child;
}());

var myParent = new Parent("foobar");
var myChild  = new Child();
myParent.someMethod();        // => "Cheese it!"
myChild.someMethod();         // => "Kill all humans!"
myParent.someParentMethod(); // => "foobar"
myChild.someParentMethod();  // => "someParam"
myChild.someChildMethod();    // => "Here be dragons"
myParent.someChildMethod();   // => TypeError: Object #<Parent> has no method 'someChildMethod'

我知道这可能不会直接回答你的问题。但是,它与传承创造良好封装类的演示。该原型系统可能需要一点神交 - 我试图使意见尽可能明确。这个想法是,通过附着的方法的原型,它们只被定义一次并且因此占用更少的内存。如果该方法不能在该实例本身存在,它就会查找它的原型链来看看它的任何地方定义,直到原型链,最终获取到。此外,通过操纵类的原型,我们可以通过组成实现多重继承。

I know this may not directly answer your question. However, it's a demonstration of creating well encapsulated "classes" with inheritance. The prototype system may take a bit to grok - I've tried to make the comments as clear as possible. The idea is that by attaching methods to the prototype, they are only defined once and therefore take up much less memory. If the method does not exist on the instance itself, it will look up its prototype chain to see if it's defined anywhere, until the prototype chain eventually gets to null. Also, by manipulating class prototypes, we can achieve multiple inheritance through composition.

希望这有助于一点。让我知道如果有不清楚的地方。

Hopefully that helps a bit. Let me know if anything is unclear.

这篇关于如何使在JavaScript良好的封装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆