Javascript OOP / Classes - 多个实例共享相同的数据 [英] Javascript OOP / Classes - multiple instances share same data

查看:168
本文介绍了Javascript OOP / Classes - 多个实例共享相同的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一些oop javascript代码。我有几个类的实例,并已将不同的数据放入每个。不幸的是,你将看到下面的例子,它们似乎共享相同的数据。

I am writing some oop javascript code. I have a couple of instances of a class and have put different data into each. Unfortunately, as you will see with the example below, they appear to share the same data.

是否可以获得我的类的两个单独的实例?如何完成。

Is it possible to get two separate instances of my class? How would it be done.

Index.html

Index.html

 <html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript">
debugger;

// Do this because a page resart seems to keep old data
function SetGlobals()
{
    var ui;
    var el;

    // Arr00
    ui = document.getElementById("Arr00");
    el = arr0.arrayGet(0);
    ui.innerHTML = el.m_String;

    // Arr01
    ui = document.getElementById("Arr01");
    el = arr0.arrayGet(1);
    ui.innerHTML = el.m_String;

    // Arr10
    ui = document.getElementById("Arr10");
    el = arr1.arrayGet(0);
    ui.innerHTML = el.m_String;

    // Arr11
    ui = document.getElementById("Arr11");
    el = arr1.arrayGet(1);
    ui.innerHTML = el.m_String;
}

function MyOnLoad()
{
    SetGlobals();
}
</script>
</head>
<body onload="MyOnLoad()" style="width:100%; height: 100%; padding: 0 0 0 0; margin: 0 0 0 0; overflow: hidden; background:#000000">

<div id="divScreen" style="display: block; width:100%; height="100%">
    <div id="divMenu" style='float: left; background:#00FF00; border-color: #000000; border-width: 1px;'>
        <table>
            <tr>
                <td>
                    Array 0/String 0: <label id="Arr00"></label>
                </td>
            </tr>
            <tr>
                <td>
                    Array 0/String 1: <label id="Arr01"></label>
                </td>
            </tr>
            <tr>
                <td>
                    Array 1/String 0: <label id="Arr10"></label>
                </td>
            </tr>
            <tr>
                <td>
                    Array 1/String 1: <label id="Arr11"></label>
                </td>
            </tr>
        </table>
    </div>
    <div id="divMain" style='height: 100%; background:#0000FF; margin-left: 250px; border-color: #000000; border-width: 1px;'>
    </div>
</div>
</body>
</html>

Test.js

var BaseARR = function()
{
    _arr = []; // new Array();

    // Public functions that can access private members
    this.Add = function(arg)
    {
        var i, addAt;

        if(arg==null || (addAt = FindEnterPos(arg))<0)
            return false;

        // since adding and not deleting anything, nothing of value will be returned
        _arr.splice(addAt, 0, arg);

        return true;
    };
    // This finds the entry position for in
    FindEnterPos = function(arg)
    {
        return (_arr.length + 1);
    };
    this.arrayGet = function(i)
    {
        return ((_arr != null && i >= 0 && i < _arr.length) ? _arr[i] : null);
    };
};

var stringId = function(id, str)
{
    // public has a this. , privates have just var
    this.m_Id = id; // int
    this.m_String = str; // string
};

// This so allow statics
var stringIdARR = function()
{
    BaseARR.call(this);
};


推荐答案

代码中有各种问题。让我尝试解释它们。

There are various problems in your code. Let me try to explain them.

首先,强烈建议不要在JavaScript中将开头的大括号放在一行上。你为什么要问?运行这两个代码片段:

First it is highly recommended to not put opening block braces on a single line in JavaScript. Why you may ask? Well run those two code snippets:

// using "braces on same line" style
(function () {
  return {
    key: 'value'
  };
})();

// using "braces on line by themself"-style
(function ()
{
  return 
  {
    key: 'value'
  }
})();

两个片段将返回不同的结果,尽管唯一的区别是大括号的定位。其原因是分号插入。在JavaScript分号中是可选的。因此,如果解析器找到换行符并且换行符的结构有意义,那么它将插入一个分号。在第二个例子中,这是return语句之后发生的。如果你把大括号放在与前面的语句相同的行上,你可以规避这样的错误。

Both snippets will return different results, allthough the only difference is positioning of braces. The reason for this is semicolon insertion. In JavaScript semicolons are optional. So if the parser finds a newline character and the construct infront of the newline makes sense, it will insert a semicolon. In the second example this is what happens after the return statement. If you place your braces on the same line as the previous statement, you can circumvent such bugs.

下一件你错了的是JavaScript有类。 JavaScript是一种面向对象的语言,但与大多数其他面向对象的语言不同,它没有类。在JavaScript对象中直接从其他对象(他们所谓的原型)继承。你目前指的是一个类,实际上是一个构造函数,当使用 new 关键字调用时,将创建一个新对象,它将继承任何对象在构造函数原型字段中。

The next thing you got wrong is that JavaScript has classes. JavaScript is an object oriented language, but unlike most other object oriented languages it does not have classes. In JavaScript objects inherit directly from other objects (their so called prototypes). What you currently arre referring to as a class is in reality a constructor function, which when invoked using the new keyword will create a new object, that will inherit from whatever object is stored in the constructors prototype field.

var anObject = {
  key: 'value'
};
function MakeAnObject() {
}

MakeAnObject.prototype = anObject;

var o = new MakeAnObject();

console.log(o.key); // will output 'value'

如果您设置了

If you set a property, the proerty will alwas be set on the object itself, it will never access the prototype chain, when setting a property.

如果你读取属性,那么它将永远不会访问原型链。从一个没有该属性的对象中,JavaScript将搜索该属性的对象原型链(即所有从对象继承的对象),并在找到后返回它。

If you read a property from an object, that does not have that property, JavaScript will search the objects prototype chain (that is all the objects that inherit from each other) for that property and returns it if found.

如果一个oject有一个属性本身,它的原型链不会被搜索,所以你可以覆盖一个对象继承属性,通过设置对象self porperty。

If an oject has a property itself, it's prototype chain will not be searched, so you can "override" an objects inherited properties by setting the porperty on the objects self.

看下面的例子:

function MakeThing() {
}

MakeThing.prototype = {
  key: 'value'
};

var o1 = new MakeThing(), o2 = new MakeThing();

console.log(o1); // will output 'value'
console.log(o2); // will output 'value'

o2.key = 'other';

console.log(o1); // will output 'value'
console.log(o2); // will output 'other'

MakeThing.prototype.key = 'changed';

console.log(o1); // will output 'changed'
console.log(o2); // will output 'other'

delete o2.key;

console.log(o1); // will output 'changed'
console.log(o2); // will output 'changed'

有了这一切,我必须告诉你:没有像JavaScript中的对象上的公共和私有成员这样的东西。会员将始终公开。有一些模式尝试使用闭包隐藏对象中的某些信息,但它们的功能与传统编程语言中的私有成员非常不同。更糟的是:这些模式是笨重的,产生可怕和非常糟糕的代码。我建议不要使用它们,如果你不是绝对要求。

With all that in mind I will have to tell you: there is no such thing as public and private members on an object in JavaScript. Members will always be public. There are some patterns which try to hide away certain information in an object using closures, but they function very different than private members in a traditional programming language. And worse: those patterns are clunky, produce terrible and very bad performing code. I suggest do not use them if you do not absoltuely require to.

那么,这是什么意思?首先,如果你想在多个对象之间共享属性和方法,他们将必须从同一个原型继承,原型必须包含那些属性和方法。其次,如果你在这个上设置的东西,它将设置在当前实例上,而不是原型。第三,只有按惯例才有普通成员和公共成员。如果你绝对需要某些子系统严格隐藏某些信息,那么就有一些模式(Crockford sealer unsealer应该产生可用的结果)。

So, what does all this mean? Well firstly, if you want to share attributes and methods between multiple objects, they will have to inherit from the same prototype and that prototype must contain those attributes and methods. Secondly if you set something on this it will be set on the current instance, not on the prototype. Thirdly have priavte and public members only by convention. If you absolutely require certain information to be strictly hidden from a certain subsystem, there are patterns for this (Crockford sealer unsealer should yield useable results).

快速尝试修复对象:

function BaseAAR {
    this._arr = []; // note >this<. You created a global array in your code.
};

BaseAAR.prototype.add = function(arg) {
    var i, addAt;

    // always use identity (triple) operators when comparing to null!
    if (arg === null || (addAt = this.findEnterPos(arg))<0)
        return false;

// since adding and not deleting anything, nothing of value will be returned
    this._arr.splice(addAt, 0, arg);
    return true;
};
    // This finds the entry position for in
BaseAAR.prototype.findEnterPos = function() {
return (this._arr.length + 1);
};
BaseAAR.prototype.arrayGet = function(i) {
    return ((this._arr !== null && i >= 0 && i < this._arr.length) ? this._arr[i] : null);
};


function StringIdAAR(id, str) {
    BaseAAR.call(this); // invoke the constructor of the base object
    this.m_Id = id; // int
    this.m_String = str; // string
}

StringIdAAR.prototype = BaseAAR.prototype; // innherit from StringIdAAR prototype

我不完全确定这个代码是否真的能满足你的需要做,但你应该得到的点如何面向对象模式在JavaScript应该看起来像。
如果你想更多地了解如何编写好的JavaScript,你绝对应该得到Douglas Crockford的书JavaScript:The Good Parts。

I am not completely sure if this code actually still does what you want it to do, but you should get the point how object oriented patterns in JavaScript should look like. If you want to read more on how to write good JavaScript you should absolutely get the book "JavaScript: The Good Parts" by Douglas Crockford.

UPDATE:我还撰写了一篇关于的文章JavaScript对象定向和基于原型的继承。这可能是任何人经过这里感兴趣。

UPDATE: I also wrote an article on JavaScript object orientation and prototype based inheritance. This might be of interest for anybody passing by here.

这篇关于Javascript OOP / Classes - 多个实例共享相同的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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