The problem, as it so often is, is that data isn't what most people think it is. data is not an accessor for data-* properties, it's both more and less than that. It manages jQuery's internal data cache for the element. It initializes that cache from data-* attributes, but it duplicates the data in the cache, processes the data, and never writes back to the attributes.
It's that "processing the data" that's hitting you in this case: data automatically detects that what you're reading is JSON and parses it for you. So you'll get back an object, and don't need to parse it.
So using data:
var locations = $("#locations-json").data("json");
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 
 
As you noted in a comment, that says there are 12 cities. That's because the JSON gives cities (and airports) a string value:
{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}
You probably meant the JSON to be:
{"cities": [1, 2, 3, 4], "airports": [5, 6]}
Example:
var locations = $("#locations-json").data("json");
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{"cities": [1, 2, 3, 4], "airports": [5, 6]}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 
 
But unless you need the various features of data, just use attr and parse yourself:
var locations = JSON.parse($("#locations-json").attr("data-json"));
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{"cities": [1, 2, 3, 4], "airports": [5, 6]}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 
 
Note:
As of this edit, your question had a valid div that looked like this:
<div id="locations-json" data-json="{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}" style="display: none"></div>
But then you edited it again to look like this, which is invalid:
<div id="locations-json" data-json="{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}" style="display: none"></div>
The version with " is correct, be sure to use that.