我正在开发一个使用javascript更改iframe页面的向导。我想为向导的每个页面创建一个对象,并引用下一个&上一页。
编辑:下面发布的代码不起作用。 actionOne.nextAction在执行后等于{}。
var actionOne = {};
var actionTwo = {};
actionOne = {
url: 'actionOneUrl.htm',
prevAction: null,
nextAction: actionTwo,
doDisplay: function(){
$('.label').html('Action One');
}
}
actionTwo = {
url: 'actionTwoUrl.htm',
prevAction: actionOne,
nextAction: null,
doDisplay: function(){
$('.label').html('Action Two');
}
}
问题是我无法弄清楚如何正确设置下一个和以前的引用。可能有一个相对简单的解决方案,但我不确定要搜索什么。我可以在创建所有页面后设置引用,但这样做非常笨重。有没有办法在创建对象时执行此操作?
答案 0 :(得分:2)
对于您尝试做的事情,您需要在JavaScript中使用面向对象的方法。这将允许您为对象的新实例分配引用。例如,这有效:
function Action(url, name){
this.url = url;
this.prevAction = null;
this.nextAction = null;
this.name = name;
}
Action.prototype.doDisplay = function(){
$(".label").html(this.name);
}
var actionOne = new Action('actionOneUrl.html', 'Action One');
var actionTwo = new Action('actionTwoUrl.html', 'Action Two');
actionOne.nextAction = actionTwo;
actionTwo.prevAction = actionOne;
console.log(actionOne.nextAction);
编辑:所以OP要求实现自动在新添加的操作之间设置这些链接。所以这是一个双向链表实现:
function ActionList(){
this.head = null;
this.tail = null;
}
ActionList.prototype.doDisplay = function(index){
var node = this.getNode(index);
console.log(node.name);
}
ActionList.prototype.getNode = function(index){
var current = this.head,
c = 0;
while(c < index && current !== null){
current = current.nextAction;
c++;
}
return current;
}
ActionList.prototype.add = function(url, name){
var node = {
url: url,
name: name,
nextAction: null,
prevAction: null
};
if(this.head === null){
this.head = node;
this.tail = node;
}
else{
this.tail.nextAction = node;
node.prevAction = this.tail;
//move tail to new node
this.tail = node;
}
}
var actionList = new ActionList();
//Each add automatically sets up links between the two
actionList.add('actionOneUrl.html', 'Action One');
actionList.add('actionTwoUrl.html', 'Action Two');
console.log(actionList.getNode(1));
actionList.doDisplay(1);
答案 1 :(得分:1)
这是一个非常简化的示例,但是类似以下结构的内容将无需手动引用您的下一个/上一个操作...让应用程序逻辑根据用户的输入找到要执行的操作。
UnderscoreJS的where
函数http://underscorejs.org/#where在这里很有用
var dataFromServer = [
{id:"1", name: "First Page", nextId:"2"},
{id:"2", name: "Second Page", nextId:"3", prevId: "1"},
.....];
var actions = [];
var Action = function(data) {
this.doNextURL = function() {
//find action with id= data.nextId;
var actionToDo = _.where(actions, {id: data.nextId})[0];
window.location.href = actionToDo.url; //or something... a callback parameter, or returning the action rather than doing the 'ui logic' here would be better real world
}
}
for(var i = 0; i < dataFromServer.length; i+=1){
actions.push(new Action(dataFromServer[i]));
}
答案 2 :(得分:1)
当你这样做时
actionTwo = {
// ...
}
您要为actionTwo
分配新值。它不再引用您在var actionTwo = {};
中指定的对象,因此不会引用您在
actionOne = {
// ...
nextAction: actionTwo,
// ...
}
最简单的方法是初始化两个对象,然后在以后将它们分配给正确的属性:
var actionOne = {
url: 'actionOneUrl.htm',
prevAction: null,
nextAction: null,
doDisplay: function(){
$('.label').html('Action One');
}
};
var actionTwo = {
url: 'actionTwoUrl.htm',
prevAction: null,
nextAction: null,
doDisplay: function(){
$('.label').html('Action Two');
}
};
actionOne.nextAction = actionTwo;
actionTwo.prevAction = actionOne;
如果要对多个操作执行此操作,则应考虑使用构造函数,以及joeltine shows in his answer。
要了解有关对象的更多信息,请查看MDN - Working with Objects。
答案 3 :(得分:1)
尝试这样做:不要为actionOne,actionTwo创建新对象,而是将代码保留原样 - 但是分配给已存在对象的对象属性(前两行创建)。
var actionOne, actionTwo;
actionOne = {
url: 'actionOneUrl.htm',
doDisplay: function(){
$('.label').html('Action One');
}
};
actionTwo = {
url: 'actionTwoUrl.htm',
doDisplay: function(){
$('.label').html('Action Two');
}
};
actionOne.prevAction = null; //could also be set above
actionOne.nextAction = actionTwo;
actionTwo.prevAction = actionOne;
actionTwo.nextAction = null; //could also be set above
你的问题是一个非常好的问题 - 不要让任何人告诉别的:)即使有相当多的JS背景也不明显,对象属性指向对象在执行(文字)对象创建语句时指向的变量,而不是变量本身(在这种情况下,您的示例将起作用)。
请忽略MVC模式的事情,即使它甚至被投票。 MVC(有时)没有任何问题,但这是一个非常多,更基本的Javascript问题,这些模式的东西在一个完全不同(更高)的水平上发挥作用比你有趣的小问题。
一些背景:Javascript执行引擎变量的内部深处有一个对象作为值是指针(C / C ++背景知识有助于理解Javascript,因为JS引擎是用它编写的)。因此,当您将此类变量的值分配给对象属性时,它不会指向该变量,而是接收该变量当时具有值的指针。这意味着如果变量获得一个新对象,指向内存中的另一个位置,则对象属性将继续指向旧对象。如果它指向变量而不是它会找到指向新对象的指针。正如您所看到的,回答您的问题会让我们深入了解Javascript引擎如何在非常低的级别上运行:)
所有其他答案肯定也解决了你的直接问题,但我相信知道这一点背景会更加肥沃,最终。而不是试图给出一个有效的答案,有时候值得调查一下究竟发生了什么...... :)
原始类型直接存储在变量中,对象的变量实际上是指针。 new String(“foo”)是一个对象(String),“foo”是一个基本类型(string)。
在Javascript中调用函数时要记住完全相同的问题!技术上总是从值调用 - 但是当变量是指向对象的指针时,值是指针,当分配给变量时,必须考虑哪个函数作为参数。
答案 4 :(得分:1)
当您使用{}
对象文字来定义对象时,您正在使用Object构造函数创建新的对象实例。
以下内容从Object构造函数创建两个新对象实例:
var actionOne = {}; // object instance 1
var actionTwo = {}; // object instance 2
下一部分从Object构造函数创建另一个新对象实例(第三个对象实例)并添加几个属性。 actionOne.nextAction
指向actionTwo
的对象实例(它没有任何属性)。
actionOne = {
url: 'actionOneUrl.htm',
prevAction: null,
nextAction: actionTwo,
doDisplay: function(){
$('.label').html('Action One');
}
} // object instance 3
现在,当您声明actionTwo = {....}
时,会创建第四个对象实例,并带有一堆新属性。 actionOne.prevAction
仍然指向您创建的第二个对象实例(但不再使用全局变量actionTwo引用)。
要记住的关键是对象文字{}
使用Object构造函数创建新对象实例,并且您创建的属性在声明它们时引用对象实例。
答案 5 :(得分:0)
每个人似乎真的过于复杂了。
function Wizard(o) {
return { url:o.url, doDisplay:function() { $('.label').html(o.html); } };
}
var wizards = [{url: 'actionOneUrl.html', html:'Action One'},
{url: 'actionTwoUrl.html', html:'Action Two'}].map(Wizard);
// wizards now contains an array of all your wizard objects
wizards.reduce(function(p,c) { c.prevAction = p; return p.nextAction = c; });
// prevAction and nextAction now point to the right places
答案 6 :(得分:-1)
不,你不能,但你可以保留空物品并填充它们:
var actionOne = {};
var actionTwo = {};
actionOne.url = 'actionOneUrl.htm';
actionOne.prevAction = null;
actionOne.nextAction = actionTwo;
...
但那很难看。我建议使用这样的函数填写它们之间的链接:
function chain() {
var i, prev, curr;
for(i = 0; i < arguments.length; i++) {
curr = arguments[i];
if(prev) {
prev.nextAction = curr;
curr.prevAction = prev;
}
else {
curr.prevAction = null;
}
prev = curr;
}
if(curr) curr.nextAction = null;
}
var actionOne, actionTwo;
actionOne = {
url: 'actionOneUrl.htm',
doDisplay: function(){
$('.label').html('Action One');
}
}
actionTwo = {
url: 'actionTwoUrl.htm',
doDisplay: function(){
$('.label').html('Action Two');
}
}
chain(actionOne, actionTwo);