0

TOS 表示栈顶。预期用法示例,

 read: var xx = tos(3).value;
write: tos(4).value = 12345678;

给定一个数组

var mystack = [11, 22, 33, 44, 55];  // 55 is tos(0), 22 is tos(3)

读取mystack很容易,tos(0).value返回 55,tos(1).value返回 44,下面的函数做得很好,

function tos(n){
    arguments.callee.value = mystack[mystack.length - 1 - n];
    return arguments.callee;
}

但我想将数据写入mystackby

tos(2).value = 3333;  // How to make tos() work this way?

mystack应该变成[11, 22, 3333, 44, 55];如何为此重新编写tos()

为什么要问这个问题?

Microsoft Office Excel 自动化允许 objExcel.workbooks(1).worksheets(1).cells(1,1).value 位于 = 的任一侧,例如 objExcel.workbooks(1).worksheets(1).cells( 1,1).值 = 11223344; WScript.echo(objExcel.workbooks(1).worksheets(1).cells(1,1).value); // 打印 11223344

我尝试以这种方式访问​​数组,但发现对我来说很难。

预期的函数 tos() 是一个避免暴露 mystack 本身的封装。

4

3 回答 3

1

如果你真的想这样做,坦率地说我不明白这一点,那么你可以这样做:

function tos (n) {
    var i = mystack.length - n - 1;
    return Object.defineProperty ({}, "value", {
       get : function() { return mystack[i]; },
       set : function(v) { mystack[i] = v; }
    });
}

当然你需要 ECMAScript 5。没有其他方法可以实现tos(2).value=999设置数组元素的语义,因为在 JS 中,.value语法要求左边的对象是一个对象,而数组元素本身就是一个对象不是可以设置值的对象。所以上面本质上构造了一个对象,并在其上定义了一个getter和setter。

要使其独立于mystack,请执行以下操作:

function as_stack (array) {
    return {
        tos : function (n) {
            var i = array.length - n - 1;
            return Object.defineProperty ({}, "value", {
                get : function() { return array[i]; },
                set : function(v) { array[i] = v; }
            };
        }
    };
}

现在你可以做

as_stack (array).tos (2).value=999;

或者

var tos = as_stack (array).tos; 
tos (2).value = 999;

如果那能让你的船浮起来。

根据您对此类事情的宗教信仰,您还可以将其添加到Array.prototype

Array.prototype.tos = function (n) {
    var i = this.length - n - 1, array = this;
    return Object.defineProperty ({}, "value", {
        get : function() { return array[i]; },
        set : function(v) { array[i] = v; }
    };
};

现在你可以做

array.tos (2).value=999;

另一种方法

如果您专注于使用.value语法来获取和设置值,而不使用Object.defineProperty,那么我能想到的唯一其他选择是使用 DOM 作为数组的代理。我们将数组存储为文档片段中的文本节点列表。但是,您必须使用nodeValue,而不是value

首先,从一个真实数组创建一个基于 DOM 的数组:

function dom_array (array) {
    this.frag = document.createDocumentFragment ();
    for (var i=0; i<array.length; i++) {
        this.frag.appendChild (document.createTextNode (array[i]);
    }
}

现在,你可以做

my_dom_array = new dom_array ([1,2,3]);

接下来,我们将添加一个返回特定元素的方法:

dom_array.prototype.tos = function (n) {
    return this.frag.childNodes.item (this.frag.childNodes.length - n -1 );
}.

此函数实际上返回一个 DOM 文本节点,您现在可以使用它来执行以下操作:

my_dom_array.tos (2).nodeValue = "bar";
alert (my_dom_array.tos (2).nodeValue);

您可能需要添加一个成员函数来取回一个真正的数组:

dom_array.prototype.to_array = function () {
    var array=[];
    for (var i=0; i<this.frag.childNodes.length; i++) {
        array.push (this.frag.childNodes[i].nodeValue);
    }
    return array;
};

现在您可能还想在这个准数组上实现所有其他数组方法,例如pushor或其他任何东西。pop

你有它 - 一个tos允许你获取和设置数组中的值的函数,尽管使用nodeValue而不是value. 但是,它使您难以想象为什么要这样做,而不是array[2]=999;像世界上其他所有 JS 程序员一样说。

请注意,这不适用于非 DOM 环境,例如 node.js。

于 2013-07-12T04:16:55.520 回答
0

正如之前的评论者指出的那样,您上面的代码很奇怪。为了使您的代码看起来更好,如果mystack真的按照数据类型Stack的意义Stack使用,请使用以下内容:

mystack.push(11);
mystack.push(22);
mystack.push(33);
mystack.push(44);
mystack.push(55);

当然,你将[11, 22, 33, 44, 55]在堆栈中拥有。要查看堆栈顶部,您可能需要这样的函数:

function peek(stack) {
  return stack[stack.length - 1];
}

或者您可以将其定义Array.prototype为:

Array.prototype.peek = function () {
  return this[this.length - 1];
};

然后您可以使用mystack.peek(). 现在你有了 a 的正确语义stackmystack[2] = 2222虽然您不应该真正直接访问堆栈内的元素,但如果确实需要,您仍然可以选择修改它们。

于 2013-07-12T04:22:07.700 回答
0

假设您控制mystack变量,只需以不同的方式构建它,生活就会变得更加轻松。

利用 JavaScript.Array 的shiftunshift运算符。从空的堆栈开始: mystack = [];

当你添加它时,只需改变值:

mystack.shift(11);
mystack.shift(22);
mystack.shift(33);
mystack.shift(44);
mystack.shift(55);

然后它将是一个索引为 0 的堆栈,并mystack[2]为您提供 33,您可以简单mystack[2] = 3333地设置您的值。

要“弹出”堆栈,请使用unshift. 它将删除 0 元素。

于 2013-07-12T04:10:29.703 回答