我需要在Javascript中递归地定义数据结构。以下是循环链表的简单示例:
// List a very simplified example of what the actual (non list) code does.
function List(f, r) {
return function(){ return [f, r]; };
}
var first = function (l){ return l()[0]; }
var rest = function (l){ return l()[1]; }
var head = List('a', List('b', List('c', head)));
执行此操作时,列表'c'中的head被解析为undefined,而不是List'a',因为我需要。 List是一个返回函数的示例函数(它不是我可以附加到的Javascript列表)。
我试图包装head的定义是一个自动执行的命名函数,但是当头被解析时,它会破坏堆栈。
我忽略了什么是Javascript风格的解决方案?
尝试
愚弄,我想出了一些可行的代码:var f = function(){
var value;
return function(v){
if (value === undefined)
value = v
return value.apply(undefined, arguments);
};
};
var tempHead = f();
var head = List('a', List('b', List('c', tempHead)));
tempHead(head);
first(head); // a
first(rest(head)) // b
first(rest(rest(head))) // c
first(rest(rest(rest(head)))) // a
first(rest(rest(rest(rest(head))))) // b
...
但这真的很难看。有更好的解决方案吗?
解决方案
user1689607提出了一个很好的解决方案,我已将其封装起来隐藏了一些实现:
var def = function(name, impl) {
var value;
return value = impl.apply(Object.defineProperty({}, name, {
'value': function() { return value.apply(this, arguments); }
}));
};
function List(f, r) {
return function(){ return [f, r]; };
}
function first(l){ return l()[0]; }
function rest(l){ return l()[1]; }
var circle = def('head', function() {
return List('a', List('b', List('c', this.head)));
});
first(circle); // 'a'
first(rest(circle)); // 'b'
first(rest(rest(circle))); // 'c'
first(rest(rest(rest(circle)))); // 'a'
first(rest(rest(rest(rest(circle))))); // 'b'
还有一次更新,我最后明确地传递了自引用而不是更改范围:
var def = function(impl) {
var value;
return (value = impl(function() { return value.apply(this, arguments); }));
};
var circle = def(function(self) {
return List('a', List('b', List('c', self)));
});
此代码用于parse.js。
答案 0 :(得分:1)
这是你想要的吗?
var headCaller = function() { return head.apply(this, arguments); };
var head = List('a', List('b', List('c', headCaller)));
它给出了你似乎想要的结果......
DEMO: http://jsfiddle.net/ruNY3/
var results = [
first(head), // a
first(rest(head)), // b
first(rest(rest(head))), // c
first(rest(rest(rest(head)))), // a
first(rest(rest(rest(rest(head))))) // b
];
[
"a",
"b",
"c",
"a",
"b"
]
答案 1 :(得分:0)
当您在参数中提供head
时,它尚未分配。
您需要使用两个步骤。
此外,不需要使用嵌套函数。
function List(f, r) {
return { value: f, next: r};
}
var head = List('a', List('b', List('c', null)));
head.next.next.next.next = head;
在Javascript中,没有指针,但所有Array
或Object
都是通过引用分配的。
修改强>
使解决方案更简单的方法:
function List(f) {
var list = { value: f, next: null };
list.next = list;
return list;
}
function insert(list, elm) {
list.next = { next: list.next, value: elm };
}
function forward(list, nb) {
for (var current = list; nb > 0; nb--)
current = current.next;
return current;
}
var head = List('a');
insert(head, 'b');
insert(head.next, 'c');
console.log(head.value); //a
console.log(head.next.value); //b
console.log(head.value); //c
console.log(forward(head, 3));//a
答案 2 :(得分:0)
我不确定这是否是您想要的,请检查:
function List(f, r) {
var fr = [f, r];
var func = function() {
return fr;
};
func.fr = fr; // because that is a reference we can trick it
return func;
}
var head = List('a', List('b', List('c', null)));
head.fr[1].fr[1].fr[1] = head; // make a loop
添加:更容易实现的功能
// Or this method for lazy people
function createCircularList(f) {
var head = List(f[f.length - 1], null);
var firstfr = head.fr;
for (var i = f.length - 2; i >= 0; i--) {
head = List(f[i], head);
}
firstfr[1] = head;
return head;
}
var head = createCircularList(['a', 'b', 'c']);
演示:http://jsfiddle.net/alvinhochun/5nmpR/
在JavaScript中,事情很有趣。一切都是参考,但参考本身就是一个价值。
var a = [0, 0]; // `a` is set to the reference of `[0, 0]`
var b = a; // `b` refers to the same thing as `a`
console.log(b[0]); // shows 0
a[0] = 1; // it modifies the object that it references to
console.log(b[0]); // shows 1
a = [2, 0]; // a new reference is assigned to `a`
console.log(b[0]); // still shows 1