13

I have some HTML that contains a JSON string. In the on DOM ready callback, I have something like this:

MyObject = JSON.parse($('#TheJsonString').html());

Later in my code, I write something this:

var SomeVar = MyObject.MyProp1;

And then when I run the code through the Google closure compiler, I get the warning

Property MyProp1 never defined on MyObject.

How should the code be written so that it doesn't generate a warning?

alex
  • 479,566
  • 201
  • 878
  • 984
frenchie
  • 51,731
  • 109
  • 304
  • 510

5 Answers5

15

The cleanest way to remove the warning is by defining the structure of the JSON. This can be done using the @type tag:

/** @type {{MyProp1:string}} */

Where MyProp1 is the name of the property, and string is the type.

Google's Closure compiler will rename the variable. If you don't want that, you have to use quotes + brackets instead of the dot-notation:

MyObject['MyProp1']

Example: paste the following in the Closure Compiler:

// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==

var MyObject;
function x() { // Magic happens at the next line
    /** @type {{MyProp1:string}}*/
    MyObject = JSON.parse(prompt(''));
}
function afterX() {
    var SomeVar = MyObject.MyProp1;
    alert(SomeVar);
}
x();
afterX();

Output:

var a;a=JSON.parse(prompt(""));alert(a.a);
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Ok thanks, now it works! Overall, is it "better" to use dot-notation vs bracket notation or is just a matter of style/preference? Also, I plan to use the google compiler and then reobfuscate the compiled code in jscrambler. I know this won't prevent reverse engineering but I'm only looking to buy time. Will double obfuscation work? – frenchie Mar 05 '12 at 15:49
  • 1
    @frenchie Generally, the bracket/dot notation a matter of preference. However, in the Closure compiler, the bracket notation has to be used, to preserve the names. The dot-notation is used in the compiled output, though. And yes, double obfuscation will indeed make reverse engineering harder. Make sure that you test the performance of the code before/after obfuscation. – Rob W Mar 05 '12 at 16:02
7

To suppress this warning for a specific function, you can use the @suppress annotation:

/**
 * @suppress {missingProperties}
 */
function useJsonObject() { ... }

To turn off this warning globally, use the jscomp_off compiler flag to turn off the missingProperties class of warnings.

bzlm
  • 9,626
  • 6
  • 65
  • 92
4

Try accessing the property in this way:

var SomeVar = MyObject['MyProp1'];
MAXE
  • 4,978
  • 2
  • 45
  • 61
lennel
  • 646
  • 3
  • 10
1

Instead of putting the JSON content in the #TheJsonString object as HTML, you should put it in your page as actual javascript. If the server is generating the content in the page, then there's no reason that the server needs to generate HTML which you then parse. The server can just make a javascript variable inside a script tag and put the actual javascript data structure in it.

JSON.parse() is very useful for parsing ajax responses, but it really isn't needed when the server can just put the finished javascript right in the generated page in the first place.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I'm putting the json strings in a literal so in the browser they're inside a div. Asp.net – frenchie Mar 05 '12 at 03:12
  • @frenchie - I know you are putting them in a div. I'm asking why you're doing that when you could just put them directly into a javascript variable. There's no reason to put them in string form in your page. This would also solve the Google closure issue because they'd be defined in real javascript. – jfriend00 Mar 05 '12 at 03:22
  • 1
    There are actually 12 json strings and the literals are injected from the master page code behind. I don't want my .master file to have an ugly server eval statement. And that wouldn't solve the compiler issue anyway since I don't have the json statements; they're evaluated at runtime. – frenchie Mar 05 '12 at 03:29
  • 1
    @frenchie - I have no idea what's ugly about having a server generate javascript data structures in a page it's serving up. That's done all the time. No eval statement is required. You're pursuing an unorthodox method of putting data in your page. Your life would be a lot easier if you used a better way to put the data in the page, but you seem to be fighting that notion and we really have no idea why. – jfriend00 Mar 05 '12 at 03:31
  • But I'm using google compiler where I copy-paste my javascript and where I want to remove the warnings (FYI, 837 warnings). The json statements are only available at runtime so even if I put the json statements as an eval in the aspx file, I still have the warning come up in google compiler because I don't have them when I'm compiling the code! The more I think of it, the more I think the solution is in prototypial inheritance where I need to create an object and cast the parse of the json or something like that. – frenchie Mar 05 '12 at 09:37
0
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="TheJsonString">
    {"bindings": "hr", "method":"asd"}
</div>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript">
    var MyObject = JSON.parse($('#TheJsonString').html());

    var SomeVar = MyObject.bindings;

    console.log(SomeVar);
</script>
</body>
</html>

I tested it like this, but it works fine without any warnings.

Hengfeng Li
  • 381
  • 1
  • 5
  • 12
  • The problem is that I don't have the json strings when I paste my code in the google compiler: the json is generated at runtime and is different for every user. The more I think of it, the more I think the solution is in prototypial inheritance where I need to create an object and cast the parse of the json, or something like that. – frenchie Mar 05 '12 at 09:42