简体   繁体   中英

Why is this javascript object property undefined?

I am using an approach described in detail at Dictionary Lookups in Javascript (see the section"A Client-Side Solution") to create an object that contains a property for each word in the scrabble dictionary.

var dict = {};

//ajax call to read dictionary.txt file
$.get("dictionary.txt", parseResults);


function parseResults(txt) {
var words = txt.split( "\n");

  for (var i=0; i < words.length; i++){
      dict[ words[i] ] = true;
  }

  console.log(dict.AAH);
  console.log(dict);

  if (dict.AAH == true) {
     console.log('dict.AAH is true!');
  }


}

(updated code to use an earlier answer from Phil)

I can't figure out why dict.AAH is returning undefined, but the dict object looks fine in the console. Screenshots from Firebug below.

Console:

安慰

Drilled down into "Object { }"

宾语

How can I check a given word ("AAH", in this case) and have it return true if it is a property in the dict object defined as true?

It's probably a race condition. You're loading the dictionary in a GET and then immediately (while the request is being made) those console.log commands are being called (and the one comes back undefined). Then the data is actually loaded by the time you debug. Everything should be done in a callback or deferred. It's an understandable quirk of debuggers that's caught me up before.

You're trying to output dict before it has been populated by the $.get success handler.

Try this:

// If the browser doesn't have String.trim() available, add it...
if (!String.prototype.trim) {
    String.prototype.trim=function(){return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');};

    String.prototype.ltrim=function(){return this.replace(/^\s+/,'');};

    String.prototype.rtrim=function(){return this.replace(/\s+$/,'');};

    String.prototype.fulltrim=function(){return this.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'').replace(/\s+/g,' ');};
}

/**
 * Parses the response returned by the AJAX call
 *
 * Response parsing logic must be executed only after the
 * response has been received. To do so, we have to encapsulate
 * it in a function and use it as a onSuccess callback when we
 * place our AJAX call.
 **/
function parseResults(txt) {
    // clean the words when we split the txt
    var words = txt.split("\n").map($.trim);

    for (var i=0; i < words.length; i++){
        dict[ words[i] ] = true;
    }

    console.log(dict.AAH);
    console.log(dict);

    if (dict.AAH == true) {
       console.log('dict.AAH is true!');
    }
}

// global object containing retrieved words.
var dict = {};

//ajax call to read dictionary.txt file
$.get("dictionary.txt", parseResults);

As another user commented, jQuery's $.when lets you chain such code.

By the way, if all you want to do is know if a word is in the results you can do:

function parseResults(txt) {
    // clean the words when we split the txt
    var words = txt.split("\n").map($.trim);

    if ($.inArray('AAH', words)) {
        console.log('AAH is in the result set');
    }
}

Get ajax requests are asynchronous. This means that while the whole operation that occurs in the ajax request is going, javascript keeps reading the next lines.

The problem then is you are logging values that the ajax request did not manage to retrieve early enough.

To get around the issue you can include the log calls inside your ajax request callback as below

var dict = {};

//ajax call to read dictionary.txt file
$.get("dictionary.txt", function( txt ){
    var words = txt.split( "\n");

    for (var i=0; i < words.length; i++){
        dict[ words[i] ] = true;
    }

    //Now inside these console.log will run once you DO have the data
    console.log(dict.AAH);
    console.log(dict);
});

//Stuff out here will run whether or not asynchronous request has finished

I WOULD RECOMMEND USING THE WHEN METHOD IN JQUERY FOR THIS TYPE OF SCENARIOS EVEN MORE AS THE BEST SOLUTION

HERE IS HOW WHAT I THINK WOULD BE MOST PROPER FOR COMPLEX PROJECTS

var dict = {};

//ajax call to read dictionary.txt file
function getDictionary(){
    return $.ajax("dictionary.txt");
}

/*I recommend this technique because this will allow you to easily extend your 
code to maybe way for more than one ajax request in the future. You can stack 
as many asynchronous operations as you want inside the when statement*/

$.when(getDictionary()).then(function(txt){//Added txt here...forgot callback param before

   var words = txt.split( "\n");

    for (var i=0; i < words.length; i++){
        dict[ words[i] ] = true;
    }

    //Now inside these console.log will run once you DO have the data
    console.log(dict.AAH);
    console.log(dict);
});

The problem isn't your code. You have invisible characters in your words, which you fail to clean up.

You can verify this by using this as your results parser

function parseResults(txt) {
  // clean the words when we split the txt
  var words = txt.split("\n")
                 .map($.trim)
                 .splice(0,3); // Keep only 3 first ones

  if(btoa(words[2]) !== btoa('AAH')){ // Compare in Base64
    console.log('YOU HAVE HIDDEN CHARS!');
  }

}

And you can fix it by whitelisting your characters.

function parseResults(txt) {
  // clean the words when we split the txt
  var words = txt.split("\n").map(function(el){
    return el.match(/[a-zA-Z0-9]/g).join('');
  });

  for (var i=0; i < words.length; i++){
      dict[ words[i] ] = true;
  }

  console.log(dict.AAH);
  console.log(dict);

  if (dict.AAH == true) {
     console.log('dict.AAH is true!');
  }
}

I would recommend cleaning it up on the server side since running regex on every element in an array as large as seen in your live site might cause performance issues.

I think the problem lays in that you have dict defined as an object but use it as an array.

Replace var dict = {} by var dict = new Array() and your code should work (tried with your live example on Google Chrome).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM