Search array for string - returning -1

时间:2015-07-08 15:37:07

标签: javascript arrays

I've been reading lots of StackOverflow answers which tell me that, in Javascript, the best way to search an array for a particular string is use indexOf(). I have been trying to make this work for a while now, and I need some help with it.

I am making a shop in a text-adventure game. These are the values I am using:

The array shopCosts:

shopCosts = [20, 25];

The array shopItems:

shopItems = [["Sword", "Shield"]];

I dynamically create radiobuttons by looping through shopItems:

for(var i = 0; i < array.length; i++)
{
    // Create the list item:
    var item = document.createElement('li');

    // Set its contents:
    item.appendChild(document.createTextNode(array[i] + " - " + shopCosts[i] + " Gold"));

    // Add it to the list:
    list.appendChild(item);

    var label = document.createElement("label");
    var radio = document.createElement("input");
    var text = document.createTextNode(array[i]);
    radio.type = "radio";
    radio.name = "shop";
    radio.value = array[i];
    radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }

    label.appendChild(radio);
    label.appendChild(text);
    document.body.appendChild(label); 
}

This is the part in question:

radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }

My logic was basically to assign values to each dynamically created radiobutton, and if one was pressed, get the value (so, the name of the item you wanted to buy) and then search shopItems for that particular string for the index value. Once I had that, I would look in the same "parallel" list shopCosts to find the price.

I used console.log() to see what variables were in play. When I clicked on the radio button, this function is called:

function addValue(nameOfItem, shopCosts, shopItems)
{
    var positionOfShopItem = shopItems.indexOf(nameOfItem);
    console.log(positionOfShopItem);
    console..log(nameOfItem);
    console.log(shopItems);
}

Surely, the console.log() would return the position of the named item? To prove to myself I'm not going crazy, here's what the Dev Tools say:

-1
Sword
    [Array[2]]
        0: "Sword"
        1: "Shield"

Sword is clearly in the array, in position 0, so why is indexOf() returning -1?

Any help appreciated!

4 个答案:

答案 0 :(得分:5)

As I alluded to in my comment, its because shopItems does not contain an array of strings, it contains a single element, where that one element is an array of strings. I suspect your code would work just fine if you removed the extra square braces

var shopItems = ["Sword", "Shield"];

答案 1 :(得分:2)

我意识到你已经修复了这个错误,但我建议你考虑采用不同的方法解决问题。这两个原则不仅会以更清洁的方式解决问题,而且还会为您提供一种思考未来类似问题的新方法:

  1. 从不使用并行数组。改为使用单个对象数组。
  2. 在附加项目的主循环中,将循环的主体放在函数中。
  3. 如果您遵循这两个想法,您将获得多项好处。代码变得更加简单,易于维护,您根本不需要进行任何数组查找!

    每个商店项目都打包为数组中的单个对象,如下所示:

    var shopItems = [
        { name: 'Sword', cost: 20 },
        { name: 'Shield', cost: 25 }
    ];
    

    因此,如果您对整个商店项目有一个引用,例如在名为shopItem的变量中,则会自动提供其所有属性:shopItem.nameshopItem.cost。这使您还可以轻松地向商店项目添加更多位数据,例如

    var shopItems = [
        { name: 'Sword', cost: 20, dangerous: true },
        { name: 'Shield', cost: 25, dangerous: false }
    ];
    

    现在shopItem.dangerous将为您提供适当的值。所有没有任何数组查找。

    使主循环体成为一个函数增加了另一个好处:在该函数内部,每次调用函数时都会保留其参数和局部变量(这称为闭包)。因此,现在您甚至不必获取列表项值并进行查找 - 您已经在代码中提供了相应的shopItem

    将它们放在一起,代码可能如下所示:

    var shopItems = [
        { name: 'Sword', cost: 20, dangerous: true },
        { name: 'Shield', cost: 25, dangerous: false }
    ];
    
    var list = document.getElementById( 'list' );
    
    for( var i = 0;  i < shopItems.length;  ++i ) {
        appendShopItem( shopItems[i] );
    }
    
    // Alternatively, you could use .forEach() instead of the for loop.
    // This will work in all browsers except very old versions of IE:
    // shopItems.forEach( appendShopItem );
    
    function appendShopItem( shopItem ) {
        // Create the list item:
        var item = document.createElement( 'li' );
    
        // Set its contents:
        item.appendChild( document.createTextNode( 
            shopItem.name + ' - ' + shopItem.cost + ' Gold'
        ) );
    
        // Add it to the list:
        list.appendChild( item );
    
        var label = document.createElement( 'label' );
        var radio = document.createElement( 'input' );
        var text = document.createTextNode( shopItem.name );
        radio.type = 'radio';
        radio.name = 'shop';
        radio.value = shopItem.name;
        radio.onclick = function () {
            addValue( shopItem );
        };
    
        label.appendChild( radio );
        label.appendChild( text );
        document.body.appendChild( label ); 
    }
    
    function addValue( shopItem ) {
        console.log( shopItem );
        alert(
            shopItem.name +
            ' costs ' + shopItem.cost + ' and is ' +
            ( shopItem.dangerous ? 'dangerous' : 'not dangerous' )
        );
    }
    

    New fiddle(对于杰米克来说,这是对小提琴的一小部分)

    如您所见,这使代码更容易理解。如果您有shopItem,则会自动拥有namecost以及您要添加的任何其他媒体资源。最重要的是,您永远不必跟踪将值放在两个,三个甚至更多不同阵列中的相同顺序。

答案 2 :(得分:0)

shopItems is an Array of Arrays. The 0 index of shopItems contains another array which contains:

["Sword", "Shield"]

So when you are trying to find the "Sword" item or "Shield" Item inside of shopItems it is returning -1 because it cannot find either inside of the array.

Change

shopItems = [["Sword", "Shield"]];

To

shopItems = ["Sword", "Shield"];

And that will fix your issue.

答案 3 :(得分:0)

I've fixed it!

Removing the double square brackets resulted in this mess. So, as a workaround, I simply added [0] to var positionOfShopItem = shopItems.indexOf(nameOfItem); to get var positionOfShopItem = shopItems[0].indexOf(nameOfItem);

Thanks for everyone's help.