如何在javascript中创建未初始化的对象?

时间:2013-02-07 18:54:29

标签: javascript object initialization

我正在开发一个使用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');
    }
}

问题是我无法弄清楚如何正确设置下一个和以前的引用。可能有一个相对简单的解决方案,但我不确定要搜索什么。我可以在创建所有页面后设置引用,但这样做非常笨重。有没有办法在创建对象时执行此操作?

7 个答案:

答案 0 :(得分:2)

对于您尝试做的事情,您需要在JavaScript中使用面向对象的方法。这将允许您为对象的新实例分配引用。例如,这有效:

http://jsfiddle.net/Gq7vQ/

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要求实现自动在新添加的操作之间设置这些链接。所以这是一个双向链表实现:

http://jsfiddle.net/wXC9B/1/

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);